-
-
Notifications
You must be signed in to change notification settings - Fork 3
/
psym.e
3785 lines (3574 loc) · 186 KB
/
psym.e
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
885
886
887
888
889
890
891
892
893
894
895
896
897
898
899
900
901
902
903
904
905
906
907
908
909
910
911
912
913
914
915
916
917
918
919
920
921
922
923
924
925
926
927
928
929
930
931
932
933
934
935
936
937
938
939
940
941
942
943
944
945
946
947
948
949
950
951
952
953
954
955
956
957
958
959
960
961
962
963
964
965
966
967
968
969
970
971
972
973
974
975
976
977
978
979
980
981
982
983
984
985
986
987
988
989
990
991
992
993
994
995
996
997
998
999
1000
--
-- psym.e
--
-- Symbol table handler
--
without trace
constant dumppsym = 0 -- 1: creates a possibly useful reference file, psym.txt
-- (maybe useful as plist.e kills unused symtab entries)
-- (tip: set to 1, then run "p p t01", then reset to 0)
-- (should have no impact on performance when left as 0,
-- and by "no impact" I mean maybe 0.0001s on running
-- "p -cp" but absolutely zero running p.exe itself.)
integer fnpsym -- file no of psym.txt (iff dumpsym!=0)
sequence priorities,
--
-- This implements automatic global resolution, and answers the basic
-- question: When I look for variable X and more than one exists, then
-- which should I choose, and/or when to error, the english answer being:
-- * Locally defined first, then
-- * Direct and Indirect includes [treat as one], then
-- * The parent(s) along with whatever they include, then
-- * The grand_parent(s), etc.
-- Error out if >1 in whatever level you got up to.
--
-- The golden rule is this: If *something works standalone*, it should
-- work exactly the same way when included as part of a larger system.
-- Simple, really, the only difficult part is to realise this goal in
-- an uber-efficient and elegant way.
--
-- <aside>
-- Implicit forward calls may need to be made explicit, ie
-- you may need to insert a few "forward func/proc x", to
-- prevent resolution to a prior (global) instance of x.
-- Also, overriding a builtin or auto-include, a notion I
-- would strongly discourage, can really foul things up
-- when you suddenly bolt together two chunks of code, but
-- that's your problem not mine.
-- <\aside>
--
-- In case you ask "why would you have multiple global X?" the reality
-- is that with large projects built using components from several
-- authors, it is almost unavoidable - and certainly better to deal
-- with it in a logical and consistent way than simply ignore it, or
-- worse force you to edit one or more third party files despite the
-- fact they each work just fine when used individually.
--
-- A proper explanation most definitely requires a proper example:
--
-- fileno desc parents priorities
-- 1 inc7 {} {2,1,1,1,1,1}
-- 2 eric {1} {2,4,3,3,3,3}
-- 3 bob {2} {2,4,6,5}
-- 4 alice {3} {2,4,6,8}
-- 5 diane {2} {2,4,4,4,10,9}
-- 6 chris {5} {2,4,4,4,10,12}
-- [-4] alice =>{3,2}
-- [-6] chris =>{5,2}
--
-- The above shows the final table, having grown from an initial {2}.
-- (see test\t13inc7.exw and test\inc7\*.* for the actual code)
--
-- This is a non-trivial concept; take the time to understand it fully.
-- It is in fact a nice, elegant, and relatively simple solution to a
-- a fairly difficult problem, but may not seem so on first reading.
-- If you have not yet bothered to read test\t13inc7.exw etc yet, then
-- expect to get lost pretty quickly in the following explanation!
--
-- Hits in files with a higher priority get chosen; there is an
-- implied priorty of 0 for the builtins, otherwise 1 is the
-- lowest priority, overridden by anything higher.
-- Multiple hits at a given priority with nowt better -> error.
-- A namespace now means "use the priority table from file N" (ish*).
--
-- Suppose we are hunting for a global X. Three examples:
--
-- 1) At the end of inc7, if there is one in file 1 [inc7, pri 2],
-- pick that, else if there is one (and only one) in files 2..6,
-- [eric..chris, pri 1], pick that. {2,1,1,1,1,1}.
--
-- 2) At the end of eric, pick one in file 2 [eric, pri 4] if it exists,
-- else pick one (and only one) in files 3..6 [bob/alice/diane/chris,
-- pri 3], else pick one in file 1 [inc7, pri 2]. {2,4,3,3,3,3}.
--
-- 3) At the end of chris, obviously an X in chris has top priority(12),
-- then one in diane(10), then one in eric/bob/alice(4), and lastly
-- one in inc7(2). {2,4,4,4,10,12}
--
-- A namespace required/not specific enough error occurs if we find multiple
-- (=ambiguous) instances at the highest priority level of any encountered.
--
-- An important aspect to notice is the diagonal 2-4-6-8-10-12 which should
-- always be the highest value in any table entry. Although strictly speaking
-- we do not need it to be so, this also means the priority table is perfect
-- for looking up local variables. As an aside, length(priorites[1]) should
-- be equal to length(priorities), as should length(priorities[$]), otherwise
-- the table is not strictly square, as shown above and detailed below.
-- When using a namespace, it will land on that diagonal, and do the right
-- thing for sub-includes. We start with cp = <diag-1> to skip other files:
-- that start value of cp is what I meant by (ish*) above, ie we do use
-- the priority table for file N, but only consider high enough entries,
-- for example bob:X uses the {2,4,6,5} entry with a cp of 5, see next.
-- (cp is the "current priority" variable, see InTable() below.)
--
-- Notice that once bob and alice are fully processed, the priority table is
-- no longer extended. This ensures that, say, our bob:X namespace lookup
-- only bothers to look at the relevant file(s), ie with {2,4,6,5} & cp=5,
-- pickup an X in bob, or if none there, one in alice, but the cp=5 prohibits
-- any from inc7/eric, and the length of 4 prohibits any from chris/diane.
--
-- Notice how in chris and diane, the files bob and alice (now fully processed)
-- have been upgraded/promoted to the same priority as eric. The initial table
-- for diane ({2,4,4,4}) is copied from eric ({2,4,3,3}) using this rule,
-- since eric is the (first) parent of diane. What this means is that if X is
-- defined in eric and bob, an unqualified reference to X in diane triggers an
-- error, as it should, whereas both an appropriate eric:X or bob:X can pick
-- the right one by following the {4,3,3} or {4,6,5} info respectively.
--
-- Lastly, the inclusion of alice and chris (again) into bob has no effect,
-- whereas for other examples (eg inc8) a similar thing does, resulting in
-- eg a priorities[5] of {2,2,2,9,10,9}.
--
parents
--
-- See above. While itself this is pretty simple stuff, it is used to propagate
-- changes up the priority table when a file is (re)included, and for nowt else.
--
--sequence localscopes -- start of cleanup chain for dropScope -- now in pglobals
--sequence scopetypes, -- now in pglobals
--
-- localscopes are simply a linked list start pointer to a chain of all locals added
-- since the last increaseScope. These need to be detached from the ternary tree.
-- Global variables are always linked into the ternary tree below any locals, to
-- simplify this delinking process (obviously they remain linked to the ternary
-- tree permanently). The detached locals are marked with a -2 so that they can
-- be relinked to the ternary tree in pemit.e, for variable name output.
--
-- localscopes may be File or Routine (held in scopetypes).
--
-- scopefiles, -- now in pglobals
-- scopelines, -- ""
sequence scopeemits, -- save of emitline (see pemit.e)
scopelasts, -- save of lastline (see pemit.e)
scopetls,
--
-- scopefiles contains the filenos corresponding to localscopes (type File), for
-- restore when EOF of the included file is reached. Likewise scopelines entries
-- are only meaningful if the corresponding localscope is type File, and are used
-- to resume processing on the line after the include statement at EOF.
--NESTEDFUNC no longer true when scopetypes[scopelevel-1]=S_Rtn:
-- scopetls contains the corresponding toplevel sub.
-- There is very little difference between named and un-named (inline) constants,
-- except for value pooling. Two named constants cannot refer to the same slot,
-- since two names need to be kept. An unnamed constant can refer to a previously
-- declared named constant of the same value, but not vice versa. [DEV test this]
--
optsets
--
-- optsets just contains copies of optset at each scope level, ie is used to restore
-- the with/without settings when resuming on the line after an include statement.
--
--global integer scopelevel -- now in pglobals
--
-- scopelevel is the main ("current") index to localscopes, scopefiles, scopelines,
-- scopetypes, and optsets.
--
--procedure s50(object x)
-- if x=0 then ?9/0 end if
--end procedure
--s50(1)
--s50({})
--without trace
--with trace
-- moved here 27/8/14:
global procedure apnds5(object code)
integer opLnv
--DEV (bug) compilation (p -cp) sometimes toggles between these two for reasons unknown.
--!/**/ #isginfo{code,0b0101,MIN,MAX,integer,-2} -- (integer|dseq of integer), any length
--!/**/ #isginfo{code,0b1101,MIN,MAX,integer,-2} -- (integer|dseq of integer), any length
--DEV borken:
--!/**/ #isginfo{s5,0b0100,MIN,MAX,integer,-2} -- (as good a place as any to check this)
--!/**/ #isginfo{s5,0b0100,MIN,MAX,atom,-2} -- WRONG!!
--!/**/ #isginfo{s5,0b1100,MIN,MAX,atom,-2} -- EVEN WRONGER!! [DEV]
if lastline!=emitline then
--DEV why oh why is this not just part of DoWithOptions?! (and optset=)
opLnv = opLn
if not bind then
if optset[OptProfile] then opLnv = opLnp
-- elsif optset[OptProfileClone] then opLnv = opLnpclone
-- elsif optset[OptProfileCoverage] then opLnv = opLnpcover
elsif optset[OptProfileTime] then opLnv = opLnpt
elsif optset[OptTrace] then opLnv = opLnt
end if
end if
--if s5=0 then ?9/0 end if
--?shorten(s5)
--s50(s5)
--object s50 = {s5}
--if s50={0} then ?9/0 end if
--s50 = 0
s5 = append(s5,opLnv) -- opLn/p/pt/t
s5 = append(s5,emitline)
lastline = emitline
--if emitline=2886 then trace(1) end if
end if
s5 &= code
end procedure
--
-- Lists of re-usable temporaries.
--
-- Each routine gets their own private temporaries so that when b() calls a()
-- it does not have to save it's own temps. (In practice when b() calls a() it
-- creates a new "frame", ie space for all locals/tmps/parameters in a().)
-- Top-level code also has temps, however although there may be a separate
-- top-level-sub [entry in symtab], one for each source file, actually they
-- share the same tmp pool(s).
-- Atom temps are not re-used, to propagate any "must be integer" info better.
--
global sequence freetmplists -- 15 (T_object) free list pointers
sequence freetmplistsX
integer currtls
currtls = -1
--with trace
integer incfile, state
function upgradedParentPriorities(integer parent, integer newPriority)
--
-- Upgrades the priority of globals in files included by the parent
-- to be the same as the priority of those in the parent file, or
-- in other words a sub-include places no priority between globals
-- defined in the parent and/or the files the parent includes.
-- Also tags on the priority for the new file at the end.
--
-- Eg, assuming 8 is parent, {2,2,7,8,7} -> {2,2,8,8,8,12}.
-- (so while the parent, file 4, will pick an X from file 4 over
-- and above any in files 3 (a re-include) or 5 [since 8>7],
-- this new file (6), assuming it finds no X in file 6, must
-- demand a namespace if it finds >1 X in files 3,4,5.)
--
--p2js:
sequence res = deep_copy(priorities[parent])
integer parentPriority = parent*2
if res[parent]!=parentPriority then ?9/0 end if
for i=1 to parent-1 do
-- any re-includes?
if res[i]=parentPriority-1 then
res[i] = parentPriority
end if
end for
for i=parent+1 to length(res) do
-- the rest are all new
res[i] = parentPriority
end for
return res & newPriority
end function
procedure addToParents(integer fno, integer elen)
-- Recursively extend the priority table for parents, adding the new
-- file at a priority one less than globals defined in the parent itself.
-- The elen (expected length) parameter is just to make sure recursion
-- does not go crazy mad when files are included in more than one place.
integer k
sequence pk, pf
pf = parents[fno]
for i=1 to length(pf) do
k = pf[i]
pk = priorities[k]
if length(pk)=elen then
priorities[k] = 0 -- reduce ref count
pk &= k*2-1
priorities[k] = pk
addToParents(k,elen)
end if
end for
end procedure
--without warning -- (suppress "external forward reference; initialisation code may be skipped")
--global procedure AddFincParent()
-- parents = append(parents,{})
---- priorities = append(priorities,{})
-- priorities = append(priorities,{fileno*2})
---- priorities = append(priorities,{0})
--end procedure
--with warning
--with trace
global function increaseScope(integer scope, integer prevfile)
--
--integer prevscope
--if fileno=1 then ?{"increaseScope",scope, prevfile} if scope=4 then ?9/0 end if end if
if fileno<0 then -- re-include
--
-- just adjust parents, priorities, and resume with same file
--
incfile = -fileno
fileno = scopefiles[scopelevel]
if fileno!=prevfile then ?9/0 end if -- sanity check
-- col = 0
if not find(fileno,parents[incfile]) then
parents[incfile] = append(parents[incfile],fileno)
end if
-- and upgrade the priority of the include to match:
if fileno!=incfile then -- not self-includer!
priorities[fileno][incfile] = fileno*2-1
end if
else
--
-- First make sure there is a spare slot for the localscope
--
if scopelevel then
optsets[scopelevel] = optset
end if
integer prevscope = scopelevel
scopelevel += 1
if scopelevel>length(scopetypes) then
localscopes = append(localscopes,0)
scopetypes = append(scopetypes,0)
scopefiles = append(scopefiles,0)
scopelines = append(scopelines,0)
scopecols = append(scopecols,0)
scopeemits = append(scopeemits,0)
scopelasts = append(scopelasts,0)
scopetls = append(scopetls,0)
optsets = append(optsets,optset)
end if
localscopes[scopelevel] = 0 -- always start a new localscope,
scopetypes[scopelevel] = scope -- be it S_File or S_Rtn
if scope=S_File then
if prevfile then
parents = append(parents,{prevfile})
priorities = append(priorities,upgradedParentPriorities(prevfile,fileno*2))
addToParents(fileno,fileno-1)
else
if fileno=0 then
--if newEmit then
--printf(1,"psym.e line 327: fileno=0, FincMax=%d\n",{getFincMax()}) -- 0...
--end if
parents = {}
priorities = {}
else
parents = append(parents,{})
priorities = append(priorities,{fileno*2})
end if
end if
--
-- add to current includeset, create new File and Global scopes,
-- and save line number so we can resume, before resetting to line 1 col 0.
--
scopefiles[scopelevel] = fileno
if scopelevel>1 then
scopelines[prevscope] = line
if Ch<=0 then
scopecols[prevscope] = -1 -- (equivalent to ltl+1)
else
scopecols[prevscope] = tokcol
end if
line = 1
-- col = 0
symlimit += 1
symtab[currtls][S_il] = s5
s5 = {}
scopeemits[prevscope] = emitline
scopelasts[prevscope] = lastline
emitline = -1
lastline = -1
currtls = symlimit
if symlimit>length(symtab) then
symtab &= repeat(0,2000)
end if
state = S_used+K_used
if optset[OptDebug] then
state += K_wdb
end if
-- {name, type, file, state, link, scope, sig, par1/N/L, il, ltab, 1stl,s_efct}:
if newEBP then
symtab[currtls] = {-1, -- S_Name[1] (a top_level_sub)
S_Proc, -- S_NTyp[2]
fileno, -- S_FPno[3]
state, -- S_State[4]
0, -- S_Nlink[5]
0, -- S_Slink[6]
{'P'}, -- S_sig[7]
0, -- S_Parm1[8]
0, -- S_ParmN[9]
0, -- S_Ltot[10]
0, -- S_il[11]
0, -- S_ltab[12]
1, -- S_1stl[13]
0} -- S_Efct[14]
else
symtab[currtls] = {-1, -- S_Name[1] (a top_level_sub)
S_Proc, -- S_NTyp[2]
fileno, -- S_FPno[3]
state, -- S_State[4]
0, -- S_Nlink[5]
0, -- S_Slink[6]
{'P'}, -- S_sig[7]
-1, -- S_Parm1[8]
0, -- S_ParmN[9]
0, -- S_Ltot[10]
0, -- S_il[11]
0, -- S_ltab[12]
1, -- S_1stl[13]
0} -- S_Efct[14]
end if
scopetls[scopelevel] = currtls
else
scopetls[1] = T_maintls
end if
elsif scope=S_Rtn then
--NESTEDFUNC (needs a stack)
-- freetmplistsX = freetmplists -- save top_level_subs temps
-- freetmplists = repeat(0,T_object) -- create 15 new free list pointers
-- if DEBUG then
-- if scope!=S_Rtn then ?9/0 end if
-- end if
--
-- Start of new routine. Save code for _top_level_sub and set to {},
-- and add a temp scope to hold params and locals.
--
if NESTEDFUNC and scopelevel>1 and scopetypes[scopelevel-1]=S_Rtn then
scopetls[scopelevel-1] = currRtn
symtab[currRtn][S_il] = s5
s5 = {}
else -- (old code)
freetmplistsX = freetmplists -- save top_level_subs temps
freetmplists = repeat(0,T_object) -- create 15 new free list pointers
symtab[currtls][S_il] = s5
s5 = {}
end if
--DEV/SUG (28/8/14): scopelasts[prevscope] = lastline
-- (if "end procedure" is the very last line, the final file-level opRetf does not get an opLn, so ends up next to some earlier emitted code...)
-- elsif scope=S_Block then
-- -- (nothing else needs doing)
end if
end if
return currtls
end function
--10/10/2020
--global procedure clearTLSDebug()
global procedure clearTLSDebug(bool optOn)
-- "without debug" applies to the whole file, including the top_level_sub,
-- which has normally been created before the "without debug" is found.
state = symtab[currtls][S_State]
if optOn then
if not and_bits(state,K_wdb) then
state += K_wdb
symtab[currtls][S_State] = state
end if
else
if and_bits(state,K_wdb) then
state -= K_wdb
symtab[currtls][S_State] = state
end if
end if
end procedure
global procedure s5thunk(object o) -- (also used in pemit.e)
--if o=0 then ?9/0 end if
--if o!=0 then -- oh dear...
--/**/
--/**/ -- WARNING: Dirty trick. This does the same as the RDS Eu
--/**/ -- compatible code below, but in such a way as to foil the
--/**/ -- gvar scan. As mentioned elsewhere, modifying hll vars
--/**/ -- with #ilASM is dicey like that. We just swap o and s5
--/**/ -- (thus avoiding any refcount issues, see below) and can
--/**/ -- only do so because we are certain that saving/restoring
--/**/ -- s5 to/from (eg) [S_il] does not change it's type. The
--/**/ -- equivalent RDS Eu hll code makes s5 an "object", when
--/**/ -- we are trying to keep it "sequence of integer". Whether
--/**/ -- that actually yields any measureable gain is unknown,
--/**/ -- but at least we get an error from s5[i]="string" etc.
--/**/
--/**/ #ilASM{
--/**/ [32]
--/**/ mov edx,[o]
--/**/ mov eax,[s5]
--/**/ mov [s5],edx
--/**/ mov [o],eax
--/**/ [64]
--/**/ mov rdx,[o]
--/**/ mov rax,[s5]
--/**/ mov [s5],rdx
--/**/ mov [o],rax
--/**/ }
--/* -- RDS Eu equivalent (but not "type-safe"):
s5 = o
--*/
--end if
--object s50 = {s5}
--if s50={0} then ?9/0 end if
--s50 = 0
end procedure
-- Above I blythely said "thus avoiding any refcount issues"; it
-- is probably worthwhile explaining this in excrutiating detail.
-- First, consider the hll "s5=o" approach. On entry, o has a
-- refcount of 2, one for symtab[?][S_il] and one for o itself.
-- The s5=o line increases that to 3 and derefs/deallocs s5.
-- Finally the end procedure derefs o, leaving the refcount 2.
-- The #ilASM does no refcounting whatsoever, and it is the
-- end procedure which derefs s5 since that is now in o. Thus
-- the net effect is the same, but you should fully understand
-- the difference before using this in your application code,
-- and think carefully before "inlining" the above.
global integer builtinsReferenced
builtinsReferenced = 0
sequence binftab
sequence agfiles, -- filenames, eg "VM\pHeap.e"
agfdone, -- -1 after syminit, 0 = rqd, 1 after getBuiltin() (same length as agfiles)
agtidx, -- from tt_string(glabel,-3)s
agfnos -- corresponding index of agtidx[i] to agfiles[] (same length as agtidx)
--with trace
global procedure agchecktt(integer tidx, integer done=0)
integer k = find(tidx,agtidx)
if not emitON then ?9/0 end if
if k!=0 then
integer fno = agfnos[k]
if agfdone[fno] = -1 then
--printf(1,"agcheck: %s set\n",{agfiles[fno]})
--trace(1)
-- agfdone[fno] = 0
agfdone[fno] = done
if done=0 then
-- added 31/3/17:
--if suppressopRetf then ?9/0 end if
-- added 30/8/14:
builtinsReferenced = 1
end if
end if
end if
end procedure
global procedure agcheckop(integer opcode)
integer tidx = aatidx[opcode]
if tt[tidx+EQ]=0 then
agchecktt(tidx)
-- lblidx = get_lblidx(ttidx)
end if
end procedure
without trace
--with trace
global function dropScope(integer routineNo, integer scopetype)
integer st = scopetypes[scopelevel], -- scope type
-- scopechain,
tidx, -- scratch, fake ttidx
tnxt, -- scratch, scope clearance
wastls,
effects
--sequence ss -- copy of symtab[scopechain], speedwise
object sc -- scratch var, copy of symtab[currtls]
--if fileno=1 then ?{"dropScope",routineNo,scopetype} end if
-- st = scopetypes[scopelevel]
scopetypes[scopelevel] = 0 -- added 13/11
if st!=scopetype then ?9/0 end if
if fileno and st=S_File then
finalOptWarn[fileno] = optset[OptWarning]
end if
optsets[scopelevel] = 0
--
-- unlink everything on the scope chain:
--
integer scopechain = localscopes[scopelevel]
while scopechain do
sequence ss = symtab[scopechain] -- (speedwise)
tnxt = ss[S_Nlink]
if tnxt!=-2 then
tidx = ss[S_Name]
symtab[scopechain] = 0 -- reduce refcount on ss
ss[S_Nlink] = -2
symtab[scopechain] = ss
tt[tidx+EQ] = tnxt
end if
scopechain = ss[S_Slink]
end while
scopetls[scopelevel] = 0 -- (13/12/22, safety measure...)
scopelevel -= 1
if st!=S_Block then
if scopelevel then
optset = optsets[scopelevel]
end if
wastls = 0
if st=S_Rtn then
-- drop the scope and save the code, before restoring _top_level_sub's code
symtab[routineNo][S_il] = s5
--NESTEDFUNC (needs a stack)
freetmplists = freetmplistsX -- restore top_level_subs temps
else --st=S_File then
-- restore the file/line to continue after the include statement.
sc = symtab[currtls]
if length(s5) then
--if 01 then
-- new code (28/2/14, avoid opCallOnce to null-effect top-level
-- subroutines; if I am to migrate opcodes to ilASM, I really
-- don't want every app to start with 200+ unnecessary calls.)
--DEV isJmpG,0,0<:%opRetf>? (newEmit)
if length(s5)<11
or s5[1]!=opLn
or s5[3]!=opAsm
or s5[4]<5
or s5[7]!=#E9 --jump_rel32
or ((s5[8]!=isJmp or s5[11]!=length(s5)) and
-- 11/9/14: (when newEmit becomes permanent, might be able to get rid of isOpCode/opRetf, but leaving it in [forever] shouldn't hurt)
-- (s5[8]!=isOpCode or s5[11]!=opRetf)) then
(s5[8]!=isOpCode or s5[11]!=opRetf) and
(s5[8]!=isJmpG or s5[11]!=tt[aatidx[opRetf]+EQ]) and
(s5[8]!=isJmpG or s5[11]!=tt[aatidx[opCallOnceYeNot]+EQ])) then
-- s5 = append(s5,opRetf)
--if length(s5)<=12 then
-- ?{wastls,s5}
--else
-- ?{wastls,s5[1..12]}
--end if
-- {0,{213,20, -- opLn
-- 212,5,0,0, -- opAsm
-- #E9,#900,0,0,12,224}}isJmpG,
--if aatidx[opRetf] = ttidx then
-- tt[ttidx+EQ] = lblidx
-- printf(1,"opRetf; lblidx=%d\n",lblidx)
--end if
wastls = currtls
end if
-- (oops, ilxlate crashes if we leave this off..)
-- 27/8/14: (does not help)
-- s5 = append(s5,opRetf)
--trace(1)
emitline = line
-- 4/12/14:
if not suppressopRetf then
if newEmit then
agcheckop(opRetf)
end if
apnds5(opRetf)
end if
--else
-- s5 = append(s5,opRetf)
-- wastls = currtls
--end if
effects = sc[S_Efct]
end if
symtab[currtls] = 0
--p2js:
sc = deep_copy(sc)
sc[S_il] = s5
symtab[currtls] = sc
if scopelevel then
-- 18/9/10
-- if checkbuiltin[fileno] then
-- for i=T_Bin to T_Ainc do
-- if symtab[i][S_FPno]=fileno then
-- if and_bits(symtab[i][S_State],S_fwd_and_used)=S_fwd_and_used then
-- Abort("incorrect autoinclude version (missing "&getname(symtab[i][S_Name],-2)&')')
-- end if
-- end if
-- end for
-- end if
fileno = scopefiles[scopelevel]
--29/12/2010:
-- text = allfiles[fileno]
text = allpfiles[fileno]
ltl = length(text)
line = scopelines[scopelevel]
scopelines[scopelevel] = 0 -- added 13/11/10
col = scopecols[scopelevel]
if col=-1 then
Ch = -1
else
Ch = text[col]
end if
emitline = scopeemits[scopelevel]
lastline = scopelasts[scopelevel]
end if
end if -- st=S_File
if NESTEDFUNC and st=S_Rtn and scopetypes[scopelevel]=S_Rtn then
--if NESTEDFUNC and st=S_Rtn and scopetypes[scopelevel]>=S_Rtn then -- no help...
-- ?9/0
--if fileno=1 then ?{"nested",currtls,scopelevel,st,S_Rtn,scopetypes} end if
-- (as below, just leaving currtls undamaged, and no callonce)
integer parentRtn = scopetls[scopelevel]
sc = symtab[parentRtn]
s5thunk(sc[S_il]) -- sets s5
symtab[parentRtn] = 0 -- kill refcount
sc[S_il] = 0 -- kill refcount
symtab[parentRtn] = sc
return parentRtn
else
--if fileno=1 then ?{"currtls",currtls,scopelevel,st,S_Rtn,scopetypes} end if
if scopelevel then
--13/12/22:
-- currtls = scopetls[scopelevel]
integer stlssl = scopetls[scopelevel]
-- if stlssl=0 then return currtls end if -- oh dear...
-- if stlssl=0 and symtab[currtls][S_il]=0 then return currtls end if -- no help...
if stlssl then
currtls = stlssl
end if
end if
--if fileno=1 then ?{"currtls",currtls,scopelevel} end if
sc = symtab[currtls]
s5thunk(sc[S_il]) -- sets s5
--object s50 = {s5}
--if s50={0} then ?9/0 end if
--s50 = 0
symtab[currtls] = 0 -- kill refcount
sc[S_il] = 0 -- kill refcount
symtab[currtls] = sc
if wastls then
-- s5 = append(s5,opCallOnce)
-- s5 = append(s5,wastls)
--trace(1)
emitline = line
apnds5({opCallOnce,wastls})
if NOLT or bind or lint then
if and_bits(effects,E_vars) then
ltCall(0,effects,length(s5)-1) -- clear rqd gvar info
end if
end if -- NOLT
end if
end if
end if
return currtls
end function
--NESTEDFUNC:
global function hideScope()
--
-- hide localscope chain over nested function definition.
-- restScope is whatever restoreScope() needs it to be.
--
sequence restScope = {}
integer scopechain = localscopes[scopelevel]
while scopechain do
integer tnxt = symtab[scopechain][S_Nlink]
if tnxt!=-2 and symtab[scopechain][S_NTyp]=S_TVar then
integer tidx = symtab[scopechain][S_Name]
-- symtab[scopechain][S_Nlink] = -2
if tt[tidx+EQ]!=scopechain then ?9/0 end if
tt[tidx+EQ] = tnxt
restScope &= scopechain
end if
scopechain = symtab[scopechain][S_Slink]
end while
return restScope
end function
global procedure restoreScope(sequence restScope)
for i=length(restScope) to 1 by -1 do
integer scopechain = restScope[i]
integer tidx = symtab[scopechain][S_Name]
tt[tidx+EQ] = scopechain
end for
end procedure
global function hideNested(sequence nested_funcs)
for nfi in nested_funcs do
integer tidx = symtab[nfi][S_Name],
tnxt = symtab[nfi][S_Nlink]
if tt[tidx+EQ]!=nfi then ?9/0 end if
tt[tidx+EQ] = tnxt
--11/3/24:
symtab[nfi][S_Nlink] = -2
end for
return {}
end function
integer slink, glink, scope
slink = -1
-- glink = 0
--integer p, op
without trace
--with trace
--DEV/SUG , integer minp=0[/-1?]) [needs a fairly thorough working through from initialSymEntry]
integer tidx, fno -- work vars
global function addSymEntry(integer ttidx, integer asGlobal, integer Stype, object sig, object code, integer state)
sequence ssl -- symtab[slink/symlimit], speedwise
integer sl2 -- adjusted copy of scopelevel
integer minp -- min params (for initialSymEntry; DoRoutineDef (and hence initialAutoEntry) does it later)
symlimit += 1
if symlimit>length(symtab) then
symtab &= repeat(0,2000)
end if
if ttidx=-1 then
slink = 0
else
slink = tt[ttidx+EQ]
end if
scope = 0
-- if asGlobal then
if asGlobal and Stype!=S_Nspc then
--
-- keep the S_Nlink chain as {locals},{globals} so that dropScope can
-- just pick off the top element, rather than go hunting for it.
--
glink = 0
while slink do
ssl = symtab[slink]
if and_bits(ssl[S_State],K_gbl) then exit end if
glink = slink
slink = ssl[S_Nlink]
end while
else
sl2 = scopelevel
-- if Stype>S_Rsvd
-- and scopetypes[sl2]=S_Rtn then
if (Stype>S_Rsvd and scopetypes[sl2]=S_Rtn)
or (Stype=S_Nspc and asGlobal) then
--?{"sl2",sl2}
sl2 -= 1
asGlobal = 0
end if
scope = localscopes[sl2]
end if
if asGlobal then
state = or_bits(state,S_used_set_gbl)
elsif not optset[OptWarning] then
state = or_bits(state,S_used_and_set)
elsif Stype=S_Const then
state = or_bits(state,S_set)
end if
if optset[OptDebug] then
state += K_wdb
end if
if Stype<=S_TVar then
if Stype=S_TVar then
TIDX -= 1
if newEBP then
LIDX -= 1
tidx = LIDX
else
tidx = TIDX
end if
-- fno = currRtn
else -- Stype = S_GVar2/S_Const
tidx = 0
-- fno = fileno
end if
ssl = {ttidx, -- S_Name[1]
Stype, -- S_NTyp[2]
--26/11/19 (for nested functions, test...) [BUST...]
fileno, -- S_FPno[3]
-- fno, -- S_FPno[3] (now currRtn for Tvar)
state, -- S_State[4]
slink, -- S_Nlink[5]
scope, -- S_Slink[6]
sig, -- S_vtype[7]
0, -- S_value[8]
tidx, -- S_Clink[9](=0)/S_Tidx[9](=TIDX)
tokcol, -- S_ErrV[10]
0, -- S_Init[11]
sig, -- S_ltype[12]
0, -- S_maxlv[13]
0, -- S_gInfo[14]
0} -- S_gNew[15]
elsif Stype<=S_Rsvd then -- S_Nspc or S_Rsvd
fno = fileno
if fileno<0 then
fno = -fileno
end if
ssl = {ttidx, -- S_Name[1]
Stype, -- S_NTyp[2]
sig, -- S_FPno[3]
state, -- S_State[4]
slink, -- S_Nlink[5]
scope, -- S_Slink[6]
fno} -- S_nFno[7]
else -- routines
if newEBP then
tidx = 0
else
tidx = -TIDX+1
end if
if sequence(sig) then
minp = length(sig)-1
else
minp = 0
end if
ssl = {ttidx, -- S_Name[1]
Stype, -- S_NTyp[2]
fileno, -- S_FPno[3]
state, -- S_State[4]
slink, -- S_Nlink[5]
scope, -- S_Slink[6]
sig, -- S_sig[7]
tidx, -- S_Parm1[8]
-- 0, -- S_ParmN[9]
minp, -- S_ParmN[9]
0, -- S_Ltot[10]
code, -- S_il[11]
{}, -- S_ltab[12]
0, -- S_1stl[13]
E_none, -- S_Efct[14]
tokcol} -- S_ErrR[15]
end if
symtab[symlimit] = ssl
if ttidx!=-1 then
if asGlobal then
if glink then
symtab[glink][S_Nlink] = symlimit
else
tt[ttidx+EQ] = symlimit
end if
else
tt[ttidx+EQ] = symlimit
localscopes[sl2] = symlimit
end if
end if
return symlimit
end function
global function addSymEntryAt(integer ttidx, integer asGlobal, integer Stype, object sig, object code, integer state, integer atcol)
integer savetokcol, N
savetokcol = tokcol
tokcol = atcol
N = addSymEntry(ttidx,asGlobal,Stype,sig,code,state)
tokcol = savetokcol
return N
end function
--with trace
global procedure ReLinkAsGlobal(integer ttidx, integer N)
--
-- An implicit forward call has assumed local not global, but the actual
-- turned out to be a global. Technically a "forward proc/func xxx" is
-- an error (xxx was, by omission, explicitly defined as local) but we
-- just do this with no error (for now).
--
sequence ssl -- symtab[slink/symlimit], speedwise
integer tlink, nlink
integer found = 0
integer sl2
--trace(1)
tlink = tt[ttidx+EQ]
slink = tlink
glink = 0
while slink do
ssl = symtab[slink]
if and_bits(ssl[S_State],K_gbl) then exit end if
nlink = ssl[S_Nlink]
if slink=N then
if glink then
symtab[glink][S_Nlink] = nlink
else
tt[ttidx+EQ] = nlink
end if
found = 1
end if
glink = slink
slink = nlink