diff options
author | John Criswell <criswell@uiuc.edu> | 2004-02-16 23:43:31 +0000 |
---|---|---|
committer | John Criswell <criswell@uiuc.edu> | 2004-02-16 23:43:31 +0000 |
commit | d9c3e7a009df96bc366150cbaab843c5a7aa1c09 (patch) | |
tree | e545005209802df9ab1d034c310c0dcf98dfbf82 | |
parent | 4ea6ad37ccc1955429c24df4b49a4deb5e347aa0 (diff) |
Initial commit of the p2c benchmark (part of the Malloc Benchmark).
git-svn-id: https://llvm.org/svn/llvm-project/test-suite/trunk@11508 91177308-0d34-0410-b5e6-96231b3b80d8
24 files changed, 65951 insertions, 0 deletions
diff --git a/MultiSource/Benchmarks/MallocBench/p2c/INPUT/README b/MultiSource/Benchmarks/MallocBench/p2c/INPUT/README new file mode 100644 index 00000000..2cb61f0d --- /dev/null +++ b/MultiSource/Benchmarks/MallocBench/p2c/INPUT/README @@ -0,0 +1,8 @@ + +Test Inputs to p2c program: + +p2c -v < INPUT/grading.p +p2c -v < INPUT/ptc.p +p2c -v < INPUT/mf.p + + diff --git a/MultiSource/Benchmarks/MallocBench/p2c/INPUT/grading.p b/MultiSource/Benchmarks/MallocBench/p2c/INPUT/grading.p new file mode 100644 index 00000000..04a7b84a --- /dev/null +++ b/MultiSource/Benchmarks/MallocBench/p2c/INPUT/grading.p @@ -0,0 +1,514 @@ +program grading (input, output); + +const + namelength = 34; + idlength = 12; + commentlength = 6; + headlinelength = 40; + +type + + scores = + ( + assign1, assign2, assign3, assign4, + assign5, assign6, assign7, assign8, assigns, + exam1, exam2, better, final, total + ); + + gradetype = + ( + A, Aminus, + Bplus, B, Bminus, + Cplus, C, Cminus, + Dplus, D, Dminus, + F + ); + + grades = + ( + absolu, curved, course + ); + + namestring = packed array [1.. namelength] of char; + idstring = packed array [1.. idlength] of char; + commentstring = packed array [1.. commentlength] of char; + headlinestring = packed array [1..headlinelength] of char; + + studentpointer = ^ studentrecord; + studentrecord = + record + name : namestring; + id : idstring; + score : array [scores] of integer; + grade : array [grades] of gradetype; + rank : integer; + percentile : integer; + comment : commentstring; + next : studentpointer; + nextinrank : studentpointer + end; + +var + studentlist : studentpointer; + nonames : boolean; + nstudents, noshows, nofinals : integer; + + scoresfile : text; + + histogram : array [0..100] of integer; + histogramlist : array [0..100] of studentpointer; + + scoretorank : array [0..100] of integer; (* scoretorank [76] = rank of student(s) + with total score of 76 *) + percent : array [0..100] of integer; (* percent [76] = percentile of student(s) + with total score of 76 *) + +function isnoshow (student : studentrecord) : boolean; + begin + isnoshow := (student.score [total] = 0) + end (* isnoshow *); + +procedure computescoretorank; + var + score, nhigher : integer; + begin + nhigher := 0; + for score := 100 downto 0 do begin + scoretorank [score] := 1 + nhigher; + if + (nstudents - noshows - nofinals) > 0 + then + percent [score] := + ((nstudents - noshows - nofinals - nhigher) * 100) + div + (nstudents - noshows - nofinals) + else + percent [score] := 0; + nhigher := nhigher + histogram [score]; + end + end (* computescoretorank *); + +procedure settitle (headline : headlinestring); + begin + writeln ('.bp'); + writeln ('.ds Ti ', headline) + end (* settitle *); + +procedure writetroffheader; + begin + writeln ('.po 1.2c'); + writeln ('.m3 0'); + writeln ('.m4 10'); + writeln ('.ps 8'); + writeln ('.vs 10'); + writeln ('.pl 10.0i'); + writeln ('.ll 7.3i'); + writeln ('.lt 7.3i'); + writeln ('\ '); + writeln ('.bp'); + writeln ('.de $f'); + writeln ('.ev 1'); + writeln ('.nf'); + writeln ('.ti 4.85c'); + writeln ('\fC\ Gr\ \ \ \ \ Id\ \ \ \ \ \ \ \ A1\ A2\ A3\ A4\ A5\ A6\ A7\ A8\ A\ \ E1\ E2\ E\ \ Fi\ To\ Ab\ Cu\ Gr\ Rank\ Percentile\ Coll'); + writeln ('.sp 2'); + writeln ('.in 1.0i'); + writeln ('\fC\s+2A = \fRsum of all assignments'); + writeln ('\fCE1 = \fRfirst exam'); + writeln ('\fCE2 = \fRsecond exam'); + writeln ('\fCE = \fR better of first two exams'); + writeln ('\fCFi = \fRfinal exam'); + writeln ('.sp -5'); + writeln ('.in +2.3i'); + writeln ('\fCTo = \fRtotal score in course'); + writeln ('\fCAb = \fRgrade according to first (absolute, i.e. not curved) policy'); + writeln ('\fCCu = \fRgrade according to second (curved) policy'); + writeln ('\fCGr = \fRcourse grade'); + writeln ('Percentiles are computed ignoring ''No shows'' and ''No finals''.\s-2'); + writeln ('.sp 2'); + writeln ('.in 0'); + writeln ('.tl ^\s+8\fB\\*(Ti^^\*(td\s-8\fP^^'); + writeln ('.ev'); + writeln ('..'); + writeln ('.de $h'); + writeln ('.ev 1'); + writeln ('.ps 8'); + writeln ('.vs 10'); + writeln ('\ '); + writeln ('.sp |2.5c'); + writeln ('.ti 4.85c'); + writeln ('\fC\ Gr\ \ \ \ \ Id\ \ \ \ \ \ \ \ A1\ A2\ A3\ A4\ A5\ A6\ A7\ A8\ A\ \ E1\ E2\ E\ \ Fi\ To\ Ab\ Cu\ Gr\ Rank\ Percentile\ Coll'); + writeln ('.sp 2'); + writeln ('.ev'); + writeln ('..'); + writeln ('\ '); + writeln ('.bp'); + writeln ('\fC'); + writeln ('.nf'); + writeln ('.ev 1'); + writeln ('.ps 8'); + writeln ('.vs 10'); + writeln ('.ev'); + end (* writetroffheader *); + +procedure initialize; + var + score : integer; + begin + nstudents := 0; + noshows := 0; + nofinals := 0; + studentlist := nil; + + for score := 0 to 100 do begin + histogram [score] := 0; + histogramlist [score] := nil + end; + + writetroffheader + end (* initialize *); + +procedure readscores; + var + newstudent : studentpointer; + s : scores; + c : integer; + begin + new (newstudent); + nstudents := nstudents + 1; + + with newstudent^ do begin + next := studentlist; + + for c := 1 to namelength do + read (input, name [c]); + + for c := 1 to idlength do + read (input, id [c]); + + for s := assign1 to assign8 do + read (input, score [s]); + + read (input, score [exam1]); + read (input, score [exam2]); + read (input, score [final]); + + for c := 1 to commentlength do + read (input, comment [c]) + end; + + readln (input); + studentlist := newstudent + end (* readscores *); + +procedure computescores (student : studentpointer); + var + s : scores; + begin + with student^ do begin + score [assigns] := 0; + for s := assign1 to assign8 do + score [assigns] := score [assigns] + score [s]; + + if + score [exam1] > score [exam2] + then + score [better] := score [exam1] + else + score [better] := score [exam2]; + + score [total] := score [assigns] + + score [better ] + + score [final ]; + + if + isnoshow (student^) + then + noshows := noshows + 1 + else if + score [final] = 0 + then + nofinals := nofinals + 1 + else + histogram [score [total]] := histogram [score [total]] + 1; + + end + end (* computescores *); + +procedure computeallscores (studentlist : studentpointer); + begin + if + studentlist <> nil + then begin + computescores (studentlist); + computeallscores (studentlist^.next) + end + end (* computeallscores *); + +procedure computegrades (student : studentpointer); + + begin + with student^ do begin + if score [total] >= 90 then grade [absolu] := A else + if score [total] >= 88 then grade [absolu] := Aminus else + if score [total] >= 86 then grade [absolu] := Bplus else + if score [total] >= 80 then grade [absolu] := B else + if score [total] >= 78 then grade [absolu] := Bminus else + if score [total] >= 76 then grade [absolu] := Cplus else + if score [total] >= 70 then grade [absolu] := C else + if score [total] >= 65 then grade [absolu] := Cminus else + if score [total] >= 60 then grade [absolu] := Dplus else + if score [total] >= 55 then grade [absolu] := D else + if score [total] >= 50 then grade [absolu] := Dminus else + grade [absolu] := F + ; + + rank := scoretorank [score [total]]; + nextinrank := histogramlist [score [total]]; + histogramlist [score [total]] := student; + percentile := percent [score [total]]; + + if percentile >= 80 then grade [curved] := A else + if percentile >= 78 then grade [curved] := Aminus else + if percentile >= 76 then grade [curved] := Bplus else + if percentile >= 50 then grade [curved] := B else + if percentile >= 48 then grade [curved] := Bminus else + if percentile >= 46 then grade [curved] := Cplus else + if percentile >= 25 then grade [curved] := C else + if percentile >= 23 then grade [curved] := Cminus else + if percentile >= 21 then grade [curved] := Dplus else + if percentile >= 10 then grade [curved] := D else + if percentile >= 8 then grade [curved] := Dminus else + grade [curved] := F + ; + + if + grade [absolu] < grade [curved] + then + grade [course] := grade [absolu] + else + grade [course] := grade [curved] + + end + end (* computegrades *); + +procedure computeallgrades (studentlist : studentpointer); + begin + if + studentlist <> nil + then begin + computegrades (studentlist); + computeallgrades (studentlist^.next) + end + end (* computeallgrades *); + +function gradepoint (g : gradetype) : real; + begin + if g = A then gradepoint := 4.0 else + if g = Aminus then gradepoint := 3.7 else + if g = Bplus then gradepoint := 3.3 else + if g = B then gradepoint := 3.0 else + if g = Bminus then gradepoint := 2.7 else + if g = Cplus then gradepoint := 2.3 else + if g = C then gradepoint := 2.0 else + if g = Cminus then gradepoint := 1.7 else + if g = Dplus then gradepoint := 1.3 else + if g = D then gradepoint := 1.0 else + if g = Dminus then gradepoint := 0.7 else + if g = F then gradepoint := 0.0 else + gradepoint := 0.0 + end (* gradepoint *); + +procedure writegrade (g : gradetype); + begin + if g = A then write (' A ') else + if g = Aminus then write (' A-') else + if g = Bplus then write (' B+') else + if g = B then write (' B ') else + if g = Bminus then write (' B-') else + if g = Cplus then write (' C+') else + if g = C then write (' C ') else + if g = Cminus then write (' C-') else + if g = Dplus then write (' D+') else + if g = D then write (' D ') else + if g = Dminus then write (' D-') else + if g = F then write (' F ') else + write (' ??') + end (* writegrade *); + +procedure readallscores; + begin + while + not eof (input) + do + readscores + end (* readallscores *); + +procedure writestudent (student : studentpointer); + var + c : integer; + s : scores; + g : grades; + begin + end (* writestudent *); + +procedure writestraight (studentlist : studentpointer); + begin + if + studentlist <> nil + then begin + writestraight (studentlist^.next); + writestudent (studentlist); + end + end (* writestraight *); + +procedure gotoXY (x, y : integer); + begin + writeln ('\ '); + writeln ('.sp |', 1500 - 40 * y : 0, 'u'); + writeln ('.ti ', 40 * x : 0, 'u'); + end (* gotoXY *); + +procedure writehistogram; + var + score, height : integer; + begin + for score := 0 to 100 do + for height := 1 to histogram [score] do begin + gotoXY (score, height); + writeln ('X') + end; + + score := 0; + repeat + gotoXY (score, - 1); + writeln ('\v''0.5c''|'); + gotoXY (score, - 3); + writeln (score : 0); + score := score + 5 + until + score > 100; + + gotoXY (0,- 10) + end (* writehistogram *); + +procedure writerank (studentlist : studentpointer); + begin + if + studentlist <> nil + then begin + writerank (studentlist^.nextinrank); + writestudent (studentlist) + end + end (* writerank *); + +procedure writebyrank; + var + score : integer; + begin + for score := 100 downto 0 do + writerank (histogramlist [score]) + end (* writebyrank *); + +procedure stats; + var + scoresum : array [scores] of real; + gradecount : array [grades, gradetype] of integer; + s : scores; + g : grades; + gt : gradetype; + currentstudent : studentpointer; + begin + writeln ('.in 0'); + writeln ('.hl'); + writeln ('\fC'); + writeln ('.2c'); + write ('Number of students: '); + writeln (nstudents : 5); + write (' No-shows: '); + writeln (noshows : 5); + write (' No finals: '); + writeln (nofinals : 5); + write (' Assignment 1: '); + writeln (scoresum [assign1] / (nstudents - noshows) : 5 : 1); + write (' Assignment 2: '); + writeln (scoresum [assign2] / (nstudents - noshows) : 5 : 1); + write (' Assignment 3: '); + writeln (scoresum [assign3] / (nstudents - noshows) : 5 : 1); + write (' Assignment 4: '); + writeln (scoresum [assign4] / (nstudents - noshows) : 5 : 1); + write (' Assignment 5: '); + writeln (scoresum [assign5] / (nstudents - noshows) : 5 : 1); + write (' Assignment 6: '); + writeln (scoresum [assign6] / (nstudents - noshows) : 5 : 1); + write (' Assignment 7: '); + writeln (scoresum [assign7] / (nstudents - noshows) : 5 : 1); + write (' Assignment 8: '); + writeln (scoresum [assign8] / (nstudents - noshows) : 5 : 1); + write (' All assignments: '); + writeln (scoresum [assigns] / (nstudents - noshows) : 5 : 1); + write (' Exam 1: '); + writeln (scoresum [exam1 ] / (nstudents - noshows) : 5 : 1); + write (' Exam 2: '); + writeln (scoresum [exam2 ] / (nstudents - noshows) : 5 : 1); + write (' Better of 1,2: '); + writeln (scoresum [better ] / (nstudents - noshows) : 5 : 1); + write (' Final exam: '); + writeln (scoresum [final ] / (nstudents - noshows) : 5 : 1); + write (' Total score: '); + writeln (scoresum [total ] / (nstudents - noshows) : 5 : 1); + + writeln ('.sp 2'); + writeln ('Absolute grade distribution: '); + for gt := A to F do begin + writegrade (gt); + writeln (gradecount [absolu, gt]) + end; + writeln ('.bc'); + + writeln ('Curved grade distribution: '); + for gt := A to F do begin + writegrade (gt); + writeln (gradecount [curved, gt]) + end; + writeln ('.sp 2'); + + writeln ('Course grade distribution: '); + for gt := A to F do begin + writegrade (gt); + writeln (gradecount [course, gt]) + end; + + end (* stats *); + +begin + initialize; + readallscores; + computeallscores (studentlist); + computescoretorank; + computeallgrades (studentlist); + + settitle ('CSCI 1200, Spring 1989'); + nonames := false; + writestraight (studentlist); + + settitle ('CSCI 1200, Spring 1989'); + nonames := true; + writestraight (studentlist); + + settitle ('CSCI 1200, Spring 1989, grades by rank'); + nonames := false; + writebyrank; + + settitle ('CSCI 1200, Spring 1989, grade statistics'); + writeln ('.de $f'); + writeln ('.tl ^\v''1.0i''\s+8\fB\\*(Ti^^\*(td\s-8\fP\v''-1.0i''^^'); + writeln ('..'); + writeln ('.de $h'); + writeln ('..'); + writeln ('\ '); + writeln ('.bp'); + writeln ('Histogram, without ''No-shows'' and ''No finals'''); + writehistogram; + stats; +end. diff --git a/MultiSource/Benchmarks/MallocBench/p2c/INPUT/mf.p b/MultiSource/Benchmarks/MallocBench/p2c/INPUT/mf.p new file mode 100644 index 00000000..1969e693 --- /dev/null +++ b/MultiSource/Benchmarks/MallocBench/p2c/INPUT/mf.p @@ -0,0 +1,19497 @@ +program MF(input, output); {6:} + +{------------------------------} +{ declarations are in mf2ps1.h } +{------------------------------} +label + 1, 9998, 9999; +{:6} {11:} +const + memmax = 30000; + maxinternal = 100; + bufsize = 500; + errorline = 79; + halferrorline = 50; + maxprintline = 79; + screenwidth = 1024; + screendepth = 1024; + stacksize = 30; + maxstrings = 2000; + stringvacancies = 8000; + poolsize = 32000; + movesize = 5000; + maxwiggle = 300; + gfbufsize = 800; + filenamesize = 256; + poolname = 'mf.pool'; + pathsize = 300; + bistacksize = 785; + headersize = 100; + ligtablesize = 300; + maxfontdimen = 50; {:11} {18:} +type + ASCIIcode = 0..127; {:18} +{24:} + eightbits = 0..255; + alphafile = text; + {------------------} + postscript = text; + {------------------} + UNIXfilename = packed array [1..filenamesize] of char; + bytefile = + record + stdioptr: ^ integer; + locptr: ^ integer; + filename: UNIXfilename + end; {:24} {37:} + poolpointer = 0..poolsize; + strnumber = 0..maxstrings; {:37} +{101:} + scaled = integer; + smallnumber = 0..63; {:101} {105:} + fraction = integer; +{:105} + {106:} + angle = integer; {:106} {156:} + quarterword = -128..127; + halfword = -32768..32767; + twochoices = 1..2; + threechoices = 1..3; + twohalves = packed + record + rh: halfword; + case twochoices of + 1: ( + lh: halfword + ); + 2: ( + b0: quarterword; + b1: quarterword + ) + end; + fourquarters = packed + record + b0: quarterword; + b1: quarterword; + b2: quarterword; + b3: quarterword + end; + memoryword = + record + case threechoices of + 1: ( + int: integer + ); + 2: ( + hh: twohalves + ); + 3: ( + qqqq: fourquarters + ) + end; + wordfile = file of memoryword; {:156} {186:} + commandcode = 1..82; {:186} {565:} + screenrow = 0..screendepth; + screencol = 0..screenwidth; + transspec = array [screencol] of screencol; + pixelcolor = 0..1; {:565} {571:} + windownumber = 0..15; {:571} {627:} + instaterecord = + record + indexfield: quarterword; + startfield, locfield, limitfield, namefield: halfword + end; {:627} {1151:} + gfindex = 0..gfbufsize; + gfbuftype = array [gfindex] of eightbits; {:1151} {13:} +var + bad: integer; {:13} {20:} + xord: array [char] of ASCIIcode; + xchr: array [ASCIIcode] of char; {:20} {25:} + nameoffile, realnameoffile: UNIXfilename; + namelength: 0..filenamesize; {:25} +{29:} + buffer: array [0..bufsize] of ASCIIcode; + first: 0..bufsize; + last: 0..bufsize; + maxbufstack: 0..bufsize; {:29} {38:} + strpool: packed array [poolpointer] of ASCIIcode; + strstart: array [strnumber] of poolpointer; + poolptr: poolpointer; + strptr: strnumber; + initpoolptr: poolpointer; + initstrptr: strnumber; + maxpoolptr: poolpointer; + maxstrptr: strnumber; {:38} {42:} + strref: array [strnumber] of 0..127; {:42} {50:} + poolfile: alphafile; {:50} {54:} + logfile: alphafile; + {-------------------------------------------------------------} + psfile :postscript; { the PostScript code } + g :postscript; { holds the character information after re-arrange} + lastx0 , lasty0 :real ; { last point in sunpath } + lastx3 , lasty3 :real ; { make optimization on commands } + prevtox3 , prevtoy3 :real; + lastyearval , { mark entering to macros } + lastmonthval :integer; { STROKE , FILL , and ERASE } + { in MY plain.mf } + my_xx , my_yy :integer; { hold the values of xx & yy } + LineSource : integer; { Identifier for sendline source } + CurveSource : integer; { Identifier for makemoves source } + foundnew : boolean; { true while xchr[s]='[' until ']' } + ascval : integer; { holds the ascii of curr. letter } + ascii_on : boolean; { reading ascval is 'on' } + {-------------------------------------------------------------} + selector: 0..5; + dig: array [0..22] of 0..15; + tally: integer; + termoffset: 0..maxprintline; + fileoffset: 0..maxprintline; + trickbuf: array [0..errorline] of ASCIIcode; + trickcount: integer; + firstcount: integer; {:54} {68:} + interaction: 0..3; {:68} {71:} + deletionsallowed: boolean; + history: 0..3; + errorcount: -1..100; {:71} {74:} + helpline: array [0..5] of strnumber; + helpptr: 0..6; + useerrhelp: boolean; + errhelp: strnumber; {:74} {91:} + interrupt: integer; + OKtointerrupt: boolean; +{:91} + {97:} + aritherror: boolean; {:97} {129:} + twotothe: array [0..30] of integer; + speclog: array [1..28] of integer; {:129} {137:} + specatan: array [1..26] of angle; {:137} {144:} + nsin, ncos: fraction; {:144} +{148:} + randoms: array [0..54] of fraction; + jrandom: 0..54; {:148} {158:} + tempptr: halfword; {:158} {159:} + mem: array [-30000..memmax] of memoryword; + lomemmax: halfword; + himemmin: halfword; {:159} {160:} + varused, dynused: integer; +{:160} + {161:} + avail: halfword; + memend: halfword; {:161} {166:} + rover: halfword; +{:166} + {178:} + freearr: packed array [-30000..memmax] of boolean; + wasfree: packed array [-30000..memmax] of boolean; + wasmemend, waslomax, washimin: halfword; + panicking: boolean; {:178} {190:} + internal: array [1..maxinternal] of scaled; + intname: array [1..maxinternal] of strnumber; + intptr: 40..maxinternal; {:190} +{196:} + oldsetting: 0..5; {:196} {198:} + charclass: array [ASCIIcode] of 0..20; +{:198} + {200:} + hashused: halfword; + stcount: integer; {:200} {201:} + hash: array [1..2241] of twohalves; + eqtb: array [1..2241] of twohalves; {:201} +{225:} + gpointer: halfword; {:225} {230:} + bignodesize: array [13..14] of smallnumber; {:230} {250:} + saveptr: halfword; +{:250} + {267:} + pathtail: halfword; {:267} {279:} + deltax, deltay, delta: array [0..pathsize] of scaled; + psi: array [1..pathsize] of angle; {:279} {283:} + theta: array [0..pathsize] of angle; + uu: array [0..pathsize] of fraction; + vv: array [0..pathsize] of angle; + ww: array [0..pathsize] of fraction; {:283} +{298:} + st, ct, sf, cf: fraction; {:298} {308:} + move: array [0..movesize] of integer; + moveptr: 0..movesize; {:308} {309:} + bisectstack: array [0..bistacksize] of integer; + bisectptr: 0..bistacksize; +{:309} + {327:} + curedges: halfword; + curwt: integer; {:327} {371:} + tracex: integer; + tracey: integer; + traceyy: integer; {:371} {379:} + octant: 1..8; {:379} {389:} + curx, cury: scaled; {:389} {395:} + octantdir: array [1..8] of strnumber; {:395} +{403:} + curspec: halfword; + turningnumber: integer; + curpen: halfword; + curpathtype: 0..2; + maxallowed: scaled; {:403} {427:} + before, after: array [0..maxwiggle] of scaled; + nodetoround: array [0..maxwiggle] of halfword; + curroundingptr: 0..maxwiggle; + maxroundingptr: 0..maxwiggle; {:427} {430:} + curgran: scaled; {:430} {448:} + octantnumber: array [1..8] of 1..8; + octantcode: array [1..8] of 1..8; {:448} +{455:} + revturns: boolean; {:455} {461:} + ycorr, xycorr, zcorr: array [1..8] of 0..1; + xcorr: array [1..8] of -1..1; {:461} +{464:} + m0, n0, m1, n1: integer; + d0, d1: 0..1; {:464} {507:} + envmove: array [0..movesize] of integer; {:507} {552:} + tolstep: 0..6; {:552} +{555:} + curt, curtt: integer; + timetogo: integer; + maxt: integer; {:555} {557:} + delx, dely: integer; + tol: integer; + uv, xy: 0..bistacksize; + threel: integer; + apprt, apprtt: integer; {:557} {566:} +{screenpixel:array[screenrow,screencol]of pixelcolor;} + {:566} + {569:} + screenstarted: boolean; + screenOK: boolean; {:569} {572:} + windowopen: array [windownumber] of boolean; + leftcol: array [windownumber] of screencol; + rightcol: array [windownumber] of screencol; + toprow: array [windownumber] of screenrow; + botrow: array [windownumber] of screenrow; + mwindow: array [windownumber] of integer; + nwindow: array [windownumber] of integer; + windowtime: array [windownumber] of integer; {:572} {579:} + rowtransition: transspec; {:579} {585:} + serialno: integer; {:585} {592:} + fixneeded: boolean; + watchcoefs: boolean; + depfinal: halfword; {:592} {624:} + curcmd: eightbits; + curmod: integer; + cursym: halfword; {:624} {628:} + inputstack: array [0..stacksize] of instaterecord; + inputptr: 0..stacksize; + maxinstack: 0..stacksize; + curinput: instaterecord; {:628} {631:} + inopen: 0..6; + inputfile: array [1..6] of alphafile; + line: integer; + linestack: array [1..6] of integer; {:631} {633:} + paramstack: array [0..150] of halfword; + paramptr: 0..150; + maxparamstack: integer; {:633} {634:} + fileptr: 0..stacksize; {:634} {659:} + scannerstatus: 0..6; + warninginfo: integer; {:659} {680:} + forceeof: boolean; +{:680} + {699:} + bgloc, egloc: 1..2241; {:699} {738:} + condptr: halfword; + iflimit: 0..4; + curif: smallnumber; + ifline: integer; {:738} {752:} + loopptr: halfword; {:752} {767:} + curname: strnumber; + curarea: strnumber; + curext: strnumber; {:767} {768:} + areadelimiter: poolpointer; + extdelimiter: poolpointer; {:768} {775:} + MFbasedefault: packed array [1..10] of char; {:775} {782:} + jobname: strnumber; + logname: strnumber; {:782} {785:} + gfext: strnumber; {:785} {791:} + gffile: bytefile; + outputfilename: strnumber; {:791} {796:} + curtype: smallnumber; + curexp: integer; {:796} {813:} + maxc: array [17..18] of integer; + maxptr: array [17..18] of halfword; + maxlink: array [17..18] of halfword; {:813} {821:} + varflag: 0..82; {:821} {954:} + txx, txy, tyx, tyy, tx, ty: scaled; {:954} {1077:} + startsym: halfword; {:1077} +{1084:} + longhelpseen: boolean; {:1084} {1087:} + tfmfile: bytefile; + metricfilename: strnumber; {:1087} {1096:} + bc, ec: eightbits; + tfmwidth: array [eightbits] of scaled; + tfmheight: array [eightbits] of scaled; + tfmdepth: array [eightbits] of scaled; + tfmitalcorr: array [eightbits] of scaled; + charexists: array [eightbits] of boolean; + chartag: array [eightbits] of 0..3; + charremainder: array [eightbits] of eightbits; + headerbyte: array [1..headersize] of -1..255; + ligkern: array [0..ligtablesize] of fourquarters; + nl: 0..ligtablesize; + kern: array [eightbits] of scaled; + nk: 0..256; + exten: array [eightbits] of fourquarters; + ne: 0..256; + param: array [1..maxfontdimen] of scaled; + np: 0..maxfontdimen; + nw, nh, nd, ni: 0..256; {:1096} {1119:} + perturbation: scaled; {:1119} {1125:} + dimenhead: array [1..4] of halfword; {:1125} {1130:} + maxtfmdimen: scaled; + tfmchanged: integer; {:1130} {1149:} + gfminm, gfmaxm, gfminn, gfmaxn: integer; + gfprevptr: integer; + totalchars: integer; + charptr: array [eightbits] of integer; + gfdx, gfdy: array [eightbits] of integer; {:1149} {1152:} + gfbuf: gfbuftype; + halfbuf: gfindex; + gflimit: gfindex; + gfptr: gfindex; + gfoffset: integer; {:1152} +{1162:} + bocc, bocp: integer; {:1162} {1183:} + baseident: strnumber; {:1183} +{1188:} + basefile: wordfile; {:1188} {1203:} + readyalready: integer; {:1203} +{1214:} + editnamestart: poolpointer; + editnamelength, editline: integer; {:1214} + +procedure unskew(x, y: scaled; octant: smallnumber);external; + +procedure sendcurve(x0,x1,x2,x3,y0,y1,y2,y3,octant:integer);external; + +procedure sendline(x0,y0,x1,y1,octant,LineSource:integer);external; + +procedure confusion(s: strnumber);external; + +function abvscd(a, b, c, d: integer): integer;external; + +procedure makemoves(xx0, xx1, xx2, xx3, yy0, yy1, yy2, yy3: scaled; xicorr, etacorr: smallnumber;CurveSource:integer;oc:smallnumber);external; + +procedure print_start(var f:postscript);external; + +procedure print_end(var f:postscript);external; + +procedure init_ps(var f:postscript);external; + +procedure tini_ps(var f:postscript);external; + +procedure auxslowprint(s: integer);external; + +procedure auxprintnl(s: strnumber);external; + +procedure sendascii(asc: integer);external; + +{------------------------------} +{ $Header$ } + +{ declarations for external C assist routines for MetaFont } + +procedure exit(x : integer); + external; + +procedure closea(var f:text); + external; + +procedure closew(var f:wordfile); + external; + +procedure dateandtime(var minutes, day, month, year : integer); + external; + +procedure setpaths; + external; + +function testaccess(var nameoffile, realnameoffile: UNIXfilename; + accessmode:integer; filepath:integer): boolean; + external; + +procedure calledit(var filename: ASCIIcode; fnlength, linenumber: integer); + external; + +function bopenout(var f: bytefile; var name: UNIXfilename): boolean; + external; + +procedure bclose(var f: bytefile); + external; + +procedure bgetname(var f: bytefile; var name: UNIXfilename); + external; + +procedure bwritebuf(var f: bytefile; var buf: gfbuftype; + first, last: integer); + external; + +procedure bwritebyte(var f: bytefile; b: integer); + external; + +procedure bwrite2bytes(var f: bytefile; b: integer); + external; + +procedure bwrite4bytes(var f: bytefile; b: integer); + external; + +function makefraction(p, q: integer): fraction; + external; + +function takefraction(q: integer; f: fraction): integer; + external; + +{ $Header$ } + +{ External procedures for UNIX MetaFont VIRMF for display graphics } + +function initscreen: boolean; + external; + +procedure updatescreen; + external; + +procedure blankrectangle(leftcol, rightcol: screencol; toprow, botrow: screenrow); + external; + +procedure paintrow(r: screenrow; b: pixelcolor; var a: transspec; n: screencol); + external; + + + procedure initialize; {19:} + var + i: 0..127; {:19} {130:} + k: integer; {:130} {21:} + begin + xchr[32] := ' '; + xchr[33] := '!'; + xchr[34] := '"'; + xchr[35] := '#'; + xchr[36] := '$'; + xchr[37] := '%'; + xchr[38] := '&'; + xchr[39] := ''''; + xchr[40] := '('; + xchr[41] := ')'; + xchr[42] := '*'; + xchr[43] := '+'; + xchr[44] := ','; + xchr[45] := '-'; + xchr[46] := '.'; + xchr[47] := '/'; + xchr[48] := '0'; + xchr[49] := '1'; + xchr[50] := '2'; + xchr[51] := '3'; + xchr[52] := '4'; + xchr[53] := '5'; + xchr[54] := '6'; + xchr[55] := '7'; + xchr[56] := '8'; + xchr[57] := '9'; + xchr[58] := ':'; + xchr[59] := ';'; + xchr[60] := '<'; + xchr[61] := '='; + xchr[62] := '>'; + xchr[63] := '?'; + xchr[64] := '@'; + xchr[65] := 'A'; + xchr[66] := 'B'; + xchr[67] := 'C'; + xchr[68] := 'D'; + xchr[69] := 'E'; + xchr[70] := 'F'; + xchr[71] := 'G'; + xchr[72] := 'H'; + xchr[73] := 'I'; + xchr[74] := 'J'; + xchr[75] := 'K'; + xchr[76] := 'L'; + xchr[77] := 'M'; + xchr[78] := 'N'; + xchr[79] := 'O'; + xchr[80] := 'P'; + xchr[81] := 'Q'; + xchr[82] := 'R'; + xchr[83] := 'S'; + xchr[84] := 'T'; + xchr[85] := 'U'; + xchr[86] := 'V'; + xchr[87] := 'W'; + xchr[88] := 'X'; + xchr[89] := 'Y'; + xchr[90] := 'Z'; + xchr[91] := '['; + xchr[92] := '\'; + xchr[93] := ']'; + xchr[94] := '^'; + xchr[95] := '_'; + xchr[96] := '`'; + xchr[97] := 'a'; + xchr[98] := 'b'; + xchr[99] := 'c'; + xchr[100] := 'd'; + xchr[101] := 'e'; + xchr[102] := 'f'; + xchr[103] := 'g'; + xchr[104] := 'h'; + xchr[105] := 'i'; + xchr[106] := 'j'; + xchr[107] := 'k'; + xchr[108] := 'l'; + xchr[109] := 'm'; + xchr[110] := 'n'; + xchr[111] := 'o'; + xchr[112] := 'p'; + xchr[113] := 'q'; + xchr[114] := 'r'; + xchr[115] := 's'; + xchr[116] := 't'; + xchr[117] := 'u'; + xchr[118] := 'v'; + xchr[119] := 'w'; + xchr[120] := 'x'; + xchr[121] := 'y'; + xchr[122] := 'z'; + xchr[123] := '{'; + xchr[124] := '|'; + xchr[125] := '}'; + xchr[126] := '~'; + xchr[0] := ' '; + xchr[127] := ' '; {:21} {22:} + for i := 1 to 31 do + xchr[i] := ' '; + xchr[9] := chr(9); + xchr[12] := chr(12); {:22} +{23:} + for i := 0 to 127 do + xord[chr(i)] := 127; + for i := 1 to 126 do + xord[xchr[i]] := i; {:23} {69:} + interaction := 3; {:69} {72:} + deletionsallowed := true; + errorcount := 0; {:72} {75:} + helpptr := 0; + useerrhelp := false; + errhelp := 0; {:75} {92:} + interrupt := 0; + OKtointerrupt := true; +{:92} + {98:} + aritherror := false; {:98} {131:} + twotothe[0] := 1; + for k := 1 to 30 do + twotothe[k] := 2 * twotothe[k - 1]; + speclog[1] := 93032640; + speclog[2] := 38612034; + speclog[3] := 17922280; + speclog[4] := 8662214; + speclog[5] := 4261238; + speclog[6] := 2113709; + speclog[7] := 1052693; + speclog[8] := 525315; + speclog[9] := 262400; + speclog[10] := 131136; + speclog[11] := 65552; + speclog[12] := 32772; + speclog[13] := 16385; + for k := 14 to 27 do + speclog[k] := twotothe[27 - k]; + speclog[28] := 1; {:131} +{138:} + specatan[1] := 27855475; + specatan[2] := 14718068; + specatan[3] := 7471121; + specatan[4] := 3750058; + specatan[5] := 1876857; + specatan[6] := 938658; + specatan[7] := 469357; + specatan[8] := 234682; + specatan[9] := 117342; + specatan[10] := 58671; + specatan[11] := 29335; + specatan[12] := 14668; + specatan[13] := 7334; + specatan[14] := 3667; + specatan[15] := 1833; + specatan[16] := 917; + specatan[17] := 458; + specatan[18] := 229; + specatan[19] := 115; + specatan[20] := 57; + specatan[21] := 29; + specatan[22] := 14; + specatan[23] := 7; + specatan[24] := 4; + specatan[25] := 2; + specatan[26] := 1; {:138} {179:} +{wasmemend:=-30000;waslomax:=-30000;washimin:=memmax;panicking:=false;} +{:179} + {191:} + for k := 1 to 40 do + internal[k] := 0; + intptr := 40; {:191} {199:} + for k := 48 to 57 do + charclass[k] := 0; + charclass[46] := 1; + charclass[32] := 2; + charclass[37] := 3; + charclass[34] := 4; + charclass[44] := 5; + charclass[59] := 6; + charclass[40] := 7; + charclass[41] := 8; + for k := 65 to 90 do + charclass[k] := 9; + for k := 97 to 122 do + charclass[k] := 9; + charclass[95] := 9; + charclass[60] := 10; + charclass[61] := 10; + charclass[62] := 10; + charclass[58] := 10; + charclass[124] := 10; + charclass[96] := 11; + charclass[39] := 11; + charclass[43] := 12; + charclass[45] := 12; + charclass[47] := 13; + charclass[42] := 13; + charclass[92] := 13; + charclass[33] := 14; + charclass[63] := 14; + charclass[35] := 15; + charclass[38] := 15; + charclass[64] := 15; + charclass[36] := 15; + charclass[94] := 16; + charclass[126] := 16; + charclass[91] := 17; + charclass[93] := 18; + charclass[123] := 19; + charclass[125] := 19; + for k := 0 to 31 do + charclass[k] := 20; + charclass[127] := 20; + charclass[9] := 2; + charclass[12] := 2; {:199} {202:} + hash[1].lh := 0; + hash[1].rh := 0; + eqtb[1].lh := 41; + eqtb[1].rh := -30000; + for k := 2 to 2241 do begin + hash[k] := hash[1]; + eqtb[k] := eqtb[1] + end; {:202} {231:} + bignodesize[13] := 12; + bignodesize[14] := 4; +{:231} + {251:} + saveptr := -30000; {:251} {396:} + octantdir[1] := 415; + octantdir[5] := 416; + octantdir[6] := 417; + octantdir[2] := 418; + octantdir[4] := 419; + octantdir[8] := 420; + octantdir[7] := 421; + octantdir[3] := 422; {:396} {428:} + maxroundingptr := 0; {:428} {449:} + octantcode[1] := 1; + octantcode[2] := 5; + octantcode[3] := 6; + octantcode[4] := 2; + octantcode[5] := 4; + octantcode[6] := 8; + octantcode[7] := 7; + octantcode[8] := 3; + for k := 1 to 8 do + octantnumber[octantcode[k]] := k; {:449} {456:} + revturns := false; {:456} {462:} + xcorr[1] := 0; + ycorr[1] := 0; + xycorr[1] := 0; + xcorr[5] := 0; + ycorr[5] := 0; + xycorr[5] := 1; + xcorr[6] := -1; + ycorr[6] := 1; + xycorr[6] := 0; + xcorr[2] := 1; + ycorr[2] := 0; + xycorr[2] := 1; + xcorr[4] := 0; + ycorr[4] := 1; + xycorr[4] := 1; + xcorr[8] := 0; + ycorr[8] := 1; + xycorr[8] := 0; + xcorr[7] := 1; + ycorr[7] := 0; + xycorr[7] := 1; + xcorr[3] := -1; + ycorr[3] := 1; + xycorr[3] := 0; + for k := 1 to 8 do + zcorr[k] := xycorr[k] - xcorr[k]; {:462} {570:} + screenstarted := false; + screenOK := false; {:570} {573:} + for k := 0 to 15 do begin + windowopen[k] := false; + windowtime[k] := 0 + end; {:573} +{593:} + fixneeded := false; + watchcoefs := true; {:593} {739:} + condptr := -30000; + iflimit := 0; + curif := 0; + ifline := 0; {:739} {753:} + loopptr := -30000; {:753} {776:} + MFbasedefault := 'plain.base'; {:776} {797:} + curexp := 0; {:797} {822:} + varflag := 0; {:822} {1078:} + startsym := 0; {:1078} {1085:} + longhelpseen := false; +{:1085} + {1097:} + for k := 0 to 255 do begin + tfmwidth[k] := 0; + tfmheight[k] := 0; + tfmdepth[k] := 0; + tfmitalcorr[k] := 0; + charexists[k] := false; + chartag[k] := 0; + charremainder[k] := 0 + end; + for k := 1 to headersize do + headerbyte[k] := -1; + bc := 255; + ec := 0; + nl := 0; + nk := 0; + ne := 0; + np := 0; {:1097} {1150:} + gfprevptr := 0; + totalchars := 0; {:1150} {1153:} + halfbuf := gfbufsize div 2; + gflimit := gfbufsize; + gfptr := 0; + gfoffset := 0; {:1153} {1184:} + baseident := 0; {:1184} {1215:} + editnamestart := 0 + end; {:1215} {57:} + + procedure println; + begin + case selector of + 3: + begin + writeln(output); + writeln(logfile); + termoffset := 0; + fileoffset := 0 + end; + 2: + begin + writeln(logfile); + fileoffset := 0 + end; + 1: + begin + writeln(output); + termoffset := 0 + end; + 0, 4, 5: + end + end; {:57} {58:} + + procedure printchar(s: ASCIIcode); + var tmp : integer; + begin + case selector of + 3: + begin + {----------------------------------} + if xchr[s] = '[' then + begin + ascii_on := true; + ascval := 0; + end + else if xchr[s] = ']' then + begin + ascii_on := false; + sendascii(ascval); + end + else if ascii_on then + begin + tmp := s - ord('0'); + ascval := ascval*10+tmp; + end; + {-------------------------------------} + write(output, xchr[s]); + write(logfile, xchr[s]); + termoffset := termoffset + 1; + fileoffset := fileoffset + 1; + if termoffset = maxprintline then begin + writeln(output); + termoffset := 0 + end; + if fileoffset = maxprintline then begin + writeln(logfile); + fileoffset := 0 + end + end; + 2: + begin + write(logfile, xchr[s]); + fileoffset := fileoffset + 1; + if fileoffset = maxprintline then + println + end; + 1: + begin + write(output, xchr[s]); + termoffset := termoffset + 1; + if termoffset = maxprintline then + println + end; + 0: + ; + 4: + if tally < trickcount then + trickbuf[tally mod errorline] := s; + 5: + begin + if poolptr < poolsize then begin + strpool[poolptr] := s; + poolptr := poolptr + 1 + end + end + end; + tally := tally + 1 + end; {:58} {59:} + + procedure print(s: integer); + var + j: poolpointer; + begin + if (s < 0) or (s >= strptr) then + s := 131; + j := strstart[s]; + while j < strstart[s + 1] do begin + printchar(strpool[j]); + j := j + 1 + end + end; {:59} +{60:} + + procedure slowprint(s: integer); + var + j: poolpointer; + begin + if (s < 0) or (s >= strptr) then + s := 131; + j := strstart[s]; + while j < strstart[s + 1] do begin + print(strpool[j]); + j := j + 1 + end + end; {:60} +{62:} + + procedure printnl(s: strnumber); + begin + if ((termoffset > 0) and odd(selector)) or ((fileoffset > 0) and (selector >= 2)) then + println; + print(s) + end; {:62} {63:} + + procedure printthedigs(k: eightbits); + begin + while k > 0 do begin + k := k - 1; + printchar(48 + dig[k]) + end + end; {:63} {64:} + + procedure printint(n: integer); + var + k: 0..23; + m: integer; + begin + k := 0; + if n < 0 then begin + printchar(45); + if n > (-100000000) then + n := -n + else begin + m := (-1) - n; + n := m div 10; + m := (m mod 10) + 1; + k := 1; + if m < 10 then + dig[0] := m + else begin + dig[0] := 0; + n := n + 1 + end + end + end; + repeat + dig[k] := n mod 10; + n := n div 10; + k := k + 1 + until n = 0; + printthedigs(k) + end; {:64} {103:} + + procedure printscaled(s: scaled); + var + delta: scaled; + begin + if s < 0 then begin + printchar(45); + s := -s + end; + printint(s div 65536); + s := (10 * (s mod 65536)) + 5; + if s <> 5 then begin + delta := 10; + printchar(46); + repeat + if delta > 65536 then + s := (s + 32768) - (delta div 2); + printchar(48 + (s div 65536)); + s := 10 * (s mod 65536); + delta := delta * 10 + until s <= delta + end + end; {:103} {104:} + + procedure printtwo(x, y: scaled); + begin + printchar(40); + printscaled(x); + printchar(44); + printscaled(y); + printchar(41) + end; {:104} {187:} + + procedure printtype(t: smallnumber); + begin + if t in + [1, 2, 3, 4, 5, 6, 7, 8, + 9, 10, 11, 12, 13, 14, 16, 17, + 18, 15, 19, 20, 21, 22, 23] then + case t of + 1: + print(194); + 2: + print(195); + 3: + print(196); + 4: + print(197); + 5: + print(198); + 6: + print(199); + 7: + print(200); + 8: + print(201); + 9: + print(202); + 10: + print(203); + 11: + print(204); + 12: + print(205); + 13: + print(206); + 14: + print(207); + 16: + print(208); + 17: + print(209); + 18: + print(210); + 15: + print(211); + 19: + print(212); + 20: + print(213); + 21: + print(214); + 22: + print(215); + 23: + print(216) + end + else + print(217) + end; {:187} {195:} + + procedure begindiagnostic; + begin + oldsetting := selector; + if (internal[13] <= 0) and (selector = 3) then begin + selector := selector - 1; + if history = 0 then + history := 1 + end + end; { begindiagnostic } + + procedure enddiagnostic(blankline: boolean); + begin + printnl(155); + if blankline then + println; + selector := oldsetting + end; {:195} {197:} + + procedure printdiagnostic(s, t: strnumber; nuline: boolean); + begin + begindiagnostic; + if nuline then + printnl(s) + else + print(s); + print(320); + printint(line); + print(t); + printchar(58) + end; {:197} {773:} + + procedure printfilename(n, a, e: integer); + begin + print(a); + print(n); + print(e) + end; {:773} {73:} + + procedure normalizeselector; + forward; + + procedure getnext; + forward; + + procedure terminput; + forward; + + procedure showcontext; + forward; + + procedure beginfilereading; + forward; + + procedure openlogfile; + forward; + + procedure closefilesandtermina; + forward; + + procedure clearforerrorprompt; + forward; {procedure debughelp;forward;} {43:} + + procedure flushstring(s: strnumber); + begin + if s < (strptr - 1) then + strref[s] := 0 + else + repeat + strptr := strptr - 1 + until strref[strptr - 1] <> 0; + poolptr := strstart[strptr] + end; {:43} {:73} {76:} + + procedure jumpout; + begin + goto 9998 + end; {:76} {77:} + + procedure error; + label + 22, 10; + var + c: ASCIIcode; + s1, s2, s3: integer; + j: poolpointer; + begin + if history < 2 then + history := 2; + printchar(46); + showcontext; + if interaction = 3 then {78:} + while true do begin + 22: + clearforerrorprompt; + begin + print(135); + terminput + end; + if last = first then + goto 10; + c := buffer[first]; + if c >= 97 then + c := c - 32; {79:} + if c in + [48, 49, 50, 51, 52, 53, 54, 55, + 56, 57, 69, 72, 73, 81, 82, 83, + 88] then + case c of + 48, 49, 50, 51, 52, 53, 54, + 55, 56, 57: + if deletionsallowed then begin {83:} + s1 := curcmd; + s2 := curmod; + s3 := cursym; + OKtointerrupt := false; + if ((last > (first + 1)) and (buffer[first + 1] >= 48)) and (buffer[first + 1] <= 57) then + c := ((c * 10) + buffer[first + 1]) - (48 * 11) + else + c := c - 48; + while c > 0 do begin + getnext; +{743:} + if curcmd = 39 then begin + if strref[curmod] < 127 then + if strref[curmod] > 1 then + strref[curmod] := strref[curmod] - 1 + else + flushstring(curmod) + end {:743}; + c := c - 1 + end; + curcmd := s1; + curmod := s2; + cursym := s3; + OKtointerrupt := true; + begin + helpptr := 2; + helpline[1] := 148; + helpline[0] := 149 + end; + showcontext; + goto 22 + end {:83}; {68:begin debughelp;goto 22;end;} + 69: + if fileptr > 0 then begin + editnamestart := strstart[inputstack[fileptr].namefield]; + editnamelength := strstart[inputstack[fileptr].namefield + 1] - strstart[inputstack[fileptr].namefield]; + editline := line; + jumpout + end; + 72: + begin {84:} + if useerrhelp then begin {85:} + j := strstart[errhelp]; + while j < strstart[errhelp + 1] do begin + if strpool[j] <> 37 then + print(strpool[j]) + else if (j + 1) = strstart[errhelp + 1] then + println + else if strpool[j + 1] <> 37 then + println + else begin + j := j + 1; + printchar(37) + end; + j := j + 1 + end {:85}; + useerrhelp := false + end else begin + if helpptr = 0 then begin + helpptr := 2; + helpline[1] := 150; + helpline[0] := 151 + end; + repeat + helpptr := helpptr - 1; + print(helpline[helpptr]); + println + until helpptr = 0 + end; + begin + helpptr := 4; + helpline[3] := 152; + helpline[2] := 151; + helpline[1] := 153; + helpline[0] := 154 + end; + goto 22 + end; {:84} + 73: + begin {82:} + beginfilereading; + if last > (first + 1) then begin + curinput.locfield := first + 1; + buffer[first] := 32 + end else begin + begin + print(147); + terminput + end; + curinput.locfield := first + end; + first := last + 1; + curinput.limitfield := last; + goto 10 + end; {:82} + 81, 82, 83: + begin {81:} + errorcount := 0; + interaction := (0 + c) - 81; + print(142); + case c of + 81: + begin + print(143); + selector := selector - 1 + end; + 82: + print(144); + 83: + print(145) + end; + print(146); + println; + flush(output); + goto 10 + end; {:81} + 88: + begin + interaction := 2; + jumpout + end + end + else + ; {80:} + begin + print(136); + printnl(137); + printnl(138); + if fileptr > 0 then + print(139); + if deletionsallowed then + printnl(140); + printnl(141) + end {:80} {:79} + end {:78}; + errorcount := errorcount + 1; + if errorcount = 100 then begin + printnl(134); + history := 3; + jumpout + end; {86:} + if interaction > 0 then + selector := selector - 1; + if useerrhelp then begin + printnl(155); {85:} + j := strstart[errhelp]; + while j < strstart[errhelp + 1] do begin + if strpool[j] <> 37 then + print(strpool[j]) + else if (j + 1) = strstart[errhelp + 1] then + println + else if strpool[j + 1] <> 37 then + println + else begin + j := j + 1; + printchar(37) + end; + j := j + 1 + end {:85} + end else + while helpptr > 0 do begin + helpptr := helpptr - 1; + printnl(helpline[helpptr]) + end; + println; + if interaction > 0 then + selector := selector + 1; {:86} + println; + 10: + + end; {:77} +{88:} + + procedure fatalerror(s: strnumber); + begin + normalizeselector; + begin + if interaction = 3 then + ; + printnl(133); + print(156) + end; + begin + helpptr := 1; + helpline[0] := s + end; + begin + if interaction = 3 then + interaction := 2; + error; +{if interaction>0 then debughelp;} + history := 3; + jumpout + end + end; {:88} {89:} + + procedure overflow(s: strnumber; n: integer); + begin + normalizeselector; + begin + if interaction = 3 then + ; + printnl(133); + print(157) + end; + print(s); + printchar(61); + printint(n); + printchar(93); + begin + helpptr := 2; + helpline[1] := 158; + helpline[0] := 159 + end; + begin + if interaction = 3 then + interaction := 2; + error; +{if interaction>0 then debughelp;} + history := 3; + jumpout + end + end; {:89} {90:} + + procedure confusion; + begin + normalizeselector; + if history < 2 then begin + begin + if interaction = 3 then + ; + printnl(133); + print(160) + end; + print(s); + printchar(41); + begin + helpptr := 1; + helpline[0] := 161 + end + end else begin + begin + if interaction = 3 then + ; + printnl(133); + print(162) + end; + begin + helpptr := 2; + helpline[1] := 163; + helpline[0] := 164 + end + end; + begin + if interaction = 3 then + interaction := 2; + error; +{if interaction>0 then debughelp;} + history := 3; + jumpout + end + end; {:90} {:4} + + +{26:} + + function aopenin(var f: alphafile; pathspecifier: integer): boolean; + var + ok: boolean; + begin + if testaccess(nameoffile, realnameoffile, 4, pathspecifier) then begin + reset(f, realnameoffile); + ok := true + end else + ok := false; + aopenin := ok + end; { aopenin } + + function aopenout(var f: alphafile): boolean; + var + ok: boolean; + begin + if testaccess(nameoffile, realnameoffile, 2, 0) then begin + rewrite(f, realnameoffile); + ok := true + end else + ok := false; + aopenout := ok + end; { aopenout } + + function wopenin(var f: wordfile): boolean; + var + ok: boolean; + begin + if testaccess(nameoffile, realnameoffile, 4, 7) then begin + reset(f, realnameoffile); + ok := true + end else + ok := false; + wopenin := ok + end; { wopenin } + + function wopenout(var f: wordfile): boolean; + var + ok: boolean; + begin + if testaccess(nameoffile, realnameoffile, 2, 0) then begin + rewrite(f, nameoffile); + ok := true + end else + ok := false; + wopenout := ok + end; {:26} {27:} + + procedure aclose(var f: alphafile); + begin + closea(f) + end; { aclose } + + procedure wclose(var f: wordfile); + begin + closew(f) + end; {:27} {30:} + + function inputln(var f: alphafile; bypasseoln: boolean): boolean; + var + lastnonblank: 0..bufsize; + begin + if bypasseoln then + if not eof(f) then + if eoln(f) then + get(f); + last := first; + if eof(f) then + inputln := false + else begin + lastnonblank := first; + while not eoln(f) do begin + if last >= maxbufstack then begin + maxbufstack := last + 1; + if maxbufstack = bufsize then + overflow(128, bufsize) + end; + buffer[last] := xord[f^]; + get(f); + last := last + 1; + if buffer[last - 1] <> 32 then + lastnonblank := last + end; + last := lastnonblank; + inputln := true + end + end; {:30} {36:} + + function initterminal: boolean; + label + 10; + var + dummy, i, j, k: integer; + arg: packed array [1..100] of char; + begin + if argc > 1 then begin + last := first; + for i := 1 to argc - 1 do begin + argv(i, arg); + j := 1; + k := 100; + while (k > 1) and (arg[k] = ' ') do + k := k - 1; + while j <= k do begin + buffer[last] := xord[arg[j]]; + j := j + 1; + last := last + 1 + end; + if k > 1 then begin + buffer[last] := xord[' ']; + last := last + 1 + end + end; + if last > first then begin + curinput.locfield := first; + initterminal := true; + goto 10 + end + end; + while true do begin + write(output, '**'); + flush(output); + if not inputln(input, true) then begin + writeln(output); + writeln(output, '! End of file on the terminal... why?'); + initterminal := false; + goto 10 + end; + curinput.locfield := first; + while (curinput.locfield < last) and (buffer[curinput.locfield] = 32) do + curinput.locfield := curinput.locfield + 1; + if curinput.locfield < last then begin + initterminal := true; + goto 10 + end; + writeln(output, 'Please type the name of your input file.') + end; + 10: + + end; { initterminal } +{:36} + {44:} + + function makestring: strnumber; + begin + if strptr = maxstrptr then begin + if strptr = maxstrings then + overflow(130, maxstrings - initstrptr); + maxstrptr := maxstrptr + 1 + end; + strref[strptr] := 1; + strptr := strptr + 1; + strstart[strptr] := poolptr; + makestring := strptr - 1 + end; { makestring } +{:44} + {45:} + + function streqbuf(s: strnumber; k: integer): boolean; + label + 45; + var + j: poolpointer; + result: boolean; + begin + j := strstart[s]; + while j < strstart[s + 1] do begin + if strpool[j] <> buffer[k] then begin + result := false; + goto 45 + end; + j := j + 1; + k := k + 1 + end; + result := true; + 45: + streqbuf := result + end; {:45} {46:} + + function strvsstr(s, t: strnumber): integer; + label + 10; + var + j, k: poolpointer; + ls, lt: integer; + l: integer; + begin + ls := strstart[s + 1] - strstart[s]; + lt := strstart[t + 1] - strstart[t]; + if ls <= lt then + l := ls + else + l := lt; + j := strstart[s]; + k := strstart[t]; + while l > 0 do begin + if strpool[j] <> strpool[k] then begin + strvsstr := strpool[j] - strpool[k]; + goto 10 + end; + j := j + 1; + k := k + 1; + l := l - 1 + end; + strvsstr := ls - lt; + 10: + + end; {:46} {47:} + {function getstringsstarted:boolean;label 30,10; + var k,l:0..127;m,n:char;g:strnumber;a:integer;c:boolean; + begin poolptr:=0;strptr:=0;maxpoolptr:=0;maxstrptr:=0;strstart[0]:=0; + [48:]for k:=0 to 127 do begin if([49:](k<32)or(k>126)[:49])then begin + begin strpool[poolptr]:=94;poolptr:=poolptr+1;end; + begin strpool[poolptr]:=94;poolptr:=poolptr+1;end; + if k<64 then begin strpool[poolptr]:=k+64;poolptr:=poolptr+1; + end else begin strpool[poolptr]:=k-64;poolptr:=poolptr+1;end; + end else begin strpool[poolptr]:=k;poolptr:=poolptr+1;end;g:=makestring; + strref[g]:=127;end[:48];[51:]nameoffile:=poolname; + if aopenin(poolfile,8)then begin c:=false; + repeat[52:]begin if eof(poolfile)then begin; + writeln(output,'! mf.pool has no check sum.');aclose(poolfile); + getstringsstarted:=false;goto 10;end;read(poolfile,m,n); + if m='*'then[53:]begin a:=0;k:=1; + while true do begin if(xord[n]<48)or(xord[n]>57)then begin; + writeln(output,'! mf.pool check sum doesn''t have nine digits.'); + aclose(poolfile);getstringsstarted:=false;goto 10;end; + a:=10*a+xord[n]-48;if k=9 then goto 30;k:=k+1;read(poolfile,n);end; + 30:if a<>503742536 then begin; + writeln(output,'! mf.pool doesn''t match; tangle me again.'); + aclose(poolfile);getstringsstarted:=false;goto 10;end;c:=true; + end[:53]else begin if(xord[m]<48)or(xord[m]>57)or(xord[n]<48)or(xord[n]> + 57)then begin; + writeln(output,'! mf.pool line doesn''t begin with two digits.'); + aclose(poolfile);getstringsstarted:=false;goto 10;end; + l:=xord[m]*10+xord[n]-48*11; + if poolptr+l+stringvacancies>poolsize then begin; + writeln(output,'! You have to increase POOLSIZE.');aclose(poolfile); + getstringsstarted:=false;goto 10;end; + for k:=1 to l do begin if eoln(poolfile)then m:=' 'else read(poolfile,m) + ;begin strpool[poolptr]:=xord[m];poolptr:=poolptr+1;end;end; + readln(poolfile);g:=makestring;strref[g]:=127;end;end[:52];until c; + aclose(poolfile);getstringsstarted:=true;end else begin; + writeln(output,'! I can''t read mf.pool.');aclose(poolfile); + getstringsstarted:=false;goto 10;end[:51];10:end;} + {:47} + {65:} + + procedure printdd(n: integer); + begin + n := abs(n) mod 100; + printchar(48 + (n div 10)); + printchar(48 + (n mod 10)) + end; {:65} {66:} + + procedure terminput; + var + k: 0..bufsize; + begin + flush(output); + if not inputln(input, true) then + fatalerror(132); + termoffset := 0; + selector := selector - 1; + if last <> first then + for k := first to last - 1 do + print(buffer[k]); + println; + buffer[last] := 37; + selector := selector + 1 + end; {:66} {87:} + + procedure normalizeselector; + begin + if jobname > 0 then + selector := 3 + else + selector := 1; + if jobname = 0 then + openlogfile; + if interaction = 0 then + selector := selector - 1 + end; {:87} {93:} + + procedure pauseforinstructions; + begin + if OKtointerrupt then begin + interaction := 3; + if (selector = 2) or (selector = 0) then + selector := selector + 1; + begin + if interaction = 3 then + ; + printnl(133); + print(165) + end; + begin + helpptr := 3; + helpline[2] := 166; + helpline[1] := 167; + helpline[0] := 168 + end; + deletionsallowed := false; + error; + deletionsallowed := true; + interrupt := 0 + end + end; {:93} {94:} + + procedure missingerr(s: strnumber); + begin + begin + if interaction = 3 then + ; + printnl(133); + print(169) + end; + print(s); + print(170) + end; {:94} {99:} + + procedure cleararith; + begin + begin + if interaction = 3 then + ; + printnl(133); + print(171) + end; + begin + helpptr := 4; + helpline[3] := 172; + helpline[2] := 173; + helpline[1] := 174; + helpline[0] := 175 + end; + error; + aritherror := false + end; {:99} {100:} + + function slowadd(x, y: integer): integer; + begin + if x >= 0 then + if y <= (2147483647 - x) then + slowadd := x + y + else begin + aritherror := true; + slowadd := 2147483647 + end + else if (-y) <= (2147483647 + x) then + slowadd := x + y + else begin + aritherror := true; + slowadd := -2147483647 + end + end; {:100} {102:} + + function rounddecimals(k: smallnumber): scaled; + var + a: integer; + begin + a := 0; + while k > 0 do begin + k := k - 1; + a := (a + (dig[k] * 131072)) div 10 + end; + rounddecimals := (a + 1) div 2 + end; {:102} {112:} + + function takescaled(q: integer; f: scaled): integer; + var + p: integer; + negative: boolean; + n: integer; + becareful: integer; {110:} + begin + if f >= 0 then + negative := false + else begin + f := -f; + negative := true + end; + if q < 0 then begin + q := -q; + negative := not negative + end; {:110} + if f < 65536 then + n := 0 + else begin + n := f div 65536; + f := f mod 65536; + if q <= (2147483647 div n) then + n := n * q + else begin + aritherror := true; + n := 2147483647 + end + end; + f := f + 65536; {113:} + p := 32768; + if q < 1073741824 then + repeat + if odd(f) then + p := (p + q) div 2 + else + p := p div 2; + f := f div 2 + until f = 1 + else + repeat + if odd(f) then + p := p + ((q - p) div 2) + else + p := p div 2; + f := f div 2 + until f = 1 {:113}; + becareful := n - 2147483647; + if (becareful + p) > 0 then begin + aritherror := true; + n := 2147483647 - p + end; + if negative then + takescaled := -(n + p) + else + takescaled := n + p + end; {:112} {114:} + + function makescaled(p, q: integer): scaled; + var + f: integer; + n: integer; + negative: boolean; + becareful: integer; + begin + if p >= 0 then + negative := false + else begin + p := -p; + negative := true + end; + if q <= 0 then begin {if q=0 then confusion(47);} + q := -q; + negative := not negative + end; + n := p div q; + p := p mod q; + if n >= 32768 then begin + aritherror := true; + if negative then + makescaled := -2147483647 + else + makescaled := 2147483647 + end else begin + n := (n - 1) * 65536; {115:} + f := 1; + repeat + becareful := p - q; + p := becareful + p; + if p >= 0 then + f := (f + f) + 1 + else begin + f := f + f; + p := p + q + end + until f >= 65536; + becareful := p - q; + if (becareful + p) >= 0 then + f := f + 1 {:115}; + if negative then + makescaled := -(f + n) + else + makescaled := f + n + end + end; {:114} +{116:} + + function velocity(st, ct, sf, cf: fraction; t: scaled): fraction; + var + acc, num, denom: integer; + begin + acc := takefraction(st - (sf div 16), sf - (st div 16)); + acc := takefraction(acc, ct - cf); + num := 536870912 + takefraction(acc, 379625062); + denom := (805306368 + takefraction(ct, 497706707)) + takefraction(cf, 307599661); + if t <> 65536 then + num := makescaled(num, t); + if (num div 4) >= denom then + velocity := 1073741824 + else + velocity := makefraction(num, denom) + end; {:116} {117:} + + function abvscd ; + label + 10; + var + q, r: integer; {118:} + begin + if a < 0 then begin + a := -a; + b := -b + end; + if c < 0 then begin + c := -c; + d := -d + end; + if d <= 0 then begin + if b >= 0 then + if ((a = 0) or (b = 0)) and ((c = 0) or (d = 0)) then begin + abvscd := 0; + goto 10 + end else begin + abvscd := 1; + goto 10 + end; + if d = 0 then + if a = 0 then begin + abvscd := 0; + goto 10 + end else begin + abvscd := -1; + goto 10 + end; + q := a; + a := c; + c := q; + q := -b; + b := -d; + d := q + end else if b <= 0 then begin + if b < 0 then + if a > 0 then begin + abvscd := -1; + goto 10 + end; + if c = 0 then begin + abvscd := 0; + goto 10 + end else begin + abvscd := -1; + goto 10 + end + end {:118}; + while true do begin + q := a div d; + r := c div b; + if q <> r then + if q > r then begin + abvscd := 1; + goto 10 + end else begin + abvscd := -1; + goto 10 + end; + q := a mod d; + r := c mod b; + if r = 0 then + if q = 0 then begin + abvscd := 0; + goto 10 + end else begin + abvscd := 1; + goto 10 + end; + if q = 0 then begin + abvscd := -1; + goto 10 + end; + a := b; + b := q; + c := d; + d := r + end; + 10: + + end; {:117} {119:} + + function floorscaled(x: scaled): scaled; + var + becareful: integer; + begin + if x >= 0 then + floorscaled := x - (x mod 65536) + else begin + becareful := x + 1; + floorscaled := (x + ((-becareful) mod 65536)) - 65535 + end + end; { floorscaled } + + function floorunscaled(x: scaled): integer; + var + becareful: integer; + begin + if x >= 0 then + floorunscaled := x div 65536 + else begin + becareful := x + 1; + floorunscaled := -(1 + ((-becareful) div 65536)) + end + end; { floorunscaled } + + function roundunscaled(x: scaled): integer; + var + becareful: integer; + begin + if x >= 32768 then + roundunscaled := 1 + ((x - 32768) div 65536) + else if x >= (-32768) then + roundunscaled := 0 + else begin + becareful := x + 1; + roundunscaled := -(1 + (((-becareful) - 32768) div 65536)) + end + end; { roundunscaled } + + function roundfraction(x: fraction): scaled; + var + becareful: integer; + begin + if x >= 2048 then + roundfraction := 1 + ((x - 2048) div 4096) + else if x >= (-2048) then + roundfraction := 0 + else begin + becareful := x + 1; + roundfraction := -(1 + (((-becareful) - 2048) div 4096)) + end + end; {:119} {121:} + + function squarert(x: scaled): scaled; + var + k: smallnumber; + y, q: integer; + begin + if x <= 0 then begin {122:} + if x < 0 then begin + begin + if interaction = 3 then + ; + printnl(133); + print(176) + end; + printscaled(x); + print(177); + begin + helpptr := 2; + helpline[1] := 178; + helpline[0] := 179 + end; + error + end; + squarert := 0 + end else begin {:122} + k := 23; + q := 2; + while x < 536870912 do begin + k := k - 1; + x := ((x + x) + x) + x + end; + if x < 1073741824 then + y := 0 + else begin + x := x - 1073741824; + y := 1 + end; {123:} + repeat + x := x + x; + y := y + y; + if x >= 1073741824 then begin + x := x - 1073741824; + y := y + 1 + end; + x := x + x; + y := (y + y) - q; + q := q + q; + if x >= 1073741824 then begin + x := x - 1073741824; + y := y + 1 + end; + if y > q then begin + y := y - q; + q := q + 2 + end else if y <= 0 then begin + q := q - 2; + y := y + q + end; + k := k - 1 {:123} + until k = 0; + squarert := q div 2 + end + end; {:121} +{124:} + + function pythadd(a, b: integer): integer; + label + 30; + var + r: fraction; + big: boolean; + begin + a := abs(a); + b := abs(b); + if a < b then begin + r := b; + b := a; + a := r + end; + if a > 0 then begin + if a < 536870912 then + big := false + else begin + a := a div 4; + b := b div 4; + big := true + end; {125:} + while true do begin + r := makefraction(b, a); + r := takefraction(r, r); + if r = 0 then + goto 30; + r := makefraction(r, 1073741824 + r); + a := a + takefraction(a + a, r); + b := takefraction(b, r) + end; + 30: {:125} + ; + if big then + if a < 536870912 then + a := ((a + a) + a) + a + else begin + aritherror := true; + a := 2147483647 + end + end; + pythadd := a + end; {:124} {126:} + + function pythsub(a, b: integer): integer; + label + 30; + var + r: fraction; + big: boolean; + begin + a := abs(a); + b := abs(b); + if a <= b then begin {128:} + if a < b then begin + begin + if interaction = 3 then + ; + printnl(133); + print(180) + end; + printscaled(a); + print(181); + printscaled(b); + print(177); + begin + helpptr := 2; + helpline[1] := 178; + helpline[0] := 179 + end; + error + end; + a := 0 + end else begin {:128} + if a < 1073741824 then + big := false + else begin + a := a div 2; + b := b div 2; + big := true + end; {127:} + while true do begin + r := makefraction(b, a); + r := takefraction(r, r); + if r = 0 then + goto 30; + r := makefraction(r, 1073741824 - r); + a := a - takefraction(a + a, r); + b := takefraction(b, r) + end; + 30: {:127} + ; + if big then + a := a + a + end; + pythsub := a + end; {:126} {132:} + + function mlog(x: scaled): scaled; + var + y, z: integer; + k: integer; + begin + if x <= 0 then begin {134:} + begin + if interaction = 3 then + ; + printnl(133); + print(182) + end; + printscaled(x); + print(177); + begin + helpptr := 2; + helpline[1] := 183; + helpline[0] := 179 + end; + error; + mlog := 0 + end else begin {:134} + y := 1302456860; + z := 6581195; + while x < 1073741824 do begin + x := x + x; + y := y - 93032639; + z := z - 48782 + end; + y := y + (z div 65536); + k := 2; + while x > 1073741828 do begin {133:} + z := ((x - 1) div twotothe[k]) + 1; + while x < (1073741824 + z) do begin + z := (z + 1) div 2; + k := k + 1 + end; + y := y + speclog[k]; + x := x - z + end {:133}; + mlog := y div 8 + end + end; {:132} {135:} + + function mexp(x: scaled): scaled; + var + k: smallnumber; + y, z: integer; + begin + if x > 174436200 then begin + aritherror := true; + mexp := 2147483647 + end else if x < (-197694359) then + mexp := 0 + else begin + if x <= 0 then begin + z := -(8 * x); + y := 1048576 + end else begin + if x <= 127919879 then + z := 1023359037 - (8 * x) + else + z := 8 * (174436200 - x); + y := 2147483647 + end; {136:} + k := 1; + while z > 0 do begin + while z >= speclog[k] do begin + z := z - speclog[k]; + y := (y - 1) - ((y - twotothe[k - 1]) div twotothe[k]) + end; + k := k + 1 + end {:136}; + if x <= 127919879 then + mexp := (y + 8) div 16 + else + mexp := y + end + end; {:135} {139:} + + function narg(x, y: integer): angle; + var + z: angle; + t: integer; + k: smallnumber; + octant: 1..8; + begin + if x >= 0 then + octant := 1 + else begin + x := -x; + octant := 2 + end; + if y < 0 then begin + y := -y; + octant := octant + 2 + end; + if x < y then begin + t := y; + y := x; + x := t; + octant := octant + 4 + end; + if x = 0 then begin {140:} + begin + if interaction = 3 then + ; + printnl(133); + print(184) + end; + begin + helpptr := 2; + helpline[1] := 185; + helpline[0] := 179 + end; + error; + narg := 0 + end else begin {:140} {142:} + while x >= 536870912 do begin + x := x div 2; + y := y div 2 + end; + z := 0; + if y > 0 then begin + while x < 268435456 do begin + x := x + x; + y := y + y + end; {143:} + k := 0; + repeat + y := y + y; + k := k + 1; + if y > x then begin + z := z + specatan[k]; + t := x; + x := x + (y div twotothe[k + k]); + y := y - t + end + until k = 15; + repeat + y := y + y; + k := k + 1; + if y > x then begin + z := z + specatan[k]; + y := y - x + end + until k = 26 {:143} + end {:142}; {141:} + case octant of + 1: + narg := z; + 5: + narg := 94371840 - z; + 6: + narg := 94371840 + z; + 2: + narg := 188743680 - z; + 4: + narg := z - 188743680; + 8: + narg := (-z) - 94371840; + 7: + narg := z - 94371840; + 3: + narg := -z + end {:141} + end + end; {:139} {145:} + + procedure nsincos(z: angle); + var + k: smallnumber; + q: 0..7; + r: fraction; + x, y, t: integer; + begin + while z < 0 do + z := z + 377487360; + z := z mod 377487360; + q := z div 47185920; + z := z mod 47185920; + x := 268435456; + y := x; + if not odd(q) then + z := 47185920 - z; {147:} + k := 1; + while z > 0 do begin + if z >= specatan[k] then begin + z := z - specatan[k]; + t := x; + x := t + (y div twotothe[k]); + y := y - (t div twotothe[k]) + end; + k := k + 1 + end; + if y < 0 then + y := 0 {:147}; {146:} + case q of + 0: + ; + 1: + begin + t := x; + x := y; + y := t + end; + 2: + begin + t := x; + x := -y; + y := t + end; + 3: + x := -x; + 4: + begin + x := -x; + y := -y + end; + 5: + begin + t := x; + x := -y; + y := -t + end; + 6: + begin + t := x; + x := y; + y := -t + end; + 7: + y := -y + end {:146}; + r := pythadd(x, y); + ncos := makefraction(x, r); + nsin := makefraction(y, r) + end; {:145} {149:} + + procedure newrandoms; + var + k: 0..54; + x: fraction; + begin + for k := 0 to 23 do begin + x := randoms[k] - randoms[k + 31]; + if x < 0 then + x := x + 268435456; + randoms[k] := x + end; + for k := 24 to 54 do begin + x := randoms[k] - randoms[k - 24]; + if x < 0 then + x := x + 268435456; + randoms[k] := x + end; + jrandom := 54 + end; {:149} +{150:} + + procedure initrandoms(seed: scaled); + var + j, jj, k: fraction; + i: 0..54; + begin + j := abs(seed); + while j >= 268435456 do + j := j div 2; + k := 1; + for i := 0 to 54 do begin + jj := k; + k := j - k; + j := jj; + if k < 0 then + k := k + 268435456; + randoms[(i * 21) mod 55] := j + end; + newrandoms; + newrandoms; + newrandoms + end; {:150} +{151:} + + function unifrand(x: scaled): scaled; + var + y: scaled; + begin + if jrandom = 0 then + newrandoms + else + jrandom := jrandom - 1; + y := takefraction(abs(x), randoms[jrandom]); + if y = abs(x) then + unifrand := 0 + else if x > 0 then + unifrand := y + else + unifrand := -y + end; {:151} {152:} + + function normrand: scaled; + var + x, u, l: integer; + begin + repeat + repeat + if jrandom = 0 then + newrandoms + else + jrandom := jrandom - 1; + x := takefraction(112429, randoms[jrandom] - 134217728); + if jrandom = 0 then + newrandoms + else + jrandom := jrandom - 1; + u := randoms[jrandom] + until abs(x) < u; + x := makefraction(x, u); + l := 139548960 - mlog(u) + until abvscd(1024, l, x, x) >= 0; + normrand := x + end; {:152} +{157:} + {procedure printword(w:memoryword);begin printint(w.int); + printchar(32);printscaled(w.int);printchar(32); + printscaled(w.int div 4096);println;printint(w.hh.lh);printchar(61); + printint(w.hh.b0);printchar(58);printint(w.hh.b1);printchar(59); + printint(w.hh.rh);printchar(32);printint(w.qqqq.b0);printchar(58); + printint(w.qqqq.b1);printchar(58);printint(w.qqqq.b2);printchar(58); + printint(w.qqqq.b3);end;} + {:157} + {162:} + {217:} + + procedure printcapsule; + forward; + + procedure showtokenlist(p, q: integer; l, nulltally: integer); + label + 10; + var + class, c: smallnumber; + r, v: integer; + begin + class := 3; + tally := nulltally; + while (p <> (-30000)) and (tally < l) do begin + if p = q then begin {646:} + firstcount := tally; + trickcount := ((tally + 1) + errorline) - halferrorline; + if trickcount < errorline then + trickcount := errorline + end {:646}; {218:} + c := 9; + if (p < (-30000)) or (p > memend) then begin + print(360); + goto 10 + end; + if p < himemmin then {219:} + if mem[p].hh.b1 = 12 then + if mem[p].hh.b0 = 16 then begin {220:} + if class = 0 then + printchar(32); + v := mem[p + 1].int; + if v < 0 then begin + if class = 17 then + printchar(32); + printchar(91); + printscaled(v); + printchar(93); + c := 18 + end else begin + printscaled(v); + c := 0 + end + end else if mem[p].hh.b0 <> 4 then {:220} + print(363) + else begin + printchar(34); + slowprint(mem[p + 1].int); + printchar(34); + c := 4 + end + else if ((mem[p].hh.b1 <> 11) or (mem[p].hh.b0 < 1)) or (mem[p].hh.b0 > 19) then + print(363) + else begin + gpointer := p; + printcapsule; + c := 8 + end {:219} + else begin + r := mem[p].hh.lh; + if r >= 2242 then begin {222:} + if r < 2392 then begin + print(365); + r := r - 2242 + end else if r < 2542 then begin + print(366); + r := r - 2392 + end else begin + print(367); + r := r - 2542 + end; + printint(r); + printchar(41); + c := 8 + end else if r < 1 then {:222} + if r = 0 then begin {221:} + if class = 17 then + printchar(32); + print(364); + c := 18 + end else {:221} + print(361) + else begin + r := hash[r].rh; + if (r < 0) or (r >= strptr) then + print(362) {223:} + else begin + c := charclass[strpool[strstart[r]]]; + if c = class then + if c in + [9, 5, 6, 7, 8] then + case c of + 9: + printchar(46); + 5, 6, 7, 8: + end + else + printchar(32); + print(r) + end {:223} + end + end {:218}; + class := c; + p := mem[p].hh.rh + end; + if p <> (-30000) then + print(359); + 10: + + end; {:217} {665:} + + procedure runaway; + begin + if scannerstatus > 2 then begin + printnl(503); + case scannerstatus of + 3: + print(504); + 4, 5: + print(505); + 6: + print(506) + end; + println; + showtokenlist(mem[29998].hh.rh, -30000, errorline - 10, 0) + end + end; { runaway } +{:665} + {:162} + {163:} + + function getavail: halfword; + var + p: halfword; + begin + p := avail; + if p <> (-30000) then + avail := mem[avail].hh.rh + else if memend < memmax then begin + memend := memend + 1; + p := memend + end else begin + himemmin := himemmin - 1; + p := himemmin; + if himemmin <= lomemmax then begin + runaway; + overflow(186, memmax + 30001) + end + end; + mem[p].hh.rh := -30000; +{dynused:=dynused+1;} + getavail := p + end; {:163} {167:} + + function getnode(s: integer): halfword; + label + 40, 10, 20; + var + p: halfword; + q: halfword; + r: integer; + t, tt: integer; + begin + 20: + p := rover; {169:} + repeat + q := p + mem[p].hh.lh; + while mem[q].hh.rh = 32767 do begin + t := mem[q + 1].hh.rh; + tt := mem[q + 1].hh.lh; + if q = rover then + rover := t; + mem[t + 1].hh.lh := tt; + mem[tt + 1].hh.rh := t; + q := q + mem[q].hh.lh + end; + r := q - s; + if r > (p + 1) then begin {170:} + mem[p].hh.lh := r - p; + rover := p; + goto 40 + end {:170}; + {171 + :} + if r = p then + if (mem[p + 1].hh.rh <> rover) or (mem[p + 1].hh.lh <> rover) then begin + rover := mem[p + 1].hh.rh; + t := mem[p + 1].hh.lh; + mem[rover + 1].hh.lh := t; + mem[t + 1].hh.rh := rover; + goto 40 + end {:171}; + mem[p].hh.lh := q - p {:169}; + p := mem[p + 1].hh.rh + until p = rover; + if s = 1073741824 then begin + getnode := 32767; + goto 10 + end; + if (lomemmax + 2) < himemmin then + if (lomemmax + 2) <= 2767 then begin {168:} + if (lomemmax + 1000) < himemmin then + t := lomemmax + 1000 + else + t := ((lomemmax + himemmin) + 2) div 2; + if t > 2767 then + t := 2767; + p := mem[rover + 1].hh.lh; + q := lomemmax; + mem[p + 1].hh.rh := q; + mem[rover + 1].hh.lh := q; + mem[q + 1].hh.rh := rover; + mem[q + 1].hh.lh := p; + mem[q].hh.rh := 32767; + mem[q].hh.lh := t - lomemmax; + lomemmax := t; + mem[lomemmax].hh.rh := -30000; + mem[lomemmax].hh.lh := -30000; + rover := q; + goto 20 + end {:168}; + overflow(186, memmax + 30001); + 40: + mem[r].hh.rh := -30000; {varused:=varused+s;} + getnode := r; + 10: + + end; {:167} {172:} + + procedure freenode(p: halfword; s: halfword); + var + q: halfword; + begin + mem[p].hh.lh := s; + mem[p].hh.rh := 32767; + q := mem[rover + 1].hh.lh; + mem[p + 1].hh.lh := q; + mem[p + 1].hh.rh := rover; + mem[rover + 1].hh.lh := p; + mem[q + 1].hh.rh := p + end; {varused:=varused-s;} {:172} +{173:} + {procedure sortavail;var p,q,r:halfword;oldrover:halfword; + begin p:=getnode(1073741824);p:=mem[rover+1].hh.rh; + mem[rover+1].hh.rh:=32767;oldrover:=rover; + while p<>oldrover do[174:]if p<rover then begin q:=p;p:=mem[q+1].hh.rh; + mem[q+1].hh.rh:=rover;rover:=q;end else begin q:=rover; + while mem[q+1].hh.rh<p do q:=mem[q+1].hh.rh;r:=mem[p+1].hh.rh; + mem[p+1].hh.rh:=mem[q+1].hh.rh;mem[q+1].hh.rh:=p;p:=r;end[:174]; + p:=rover; + while mem[p+1].hh.rh<>32767 do begin mem[mem[p+1].hh.rh+1].hh.lh:=p; + p:=mem[p+1].hh.rh;end;mem[p+1].hh.rh:=rover;mem[rover+1].hh.lh:=p;end;} +{:173} + {177:} + + procedure flushlist(p: halfword); + label + 30; + var + q, r: halfword; + begin + if p >= himemmin then + if p <> 30000 then begin + r := p; + repeat + q := r; + r := mem[r].hh.rh; {dynused:=dynused-1;} + if r < himemmin then + goto 30 + until r = 30000; + 30: + mem[q].hh.rh := avail; + avail := p + end + end; { flushlist } + + procedure flushnodelist(p: halfword); + var + q: halfword; + begin + while p <> (-30000) do begin + q := p; + p := mem[p].hh.rh; + if q < himemmin then + freenode(q, 2) + else begin + mem[q].hh.rh := avail; + avail := q + end +{dynused:=dynused-1;} + end + end; {:177} {180:} +{procedure checkmem(printlocs:boolean);label 31,32;var p,q,r:halfword; +clobbered:boolean;begin for p:=-30000 to lomemmax do freearr[p]:=false; +for p:=himemmin to memend do freearr[p]:=false;[181:]p:=avail;q:=-30000; +clobbered:=false; +while p<>-30000 do begin if(p>memend)or(p<himemmin)then clobbered:=true +else if freearr[p]then clobbered:=true; +if clobbered then begin printnl(187);printint(q);goto 31;end; +freearr[p]:=true;q:=p;p:=mem[q].hh.rh;end;31:[:181];[182:]p:=rover; +q:=-30000;clobbered:=false; +repeat if(p>=lomemmax)or(p<-30000)then clobbered:=true else if(mem[p+1]. +hh.rh>=lomemmax)or(mem[p+1].hh.rh<-30000)then clobbered:=true else if +not((mem[p].hh.rh=32767))or(mem[p].hh.lh<2)or(p+mem[p].hh.lh>lomemmax)or +(mem[mem[p+1].hh.rh+1].hh.lh<>p)then clobbered:=true; +if clobbered then begin printnl(188);printint(q);goto 32;end; +for q:=p to p+mem[p].hh.lh-1 do begin if freearr[q]then begin printnl( +189);printint(q);goto 32;end;freearr[q]:=true;end;q:=p; +p:=mem[p+1].hh.rh;until p=rover;32:[:182];[183:]p:=-30000; +while p<=lomemmax do begin if(mem[p].hh.rh=32767)then begin printnl(190) +;printint(p);end;while(p<=lomemmax)and not freearr[p]do p:=p+1; +while(p<=lomemmax)and freearr[p]do p:=p+1;end[:183];[617:]q:=-29987; +p:=mem[q].hh.rh; +while p<>-29987 do begin if mem[p+1].hh.lh<>q then begin printnl(463); +printint(p);end;p:=mem[p+1].hh.rh;r:=himemmin; +repeat if mem[p].hh.lh>=r then begin printnl(464);printint(p);end; +r:=mem[p].hh.lh;q:=p;p:=mem[q].hh.rh;until r=-30000;end[:617]; +if printlocs then[184:]begin printnl(191); +for p:=-30000 to lomemmax do if not freearr[p]and((p>waslomax)or wasfree +[p])then begin printchar(32);printint(p);end; +for p:=himemmin to memend do if not freearr[p]and((p<washimin)or(p> +wasmemend)or wasfree[p])then begin printchar(32);printint(p);end; +end[:184];for p:=-30000 to lomemmax do wasfree[p]:=freearr[p]; +for p:=himemmin to memend do wasfree[p]:=freearr[p];wasmemend:=memend; +waslomax:=lomemmax;washimin:=himemmin;end;} + {:180} + {185:} +{procedure searchmem(p:halfword);var q:integer; +begin for q:=-30000 to lomemmax do begin if mem[q].hh.rh=p then begin +printnl(192);printint(q);printchar(41);end; +if mem[q].hh.lh=p then begin printnl(193);printint(q);printchar(41);end; +end; +for q:=himemmin to memend do begin if mem[q].hh.rh=p then begin printnl( +192);printint(q);printchar(41);end; +if mem[q].hh.lh=p then begin printnl(193);printint(q);printchar(41);end; +end; +[209:]for q:=1 to 2241 do begin if eqtb[q].rh=p then begin printnl(328); +printint(q);printchar(41);end;end[:209];end;} + {:185} + {189:} + + procedure printop(c: quarterword); + begin + if c <= 15 then + printtype(c) + else + if c in + [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, 94, + 95, 96, 97, 98, 99, 100] then + case c of + 30: + print(218); + 31: + print(219); + 32: + print(220); + 33: + print(221); + 34: + print(222); + 35: + print(223); + 36: + print(224); + 37: + print(225); + 38: + print(226); + 39: + print(227); + 40: + print(228); + 41: + print(229); + 42: + print(230); + 43: + print(231); + 44: + print(232); + 45: + print(233); + 46: + print(234); + 47: + print(235); + 48: + print(236); + 49: + print(237); + 50: + print(238); + 51: + print(239); + 52: + print(240); + 53: + print(241); + 54: + print(242); + 55: + print(243); + 56: + print(244); + 57: + print(245); + 58: + print(246); + 59: + print(247); + 60: + print(248); + 61: + print(249); + 62: + print(250); + 63: + print(251); + 64: + print(252); + 65: + print(253); + 66: + print(254); + 67: + print(255); + 68: + print(256); + 69: + printchar(43); + 70: + printchar(45); + 71: + printchar(42); + 72: + printchar(47); + 73: + print(257); + 74: + print(181); + 75: + print(258); + 76: + print(259); + 77: + printchar(60); + 78: + print(260); + 79: + printchar(62); + 80: + print(261); + 81: + printchar(61); + 82: + print(262); + 83: + print(38); + 84: + print(263); + 85: + print(264); + 86: + print(265); + 87: + print(266); + 88: + print(267); + 89: + print(268); + 90: + print(269); + 91: + print(270); + 92: + print(271); + 94: + print(272); + 95: + print(273); + 96: + print(274); + 97: + print(275); + 98: + print(276); + 99: + print(277); + 100: + print(278) + end + else + print(279) + end; { printop } +{:189} + {194:} + + procedure fixdateandtime; + begin + dateandtime(internal[17], internal[16], internal[15], internal[14]); + internal[17] := internal[17] * 65536; + internal[16] := internal[16] * 65536; + internal[15] := internal[15] * 65536; + internal[14] := internal[14] * 65536; + {----------------------------------} + lastyearval := internal[14]; + lastmonthval:= internal[15]; + {----------------------------------} + end; { fixdateandtime } +{:194} + {205:} + + function idlookup(j, l: integer): halfword; + label + 40; + var + h: integer; + p: halfword; + k: halfword; + begin + if l = 1 then begin {206:} + p := buffer[j] + 1; + hash[p].rh := p - 1; + goto 40 + end {:206}; {208:} + h := buffer[j]; + for k := j + 1 to (j + l) - 1 do begin + h := (h + h) + buffer[k]; + while h >= 1777 do + h := h - 1777 + end {:208}; + p := h + 129; + while true do begin + if hash[p].rh > 0 then + if (strstart[hash[p].rh + 1] - strstart[hash[p].rh]) = l then + if streqbuf(hash[p].rh, j) then + goto 40; + if hash[p].lh = 0 then begin {207:} + if hash[p].rh > 0 then begin + repeat + if hashused = 1 then + overflow(327, 2100); + hashused := hashused - 1 + until hash[hashused].rh = 0; + hash[p].lh := hashused; + p := hashused + end; + begin + if (poolptr + l) > maxpoolptr then begin + if (poolptr + l) > poolsize then + overflow(129, poolsize - initpoolptr); + maxpoolptr := poolptr + l + end + end; + for k := j to (j + l) - 1 do begin + strpool[poolptr] := buffer[k]; + poolptr := poolptr + 1 + end; + hash[p].rh := makestring; + strref[hash[p].rh] := 127; +{stcount:=stcount+1;} + goto 40 + end {:207}; + p := hash[p].lh + end; + 40: + idlookup := p + end; {:205} {210:} + {procedure primitive(s:strnumber;c:halfword;o:halfword); + var k:poolpointer;j:smallnumber;l:smallnumber;begin k:=strstart[s]; + l:=strstart[s+1]-k;for j:=0 to l-1 do buffer[j]:=strpool[k+j]; + cursym:=idlookup(0,l);if s>=128 then begin flushstring(strptr-1); + hash[cursym].rh:=s;end;eqtb[cursym].lh:=c;eqtb[cursym].rh:=o;end;} + {:210} +{215:} + + function newnumtok(v: scaled): halfword; + var + p: halfword; + begin + p := getnode(2); + mem[p + 1].int := v; + mem[p].hh.b0 := 16; + mem[p].hh.b1 := 12; + newnumtok := p + end; {:215} {216:} + + procedure tokenrecycle; + forward; + + procedure flushtokenlist(p: halfword); + var + q: halfword; + begin + while p <> (-30000) do begin + q := p; + p := mem[p].hh.rh; + if q >= himemmin then begin + mem[q].hh.rh := avail; + avail := q + end else begin +{dynused:=dynused-1;} + if mem[q].hh.b0 in + [1, 2, 16, 4, 3, 5, 7, 12, + 10, 6, 9, 8, 11, 14, 13, 17, + 18, 19] then + case mem[q].hh.b0 of + 1, 2, 16: + ; + 4: + begin + if strref[mem[q + 1].int] < 127 then + if strref[mem[q + 1].int] > 1 then + strref[mem[q + 1].int] := strref[mem[q + 1].int] - 1 + else + flushstring(mem[q + 1].int) + end; + 3, 5, 7, 12, 10, 6, 9, + 8, 11, 14, 13, 17, 18, 19: + begin + gpointer := q; + tokenrecycle + end + end + else + confusion(358); + freenode(q, 2) + end + end + end; { flushtokenlist } +{:216} + {226:} + + procedure deletemacref(p: halfword); + begin + if mem[p].hh.lh = (-30000) then + flushtokenlist(p) + else + mem[p].hh.lh := mem[p].hh.lh - 1 + end; {:226} {227:} {625:} + + procedure printcmdmod(c, m: integer); + begin + if c in + [18, 77, 59, 72, 32, 78, 79, 57, + 19, 60, 27, 11, 81, 26, 6, 9, + 70, 73, 13, 46, 63, 14, 15, 69, + 28, 47, 24, 7, 65, 64, 12, 8, + 80, 17, 74, 35, 58, 71, 75, 16, + 4, 61, 56, 3, 1, 2, 33, 34, + 37, 55, 45, 50, 36, 43, 54, 48, + 51, 52, 30, 82, 23, 21, 22, 31, + 62, 41, 10, 53, 44, 49, 5, 40, + 68, 66, 67, 25, 20, 76, 29] then + case c of {212:} + 18: + print(330); + 77: + print(329); + 59: + print(332); + 72: + print(331); + 32: + print(333); + 78: + print(58); + 79: + print(44); + 57: + print(334); + 19: + print(335); + 60: + print(336); + 27: + print(337); + 11: + print(338); + 81: + print(323); + 26: + print(339); + 6: + print(340); + 9: + print(341); + 70: + print(342); + 73: + print(343); + 13: + print(344); + 46: + print(123); + 63: + print(91); + 14: + print(345); + 15: + print(346); + 69: + print(347); + 28: + print(348); + 47: + print(279); + 24: + print(349); + 7: + printchar(92); + 65: + print(125); + 64: + print(93); + 12: + print(350); + 8: + print(351); + 80: + print(59); + 17: + print(352); + 74: + print(353); + 35: + print(354); + 58: + print(355); + 71: + print(356); + 75: + print(357); {:212} {684:} + 16: + if m <= 2 then + if m = 1 then + print(520) + else if m < 1 then + print(324) + else + print(521) + else if m = 53 then + print(522) + else if m = 44 then + print(523) + else + print(524); + 4: + if m <= 1 then + if m = 1 then + print(527) + else + print(325) + else if m = 2242 then + print(525) + else + print(526); {:684} {689:} + 61: + if m in + [1, 2, 3] then + case m of + 1: + print(529); + 2: + printchar(64); + 3: + print(530) + end + else + print(528); {:689} {696:} + 56: + if m >= 2242 then + if m = 2242 then + print(541) + else if m = 2392 then + print(542) + else + print(543) + else if m < 2 then + print(544) + else if m = 2 then + print(545) + else + print(546); {:696} {710:} + 3: + if m = 0 then + print(556) + else + print(482); +{:710} + {741:} + 1, 2: + if m in + [1, 2, 3] then + case m of + 1: + print(583); + 2: + print(322); + 3: + print(584) + end + else + print(585); {:741} {894:} + 33, 34, 37, 55, 45, 50, 36, + 43, 54, 48, 51, 52: + printop(m); {:894} {1014:} + 30: + printtype(m); {:1014} {1019:} + 82: + if m = 0 then + print(776) + else + print(777); +{:1019} + {1025:} + 23: + if m in + [0, 1, 2] then + case m of + 0: + print(143); + 1: + print(144); + 2: + print(145) + end + else + print(783); {:1025} {1028:} + 21: + if m = 0 then + print(784) + else + print(785); {:1028} {1038:} + 22: + if m in + [0, 1, 2, 3] then + case m of + 0: + print(799); + 1: + print(800); + 2: + print(801); + 3: + print(802) + end + else + print(803); {:1038} {1043:} + 31, 62: + begin + if c = 31 then + print(806) + else + print(807); + print(808); + print(hash[m].rh) + end; + 41: + if m = (-30000) then + print(809) + else + print(810); + 10: + print(811); + 53, 44, 49: + begin + printcmdmod(16, c); + print(812); + println; + showtokenlist(mem[mem[m].hh.rh].hh.rh, -30000, 1000, 0) + end; + 5: + print(813); + 40: + print(intname[m]); {:1043} {1053:} + 68: + if m = 1 then + print(820) + else if m = 0 then + print(821) + else + print(822); + 66: + if m = 6 then + print(823) + else + print(824); + 67: + if m = 0 then + print(825) + else + print(826); {:1053} {1080:} + 25: + if m < 1 then + print(856) + else if m = 1 then + print(857) + else + print(858); +{:1080} + {1102:} + 20: + if m in + [0, 1, 2, 3] then + case m of + 0: + print(868); + 1: + print(869); + 2: + print(870); + 3: + print(871) + end + else + print(872); {:1102} {1110:} + 76: + if m = 0 then + print(889) + else + print(890); {:1110} {1180:} + 29: + if m = 16 then + print(913) + else + print(912) + end + else {:1180} + print(468) + end; {:625} + + procedure showmacro(p: halfword; q, l: integer); + label + 10; + var + r: halfword; + begin + p := mem[p].hh.rh; + while mem[p].hh.lh > 7 do begin + r := mem[p].hh.rh; + mem[p].hh.rh := -30000; + showtokenlist(p, -30000, l, 0); + mem[p].hh.rh := r; + p := r; + if l > 0 then + l := l - tally + else + goto 10 + end; + tally := 0; + case mem[p].hh.lh of + 0: + print(368); + 1, 2, 3: + begin + printchar(60); + printcmdmod(56, mem[p].hh.lh); + print(369) + end; + 4: + print(370); + 5: + print(371); + 6: + print(372); + 7: + print(373) + end; + showtokenlist(mem[p].hh.rh, q, l - tally, 0); + 10: + + end; {:227} {232:} + + procedure initbignode(p: halfword); + var + q: halfword; + s: smallnumber; + begin + s := bignodesize[mem[p].hh.b0]; + q := getnode(s); + repeat + s := s - 2; {586:} + begin + mem[q + s].hh.b0 := 19; + serialno := serialno + 64; + mem[(q + s) + 1].int := serialno + end {:586}; + mem[q + s].hh.b1 := (s div 2) + 5; + mem[q + s].hh.rh := -30000 + until s = 0; + mem[q].hh.rh := p; + mem[p + 1].int := q + end; { initbignode } +{:232} + {233:} + + function idtransform: halfword; + var + p, q, r: halfword; + begin + p := getnode(2); + mem[p].hh.b0 := 13; + mem[p].hh.b1 := 11; + mem[p + 1].int := -30000; + initbignode(p); + q := mem[p + 1].int; + r := q + 12; + repeat + r := r - 2; + mem[r].hh.b0 := 16; + mem[r + 1].int := 0 + until r = q; + mem[q + 5].int := 65536; + mem[q + 11].int := 65536; + idtransform := p + end; {:233} {234:} + + procedure newroot(x: halfword); + var + p: halfword; + begin + p := getnode(2); + mem[p].hh.b0 := 0; + mem[p].hh.b1 := 0; + mem[p].hh.rh := x; + eqtb[x].rh := p + end; {:234} +{235:} + + procedure printvariablename(p: halfword); + label + 40, 10; + var + q: halfword; + r: halfword; + begin + while mem[p].hh.b1 >= 5 do begin {237:} + case mem[p].hh.b1 of + 5: + printchar(120); + 6: + printchar(121); + 7: + print(376); + 8: + print(377); + 9: + print(378); + 10: + print(379); + 11: + begin + print(380); + printint(p + 30000); + goto 10 + end + end; + print(381); + p := mem[p - (2 * (mem[p].hh.b1 - 5))].hh.rh + end {:237}; + q := -30000; + while mem[p].hh.b1 > 1 do begin {236:} + if mem[p].hh.b1 = 3 then begin + r := newnumtok(mem[p + 2].int); + repeat + p := mem[p].hh.rh + until mem[p].hh.b1 = 4 + end else if mem[p].hh.b1 = 2 then begin + p := mem[p].hh.rh; + goto 40 + end else begin + if mem[p].hh.b1 <> 4 then + confusion(375); + r := getavail; + mem[r].hh.lh := mem[p + 2].hh.lh + end; + mem[r].hh.rh := q; + q := r; + 40: + p := mem[p + 2].hh.rh + end {:236}; + r := getavail; + mem[r].hh.lh := mem[p].hh.rh; + mem[r].hh.rh := q; + if mem[p].hh.b1 = 1 then + print(374); + showtokenlist(r, -30000, 2147483647, tally); + flushtokenlist(r); + 10: + + end; {:235} +{238:} + + function interesting(p: halfword): boolean; + var + t: smallnumber; + begin + if internal[3] > 0 then + interesting := true + else begin + t := mem[p].hh.b1; + if t >= 5 then + if t <> 11 then + t := mem[mem[p - (2 * (t - 5))].hh.rh].hh.b1; + interesting := t <> 11 + end + end; {:238} {239:} + + function newstructure(p: halfword): halfword; + var + q, r: halfword; + begin + if mem[p].hh.b1 in + [0, 3, 4] then + case mem[p].hh.b1 of + 0: + begin + q := mem[p].hh.rh; + r := getnode(2); + eqtb[q].rh := r + end; + 3: + begin {240:} + q := p; + repeat + q := mem[q].hh.rh + until mem[q].hh.b1 = 4; + q := mem[q + 2].hh.rh; + r := q + 1; + repeat + q := r; + r := mem[r].hh.rh + until r = p; + r := getnode(3); + mem[q].hh.rh := r; + mem[r + 2].int := mem[p + 2].int + end; {:240} + 4: + begin {241:} + q := mem[p + 2].hh.rh; + r := mem[q + 1].hh.lh; + repeat + q := r; + r := mem[r].hh.rh + until r = p; + r := getnode(3); + mem[q].hh.rh := r; + mem[r + 2] := mem[p + 2]; + if mem[p + 2].hh.lh = 0 then begin + q := mem[p + 2].hh.rh + 1; + while mem[q].hh.rh <> p do + q := mem[q].hh.rh; + mem[q].hh.rh := r + end + end + end + else {:241} + confusion(382); + mem[r].hh.rh := mem[p].hh.rh; + mem[r].hh.b0 := 21; + mem[r].hh.b1 := mem[p].hh.b1; + mem[r + 1].hh.lh := p; + mem[p].hh.b1 := 2; + q := getnode(3); + mem[p].hh.rh := q; + mem[r + 1].hh.rh := q; + mem[q + 2].hh.rh := r; + mem[q].hh.b0 := 0; + mem[q].hh.b1 := 4; + mem[q].hh.rh := -29983; + mem[q + 2].hh.lh := 0; + newstructure := r + end; {:239} {242:} + + function findvariable(t: halfword): halfword; + label + 10; + var + p, q, r, s: halfword; + pp, qq, rr, ss: halfword; + n: integer; + saveword: memoryword; + begin + p := mem[t].hh.lh; + t := mem[t].hh.rh; + if (eqtb[p].lh mod 83) <> 41 then begin + findvariable := -30000; + goto 10 + end; + if eqtb[p].rh = (-30000) then + newroot(p); + p := eqtb[p].rh; + pp := p; + while t <> (-30000) do begin {243:} + if mem[pp].hh.b0 <> 21 then begin + if mem[pp].hh.b0 > 21 then begin + findvariable := -30000; + goto 10 + end; + ss := newstructure(pp); + if p = pp then + p := ss; + pp := ss + end; + if mem[p].hh.b0 <> 21 then + p := newstructure(p) {:243}; + if t < himemmin then begin {244:} + n := mem[t + 1].int; + pp := mem[mem[pp + 1].hh.lh].hh.rh; + q := mem[mem[p + 1].hh.lh].hh.rh; + saveword := mem[q + 2]; + mem[q + 2].int := 2147483647; + s := p + 1; + repeat + r := s; + s := mem[s].hh.rh + until n <= mem[s + 2].int; + if n = mem[s + 2].int then + p := s + else begin + p := getnode(3); + mem[r].hh.rh := p; + mem[p].hh.rh := s; + mem[p + 2].int := n; + mem[p].hh.b1 := 3; + mem[p].hh.b0 := 0 + end; + mem[q + 2] := saveword + end else begin {:244} {245:} + n := mem[t].hh.lh; + ss := mem[pp + 1].hh.lh; + repeat + rr := ss; + ss := mem[ss].hh.rh + until n <= mem[ss + 2].hh.lh; + if n < mem[ss + 2].hh.lh then begin + qq := getnode(3); + mem[rr].hh.rh := qq; + mem[qq].hh.rh := ss; + mem[qq + 2].hh.lh := n; + mem[qq].hh.b1 := 4; + mem[qq].hh.b0 := 0; + mem[qq + 2].hh.rh := pp; + ss := qq + end; + if p = pp then begin + p := ss; + pp := ss + end else begin + pp := ss; + s := mem[p + 1].hh.lh; + repeat + r := s; + s := mem[s].hh.rh + until n <= mem[s + 2].hh.lh; + if n = mem[s + 2].hh.lh then + p := s + else begin + q := getnode(3); + mem[r].hh.rh := q; + mem[q].hh.rh := s; + mem[q + 2].hh.lh := n; + mem[q].hh.b1 := 4; + mem[q].hh.b0 := 0; + mem[q + 2].hh.rh := p; + p := q + end + end + end {:245}; + t := mem[t].hh.rh + end; + if mem[pp].hh.b0 >= 21 then + if mem[pp].hh.b0 = 21 then + pp := mem[pp + 1].hh.lh + else begin + findvariable := -30000; + goto 10 + end; + if mem[p].hh.b0 = 21 then + p := mem[p + 1].hh.lh; + if mem[p].hh.b0 = 0 then begin + if mem[pp].hh.b0 = 0 then begin + mem[pp].hh.b0 := 15; + mem[pp + 1].int := -30000 + end; + mem[p].hh.b0 := mem[pp].hh.b0; + mem[p + 1].int := -30000 + end; + findvariable := p; + 10: + + end; {:242} {246:} {257:} + + procedure printpath(h: halfword; s: strnumber; nuline: boolean); + label + 30, 31; + var + p, q: halfword; + begin + printdiagnostic(384, s, nuline); + println; + p := h; + repeat + q := mem[p].hh.rh; + if (p = (-30000)) or (q = (-30000)) then begin + printnl(131); + goto 30 + end; {258:} + printtwo(mem[p + 1].int, mem[p + 2].int); + if mem[p].hh.b1 in + [0, 1, 4, 3, 2] then + case mem[p].hh.b1 of + 0: + begin + if mem[p].hh.b0 = 4 then + print(385); + if (mem[q].hh.b0 <> 0) or (q <> h) then + q := -30000; + goto 31 + end; + 1: + begin {261:} + print(391); + printtwo(mem[p + 5].int, mem[p + 6].int); + print(390); + if mem[q].hh.b0 <> 1 then + print(392) + else + printtwo(mem[q + 3].int, mem[q + 4].int); + goto 31 + end; {:261} + 4: {262:} + if (mem[p].hh.b0 <> 1) and (mem[p].hh.b0 <> 4) then + print(385) {:262}; + 3, 2: + begin {263:} + if mem[p].hh.b0 = 4 then + print(392); + if mem[p].hh.b1 = 3 then begin + print(388); + printscaled(mem[p + 5].int) + end else begin + nsincos(mem[p + 5].int); + printchar(123); + printscaled(ncos); + printchar(44); + printscaled(nsin) + end; + printchar(125) + end + end + else {:263} + print(131); + if mem[q].hh.b0 <= 1 then + print(386) + else if (mem[p + 6].int <> 65536) or (mem[q + 4].int <> 65536) then begin {260:} + print(389); + if mem[p + 6].int < 0 then + print(332); + printscaled(abs(mem[p + 6].int)); + if mem[p + 6].int <> mem[q + 4].int then begin + print(390); + if mem[q + 4].int < 0 then + print(332); + printscaled(abs(mem[q + 4].int)) + end + end {:260}; + 31: {:258} + ; + p := q; + if (p <> h) or (mem[h].hh.b0 <> 0) then begin {259:} + printnl(387); + if mem[p].hh.b0 = 2 then begin + nsincos(mem[p + 3].int); + printchar(123); + printscaled(ncos); + printchar(44); + printscaled(nsin); + printchar(125) + end else if mem[p].hh.b0 = 3 then begin + print(388); + printscaled(mem[p + 3].int); + printchar(125) + end + end {:259} + until p = h; + if mem[h].hh.b0 <> 0 then + print(256); + 30: + enddiagnostic(true) + end; {:257} +{332:} + {333:} + + procedure printweight(q: halfword; xoff: integer); + var + w, m: integer; + d: integer; + begin + d := mem[q].hh.lh + 32768; + w := d mod 8; + m := (d div 8) - mem[curedges + 3].hh.lh; + if fileoffset > (maxprintline - 9) then + printnl(32) + else + printchar(32); + printint(m + xoff); + while w > 4 do begin + printchar(43); + w := w - 1 + end; + while w < 4 do begin + printchar(45); + w := w + 1 + end + end; {:333} + + procedure printedges(s: strnumber; nuline: boolean; xoff, yoff: integer); + var + p, q, r: halfword; + n: integer; + begin + printdiagnostic(399, s, nuline); + p := mem[curedges].hh.lh; + n := mem[curedges + 1].hh.rh - 4096; + while p <> curedges do begin + q := mem[p + 1].hh.lh; + r := mem[p + 1].hh.rh; + if (q > (-29999)) or (r <> 30000) then begin + printnl(400); + printint(n + yoff); + printchar(58); + while q > (-29999) do begin + printweight(q, xoff); + q := mem[q].hh.rh + end; + print(401); + while r <> 30000 do begin + printweight(r, xoff); + r := mem[r].hh.rh + end + end; + p := mem[p].hh.lh; + n := n - 1 + end; + enddiagnostic(true) + end; {:332} {388:} + + {--------------------------------------------------- + procedure unskew(x, y: scaled; octant: smallnumber); + + moved to mf2ps1.p + ---------------------------------------------------} + + procedure printpen(p: halfword; s: strnumber; nuline: boolean); + var + nothingprinted: boolean; + k: 1..8; + h: halfword; + m, n: integer; + w, ww: halfword; + begin + printdiagnostic(436, s, nuline); + nothingprinted := true; + println; + for k := 1 to 8 do begin + octant := octantcode[k]; + h := p + octant; + n := mem[h].hh.lh; + w := mem[h].hh.rh; + if not odd(k) then + w := mem[w].hh.lh; + for m := 1 to n + 1 do begin + if odd(k) then + ww := mem[w].hh.rh + else + ww := mem[w].hh.lh; + if (mem[ww + 1].int <> mem[w + 1].int) or (mem[ww + 2].int <> mem[w + 2].int) then begin {474:} + if nothingprinted then + nothingprinted := false + else + printnl(438); + unskew(mem[ww + 1].int, mem[ww + 2].int, octant); + printtwo(curx, cury) + end {:474}; + w := ww + end + end; + if nothingprinted then begin + w := mem[p + 1].hh.rh; + printtwo(mem[w + 1].int + mem[w + 2].int, mem[w + 2].int) + end; + printnl(437); + enddiagnostic(true) + end; {:473} {589:} + + procedure printdependency(p: halfword; t: smallnumber); + label + 10; + var + v: integer; + pp, q: halfword; + begin + pp := p; + while true do begin + v := abs(mem[p + 1].int); + q := mem[p].hh.lh; + if q = (-30000) then begin + if (v <> 0) or (p = pp) then begin + if mem[p + 1].int > 0 then + if p <> pp then + printchar(43); + printscaled(mem[p + 1].int) + end; + goto 10 + end; +{590:} + if mem[p + 1].int < 0 then + printchar(45) + else if p <> pp then + printchar(43); + if t = 17 then + v := roundfraction(v); + if v <> 65536 then + printscaled(v) {:590}; + if mem[q].hh.b0 <> 19 then + confusion(454); + printvariablename(q); + v := mem[q + 1].int mod 64; + while v > 0 do begin + print(455); + v := v - 2 + end; + p := mem[p].hh.rh + end; + 10: + + end; {:589} {801:} {805:} + + procedure printdp(t: smallnumber; p: halfword; verbosity: smallnumber); + var + q: halfword; + begin + q := mem[p].hh.rh; + if (mem[q].hh.lh = (-30000)) or (verbosity > 0) then + printdependency(p, t) + else + print(628) + end; {:805} {799:} + + function stashcurexp: halfword; + var + p: halfword; + begin + if curtype in + [3, 5, 7, 12, 10, 13, 14, 17, + 18, 19] then + case curtype of + 3, 5, 7, 12, 10, 13, 14, + 17, 18, 19: + p := curexp + end + else + begin + p := getnode(2); + mem[p].hh.b1 := 11; + mem[p].hh.b0 := curtype; + mem[p + 1].int := curexp + end; + curtype := 1; + mem[p].hh.rh := -29999; + stashcurexp := p + end; {:799} {800:} + + procedure unstashcurexp(p: halfword); + begin + curtype := mem[p].hh.b0; + if curtype in + [3, 5, 7, 12, 10, 13, 14, 17, + 18, 19] then + case curtype of + 3, 5, 7, 12, 10, 13, 14, + 17, 18, 19: + curexp := p + end + else + begin + curexp := mem[p + 1].int; + freenode(p, 2) + end + end; {:800} + + procedure printexp(p: halfword; verbosity: smallnumber); + var + restorecurexp: boolean; + t: smallnumber; + v: integer; + q: halfword; + begin + if p <> (-30000) then + restorecurexp := false + else begin + p := stashcurexp; + restorecurexp := true + end; + t := mem[p].hh.b0; + if t < 17 then + v := mem[p + 1].int + else if t < 19 then + v := mem[p + 1].hh.rh; {802:} + if t in + [1, 2, 3, 5, 7, 12, 10, 15, + 4, 6, 8, 9, 11, 13, 14, 16, + 17, 18, 19] then + case t of + 1: + print(194); + 2: + if v = 30 then + print(218) + else + print(219); + 3, 5, 7, 12, 10, 15: + begin {806:} + printtype(t); + if v <> (-30000) then begin + printchar(32); + while (mem[v].hh.b1 = 11) and (v <> p) do + v := mem[v + 1].int; + printvariablename(v) + end + end; {:806} + 4: + begin + printchar(34); + slowprint(v); + printchar(34) + end; + 6, 8, 9, 11: {804:} + if verbosity <= 1 then + printtype(t) + else begin + if selector = 3 then + if internal[13] <= 0 then begin + selector := 1; + printtype(t); + print(626); + selector := 3 + end; + case t of + 6: + printpen(v, 155, false); + 8: + printpath(v, 627, false); + 9: + printpath(v, 155, false); + 11: + begin + curedges := v; + printedges(155, false, 0, 0) + end + end + end {:804}; + 13, 14: + if v = (-30000) then + printtype(t) {803:} + else begin + printchar(40); + q := v + bignodesize[t]; + repeat + if mem[v].hh.b0 = 16 then + printscaled(mem[v + 1].int) + else if mem[v].hh.b0 = 19 then + printvariablename(v) + else + printdp(mem[v].hh.b0, mem[v + 1].hh.rh, verbosity); + v := v + 2; + if v <> q then + printchar(44) + until v = q; + printchar(41) + end {:803}; + 16: + printscaled(v); + 17, 18: + printdp(t, v, verbosity); + 19: + printvariablename(p) + end + else + confusion(625) {:802}; + if restorecurexp then + unstashcurexp(p) + end; {:801} {807:} + + procedure disperr(p: halfword; s: strnumber); + begin + if interaction = 3 then + ; + printnl(629); + printexp(p, 1); + if s <> 155 then begin + printnl(133); + print(s) + end + end; {:807} {594:} + + function pplusfq(p: halfword; f: integer; q: halfword; t, tt: smallnumber): halfword; + label + 30; + var + pp, qq: halfword; + r, s: halfword; + threshold: integer; + v: integer; + begin + if t = 17 then + threshold := 2685 + else + threshold := 8; + r := 29999; + pp := mem[p].hh.lh; + qq := mem[q].hh.lh; + while true do + if pp = qq then + if pp = (-30000) then + goto 30 {595:} + else begin + if tt = 17 then + v := mem[p + 1].int + takefraction(f, mem[q + 1].int) + else + v := mem[p + 1].int + takescaled(f, mem[q + 1].int); + mem[p + 1].int := v; + s := p; + p := mem[p].hh.rh; + if abs(v) < threshold then + freenode(s, 2) + else begin + if abs(v) >= 626349397 then + if watchcoefs then begin + mem[qq].hh.b0 := 0; + fixneeded := true + end; + mem[r].hh.rh := s; + r := s + end; + pp := mem[p].hh.lh; + q := mem[q].hh.rh; + qq := mem[q].hh.lh + end {:595} + else if mem[pp + 1].int < mem[qq + 1].int then begin {596:} + if tt = 17 then + v := takefraction(f, mem[q + 1].int) + else + v := takescaled(f, mem[q + 1].int); + if abs(v) > (threshold div 2) then begin + s := getnode(2); + mem[s].hh.lh := qq; + mem[s + 1].int := v; + if abs(v) >= 626349397 then + if watchcoefs then begin + mem[qq].hh.b0 := 0; + fixneeded := true + end; + mem[r].hh.rh := s; + r := s + end; + q := mem[q].hh.rh; + qq := mem[q].hh.lh + end else begin {:596} + mem[r].hh.rh := p; + r := p; + p := mem[p].hh.rh; + pp := mem[p].hh.lh + end; + 30: + if t = 17 then + mem[p + 1].int := slowadd(mem[p + 1].int, takefraction(mem[q + 1].int, f)) + else + mem[p + 1].int := slowadd(mem[p + 1].int, takescaled(mem[q + 1].int, f)); + mem[r].hh.rh := p; + depfinal := p; + pplusfq := mem[29999].hh.rh + end; {:594} +{600:} + + function poverv(p: halfword; v: scaled; t0, t1: smallnumber): halfword; + var + r, s: halfword; + w: integer; + threshold: integer; + scalingdown: boolean; + begin + if t0 <> t1 then + scalingdown := true + else + scalingdown := false; + if t1 = 17 then + threshold := 1342 + else + threshold := 4; + r := 29999; + while mem[p].hh.lh <> (-30000) do begin + if scalingdown then + if abs(v) < 524288 then + w := makescaled(mem[p + 1].int, v * 4096) + else + w := makescaled(roundfraction(mem[p + 1].int), v) + else + w := makescaled(mem[p + 1].int, v); + if abs(w) <= threshold then begin + s := mem[p].hh.rh; + freenode(p, 2); + p := s + end else begin + if abs(w) >= 626349397 then begin + fixneeded := true; + mem[mem[p].hh.lh].hh.b0 := 0 + end; + mem[r].hh.rh := p; + r := p; + mem[p + 1].int := w; + p := mem[p].hh.rh + end + end; + mem[r].hh.rh := p; + mem[p + 1].int := makescaled(mem[p + 1].int, v); + poverv := mem[29999].hh.rh + end; { poverv } +{:600} + {602:} + + procedure valtoobig(x: scaled); + begin + if internal[40] > 0 then begin + begin + if interaction = 3 then + ; + printnl(133); + print(456) + end; + printscaled(x); + printchar(41); + begin + helpptr := 4; + helpline[3] := 457; + helpline[2] := 458; + helpline[1] := 459; + helpline[0] := 460 + end; + error + end + end; {:602} {603:} + + procedure makeknown(p, q: halfword); + var + t: 17..18; + begin + mem[mem[q].hh.rh + 1].hh.lh := mem[p + 1].hh.lh; + mem[mem[p + 1].hh.lh].hh.rh := mem[q].hh.rh; + t := mem[p].hh.b0; + mem[p].hh.b0 := 16; + mem[p + 1].int := mem[q + 1].int; + freenode(q, 2); + if abs(mem[p + 1].int) >= 268435456 then + valtoobig(mem[p + 1].int); + if internal[2] > 0 then + if interesting(p) then begin + begindiagnostic; + printnl(461); + printvariablename(p); + printchar(61); + printscaled(mem[p + 1].int); + enddiagnostic(false) + end; + if curexp = p then + if curtype = t then begin + curtype := 16; + curexp := mem[p + 1].int; + freenode(p, 2) + end + end; {:603} {604:} + + procedure fixdependencies; + label + 30; + var + p, q, r, s, t: halfword; + x: halfword; + begin + r := mem[-29987].hh.rh; + s := -30000; + while r <> (-29987) do begin + t := r; +{605:} + r := t + 1; + while true do begin + q := mem[r].hh.rh; + x := mem[q].hh.lh; + if x = (-30000) then + goto 30; + if mem[x].hh.b0 <= 1 then begin + if mem[x].hh.b0 < 1 then begin + p := getavail; + mem[p].hh.rh := s; + s := p; + mem[s].hh.lh := x; + mem[x].hh.b0 := 1 + end; + mem[q + 1].int := mem[q + 1].int div 4; + if mem[q + 1].int = 0 then begin + mem[r].hh.rh := mem[q].hh.rh; + freenode(q, 2); + q := r + end + end; + r := q + end; + 30: {:605} + ; + r := mem[q].hh.rh; + if q = mem[t + 1].hh.rh then + makeknown(t, q) + end; + while s <> (-30000) do begin + p := mem[s].hh.rh; + x := mem[s].hh.lh; + begin + mem[s].hh.rh := avail; + avail := s + end {dynused:=dynused-1;}; + s := p; + mem[x].hh.b0 := 19; + mem[x + 1].int := mem[x + 1].int + 2 + end; + fixneeded := false + end; { fixdependencies } +{:604} + {268:} + + procedure tossknotlist(p: halfword); + var + q: halfword; + r: halfword; + begin + q := p; + repeat + r := mem[q].hh.rh; + freenode(q, 7); + q := r + until q = p + end; {:268} {385:} + + procedure tossedges(h: halfword); + var + p, q: halfword; + begin + q := mem[h].hh.rh; + while q <> h do begin + flushlist(mem[q + 1].hh.rh); + if mem[q + 1].hh.lh > (-29999) then + flushlist(mem[q + 1].hh.lh); + p := q; + q := mem[q].hh.rh; + freenode(p, 2) + end; + freenode(h, 6) + end; {:385} {487:} + + procedure tosspen(p: halfword); + var + k: 1..8; + w, ww: halfword; + begin + if p <> (-29997) then begin + for k := 1 to 8 do begin + w := mem[p + k].hh.rh; + repeat + ww := mem[w].hh.rh; + freenode(w, 3); + w := ww + until w = mem[p + k].hh.rh + end; + freenode(p, 10) + end + end; {:487} {620:} + + procedure ringdelete(p: halfword); + var + q: halfword; + begin + q := mem[p + 1].int; + if q <> (-30000) then + if q <> p then begin + while mem[q + 1].int <> p do + q := mem[q + 1].int; + mem[q + 1].int := mem[p + 1].int + end + end; {:620} {809:} + + procedure recyclevalue(p: halfword); + label + 30; + var + t: smallnumber; + v: integer; + vv: integer; + q, r, s, pp: halfword; + begin + t := mem[p].hh.b0; + if t < 17 then + v := mem[p + 1].int; + case t of + 0, 1, 2, 16, 15: + ; + 3, 5, 7, 12, 10: + ringdelete(p); + 4: + begin + if strref[v] < 127 then + if strref[v] > 1 then + strref[v] := strref[v] - 1 + else + flushstring(v) + end; + 6: + if mem[v].hh.lh = (-30000) then + tosspen(v) + else + mem[v].hh.lh := mem[v].hh.lh - 1; + 9, 8: + tossknotlist(v); + 11: + tossedges(v); + 14, 13: {810:} + if v <> (-30000) then begin + q := v + bignodesize[t]; + repeat + q := q - 2; + recyclevalue(q) + until q = v; + freenode(v, bignodesize[t]) + end {:810}; + 17, 18: + begin {811:} + q := mem[p + 1].hh.rh; + while mem[q].hh.lh <> (-30000) do + q := mem[q].hh.rh; + mem[mem[p + 1].hh.lh].hh.rh := mem[q].hh.rh; + mem[mem[q].hh.rh + 1].hh.lh := mem[p + 1].hh.lh; + mem[q].hh.rh := -30000; + flushnodelist(mem[p + 1].hh.rh) + end; {:811} + 19: + begin {812:} + maxc[17] := 0; + maxc[18] := 0; + maxlink[17] := -30000; + maxlink[18] := -30000; + q := mem[-29987].hh.rh; + while q <> (-29987) do begin + s := q + 1; + while true do begin + r := mem[s].hh.rh; + if mem[r].hh.lh = (-30000) then + goto 30; + if mem[r].hh.lh <> p then + s := r + else begin + t := mem[q].hh.b0; + mem[s].hh.rh := mem[r].hh.rh; + mem[r].hh.lh := q; + if abs(mem[r + 1].int) > maxc[t] then begin {814:} + if maxc[t] > 0 then begin + mem[maxptr[t]].hh.rh := maxlink[t]; + maxlink[t] := maxptr[t] + end; + maxc[t] := abs(mem[r + 1].int); + maxptr[t] := r + end else begin {:814} + mem[r].hh.rh := maxlink[t]; + maxlink[t] := r + end + end + end; + 30: + q := mem[r].hh.rh + end; + if (maxc[17] > 0) or (maxc[18] > 0) then begin {815:} + if (maxc[17] >= 268435456) or ((maxc[17] div 4096) >= maxc[18]) then + t := 17 + else + t := 18; {816:} + s := maxptr[t]; + pp := mem[s].hh.lh; + v := mem[s + 1].int; + if t = 17 then + mem[s + 1].int := -268435456 + else + mem[s + 1].int := -65536; + r := mem[pp + 1].hh.rh; + mem[s].hh.rh := r; + while mem[r].hh.lh <> (-30000) do + r := mem[r].hh.rh; + q := mem[r].hh.rh; + mem[r].hh.rh := -30000; + mem[q + 1].hh.lh := mem[pp + 1].hh.lh; + mem[mem[pp + 1].hh.lh].hh.rh := q; + begin + mem[pp].hh.b0 := 19; + serialno := serialno + 64; + mem[pp + 1].int := serialno + end; + if curexp = pp then + if curtype = t then + curtype := 19; + if internal[2] > 0 then {817:} + if interesting(p) then begin + begindiagnostic; + printnl(631); + if v > 0 then + printchar(45); + if t = 17 then + vv := roundfraction(maxc[17]) + else + vv := maxc[18]; + if vv <> 65536 then + printscaled(vv); + printvariablename(p); + while (mem[p + 1].int mod 64) > 0 do begin + print(455); + mem[p + 1].int := mem[p + 1].int - 2 + end; + if t = 17 then + printchar(61) + else + print(632); + printdependency(s, t); + enddiagnostic(false) + end {:817} {:816}; + t := 35 - t; + if maxc[t] > 0 then begin + mem[maxptr[t]].hh.rh := maxlink[t]; + maxlink[t] := maxptr[t] + end; + if t <> 17 then {818:} + for t := 17 to 18 do begin + r := maxlink[t]; + while r <> (-30000) do begin + q := mem[r].hh.lh; + mem[q + 1].hh.rh := pplusfq(mem[q + 1].hh.rh, makefraction(mem[r + 1].int, -v), s, t, 17); + if mem[q + 1].hh.rh = depfinal then + makeknown(q, depfinal); + q := r; + r := mem[r].hh.rh; + freenode(q, 2) + end + end {:818} {819:} + else + for t := 17 to 18 do begin + r := maxlink[t]; + while r <> (-30000) do begin + q := mem[r].hh.lh; + if t = 17 then begin + if curexp = q then + if curtype = 17 then + curtype := 18; + mem[q + 1].hh.rh := poverv(mem[q + 1].hh.rh, 65536, 17, 18); + mem[q].hh.b0 := 18; + mem[r + 1].int := roundfraction(mem[r + 1].int) + end; + mem[q + 1].hh.rh := pplusfq(mem[q + 1].hh.rh, makescaled(mem[r + 1].int, -v), s, 18, 18); + if mem[q + 1].hh.rh = depfinal then + makeknown(q, depfinal); + q := r; + r := mem[r].hh.rh; + freenode(q, 2) + end + end {:819}; + flushnodelist(s); + if fixneeded then + fixdependencies; + begin + if aritherror then + cleararith + end + end {:815} + end; {:812} + 20, 21: + confusion(630); + 22, 23: + deletemacref(mem[p + 1].int) + end; + mem[p].hh.b0 := 0 + end; {:809} {808:} + + procedure flushcurexp(v: scaled); + begin + if curtype in + [3, 5, 7, 12, 10, 13, 14, 17, + 18, 19, 6, 4, 8, 9, 11] then + case curtype of + 3, 5, 7, 12, 10, 13, 14, + 17, 18, 19: + begin + recyclevalue(curexp); + freenode(curexp, 2) + end; + 6: + if mem[curexp].hh.lh = (-30000) then + tosspen(curexp) + else + mem[curexp].hh.lh := mem[curexp].hh.lh - 1; + 4: + begin + if strref[curexp] < 127 then + if strref[curexp] > 1 then + strref[curexp] := strref[curexp] - 1 + else + flushstring(curexp) + end; + 8, 9: + tossknotlist(curexp); + 11: + tossedges(curexp) + end + else + ; + curtype := 16; + curexp := v + end; {:808} {820:} + + procedure flusherror(v: scaled); + begin + error; + flushcurexp(v) + end; + + procedure backerror; + forward; + + procedure getxnext; + forward; + + procedure putgeterror; + begin + backerror; + getxnext + end; { putgeterror } + + procedure putgetflusherror(v: scaled); + begin + putgeterror; + flushcurexp(v) + end; {:820} {247:} + + procedure flushbelowvariable(p: halfword); + var + q, r: halfword; + begin + if mem[p].hh.b0 <> 21 then + recyclevalue(p) + else begin + q := mem[p + 1].hh.rh; + while mem[q].hh.b1 = 3 do begin + flushbelowvariable(q); + r := q; + q := mem[q].hh.rh; + freenode(r, 3) + end; + r := mem[p + 1].hh.lh; + q := mem[r].hh.rh; + recyclevalue(r); + if mem[p].hh.b1 <= 1 then + freenode(r, 2) + else + freenode(r, 3); + repeat + flushbelowvariable(q); + r := q; + q := mem[q].hh.rh; + freenode(r, 3) + until q = (-29983); + mem[p].hh.b0 := 0 + end + end; {:247} + + procedure flushvariable(p, t: halfword; discardsuffixes: boolean); + label + 10; + var + q, r: halfword; + n: halfword; + begin + while t <> (-30000) do begin + if mem[p].hh.b0 <> 21 then + goto 10; + n := mem[t].hh.lh; + t := mem[t].hh.rh; + if n = 0 then begin + r := p + 1; + q := mem[r].hh.rh; + while mem[q].hh.b1 = 3 do begin + flushvariable(q, t, discardsuffixes); + if t = (-30000) then + if mem[q].hh.b0 = 21 then + r := q + else begin + mem[r].hh.rh := mem[q].hh.rh; + freenode(q, 3) + end + else + r := q; + q := mem[r].hh.rh + end + end; + p := mem[p + 1].hh.lh; + repeat + r := p; + p := mem[p].hh.rh + until mem[p + 2].hh.lh >= n; + if mem[p + 2].hh.lh <> n then + goto 10 + end; + if discardsuffixes then + flushbelowvariable(p) + else begin + if mem[p].hh.b0 = 21 then + p := mem[p + 1].hh.lh; + recyclevalue(p) + end; + 10: + + end; {:246} {248:} + + function undtype(p: halfword): smallnumber; + begin + case mem[p].hh.b0 of + 0, 1: + undtype := 0; + 2, 3: + undtype := 3; + 4, 5: + undtype := 5; + 6, 7, 8: + undtype := 7; + 9, 10: + undtype := 10; + 11, 12: + undtype := 12; + 13, 14, 15: + undtype := mem[p].hh.b0; + 16, 17, 18, 19: + undtype := 15 + end + end; {:248} +{249:} + + procedure clearsymbol(p: halfword; saving: boolean); + var + q: halfword; + begin + q := eqtb[p].rh; + if eqtb[p].lh mod 83 in + [10, 53, 44, 49, 41] then + case eqtb[p].lh mod 83 of + 10, 53, 44, 49: + if not saving then + deletemacref(q); + 41: + if q <> (-30000) then + if saving then + mem[q].hh.b1 := 1 + else begin + flushbelowvariable(q); + freenode(q, 2) + end + end + else + ; + eqtb[p] := eqtb[2241] + end; {:249} {252:} + + procedure savevariable(q: halfword); + var + p: halfword; + begin + if saveptr <> (-30000) then begin + p := getnode(2); + mem[p].hh.lh := q; + mem[p].hh.rh := saveptr; + mem[p + 1].hh := eqtb[q]; + saveptr := p + end; + clearsymbol(q, saveptr <> (-30000)) + end; {:252} {253:} + + procedure saveinternal(q: halfword); + var + p: halfword; + begin + if saveptr <> (-30000) then begin + p := getnode(2); + mem[p].hh.lh := 2241 + q; + mem[p].hh.rh := saveptr; + mem[p + 1].int := internal[q]; + saveptr := p + end + end; { saveinternal } +{:253} + {254:} + + procedure unsave; + var + q: halfword; + p: halfword; + begin + while mem[saveptr].hh.lh <> 0 do begin + q := mem[saveptr].hh.lh; + if q > 2241 then begin + if internal[8] > 0 then begin + begindiagnostic; + printnl(383); + print(intname[q - 2241]); + printchar(61); + printscaled(mem[saveptr + 1].int); + printchar(125); + enddiagnostic(false) + end; + internal[q - 2241] := mem[saveptr + 1].int + end else begin + if internal[8] > 0 then begin + begindiagnostic; + printnl(383); + print(hash[q].rh); + printchar(125); + enddiagnostic(false) + end; + clearsymbol(q, false); + eqtb[q] := mem[saveptr + 1].hh; + if (eqtb[q].lh mod 83) = 41 then begin + p := eqtb[q].rh; + if p <> (-30000) then + mem[p].hh.b1 := 0 + end + end; + p := mem[saveptr].hh.rh; + freenode(saveptr, 2); + saveptr := p + end; + p := mem[saveptr].hh.rh; + begin + mem[saveptr].hh.rh := avail; + avail := saveptr + end {dynused:=dynused-1;}; + saveptr := p + end; {:254} {264:} + + function copyknot(p: halfword): halfword; + var + q: halfword; + k: 0..6; + begin + q := getnode(7); + for k := 0 to 6 do + mem[q + k] := mem[p + k]; + copyknot := q + end; {:264} {265:} + + function copypath(p: halfword): halfword; + label + 10; + var + q, pp, qq: halfword; + begin + q := getnode(7); + qq := q; + pp := p; + while true do begin + mem[qq].hh.b0 := mem[pp].hh.b0; + mem[qq].hh.b1 := mem[pp].hh.b1; + mem[qq + 1].int := mem[pp + 1].int; + mem[qq + 2].int := mem[pp + 2].int; + mem[qq + 3].int := mem[pp + 3].int; + mem[qq + 4].int := mem[pp + 4].int; + mem[qq + 5].int := mem[pp + 5].int; + mem[qq + 6].int := mem[pp + 6].int; + if mem[pp].hh.rh = p then begin + mem[qq].hh.rh := q; + copypath := q; + goto 10 + end; + mem[qq].hh.rh := getnode(7); + qq := mem[qq].hh.rh; + pp := mem[pp].hh.rh + end; + 10: + + end; {:265} {266:} + + function htapypoc(p: halfword): halfword; + label + 10; + var + q, pp, qq, rr: halfword; + begin + q := getnode(7); + qq := q; + pp := p; + while true do begin + mem[qq].hh.b1 := mem[pp].hh.b0; + mem[qq].hh.b0 := mem[pp].hh.b1; + mem[qq + 1].int := mem[pp + 1].int; + mem[qq + 2].int := mem[pp + 2].int; + mem[qq + 5].int := mem[pp + 3].int; + mem[qq + 6].int := mem[pp + 4].int; + mem[qq + 3].int := mem[pp + 5].int; + mem[qq + 4].int := mem[pp + 6].int; + if mem[pp].hh.rh = p then begin + mem[q].hh.rh := qq; + pathtail := pp; + htapypoc := q; + goto 10 + end; + rr := getnode(7); + mem[rr].hh.rh := qq; + qq := rr; + pp := mem[pp].hh.rh + end; + 10: + + end; {:266} {269:} {284:} {296:} + + function curlratio(gamma, atension, btension: scaled): fraction; + var + alpha, beta, num, denom, ff: fraction; + begin + alpha := makefraction(65536, atension); + beta := makefraction(65536, btension); + if alpha <= beta then begin + ff := makefraction(alpha, beta); + ff := takefraction(ff, ff); + gamma := takefraction(gamma, ff); + beta := beta div 4096; + denom := (takefraction(gamma, alpha) + 196608) - beta; + num := takefraction(gamma, 805306368 - alpha) + beta + end else begin + ff := makefraction(beta, alpha); + ff := takefraction(ff, ff); + beta := takefraction(beta, ff) div 4096; + denom := (takefraction(gamma, alpha) + (ff div 1365)) - beta; + num := takefraction(gamma, 805306368 - alpha) + beta + end; + if num >= (((denom + denom) + denom) + denom) then + curlratio := 1073741824 + else + curlratio := makefraction(num, denom) + end; {:296} {299:} + + procedure setcontrols(p, q: halfword; k: integer); + var + rr, ss: fraction; + lt, rt: scaled; + sine: fraction; + begin + lt := abs(mem[q + 4].int); + rt := abs(mem[p + 6].int); + rr := velocity(st, ct, sf, cf, rt); + ss := velocity(sf, cf, st, ct, lt); + if (mem[p + 6].int < 0) or (mem[q + 4].int < 0) then {300:} + if ((st >= 0) and (sf >= 0)) or ((st <= 0) and (sf <= 0)) then begin + sine := takefraction(abs(st), cf) + takefraction(abs(sf), ct); + if sine > 0 then begin + sine := takefraction(sine, 268500992); + if mem[p + 6].int < 0 then + if abvscd(abs(sf), 268435456, rr, sine) < 0 then + rr := makefraction(abs(sf), sine); + if mem[q + 4].int < 0 then + if abvscd(abs(st), 268435456, ss, sine) < 0 then + ss := makefraction(abs(st), sine) + end + end {:300}; + mem[p + 5].int := mem[p + 1].int + takefraction(takefraction(deltax[k], ct) - takefraction(deltay[k], st), rr); + mem[p + 6].int := mem[p + 2].int + takefraction(takefraction(deltay[k], ct) + takefraction(deltax[k], st), rr); + mem[q + 3].int := mem[q + 1].int - takefraction(takefraction(deltax[k], cf) + takefraction(deltay[k], sf), ss); + mem[q + 4].int := mem[q + 2].int - takefraction(takefraction(deltay[k], cf) - takefraction(deltax[k], sf), ss); + mem[p].hh.b1 := 1; + mem[q].hh.b0 := 1 + end; { setcontrols } +{:299} + + procedure solvechoices(p, q: halfword; n: halfword); + label + 40, 10; + var + k: 0..pathsize; + r, s, t: halfword; + sine, cosine: fraction; {286:} + aa, bb, cc, ff, acc: fraction; + dd, ee: scaled; + lt, rt: scaled; {:286} + begin + k := 0; + s := p; + while true do begin + t := mem[s].hh.rh; + if k = 0 then {285:} + case mem[s].hh.b1 of + 2: + if mem[t].hh.b0 = 2 then begin {301:} + aa := narg(deltax[0], deltay[0]); + nsincos(mem[p + 5].int - aa); + ct := ncos; + st := nsin; + nsincos(mem[q + 3].int - aa); + cf := ncos; + sf := -nsin; + setcontrols(p, q, 0); + goto 10 + end else begin {:301} {293:} + vv[0] := mem[s + 5].int - narg(deltax[0], deltay[0]); + if abs(vv[0]) > 188743680 then + if vv[0] > 0 then + vv[0] := vv[0] - 377487360 + else + vv[0] := vv[0] + 377487360; + uu[0] := 0; + ww[0] := 0 + end {:293}; + 3: + if mem[t].hh.b0 = 3 then begin {302:} + mem[p].hh.b1 := 1; + mem[q].hh.b0 := 1; + lt := abs(mem[q + 4].int); + rt := abs(mem[p + 6].int); + if rt = 65536 then begin + if deltax[0] >= 0 then + mem[p + 5].int := mem[p + 1].int + ((deltax[0] + 1) div 3) + else + mem[p + 5].int := mem[p + 1].int + ((deltax[0] - 1) div 3); + if deltay[0] >= 0 then + mem[p + 6].int := mem[p + 2].int + ((deltay[0] + 1) div 3) + else + mem[p + 6].int := mem[p + 2].int + ((deltay[0] - 1) div 3) + end else begin + ff := makefraction(65536, 3 * rt); + mem[p + 5].int := mem[p + 1].int + takefraction(deltax[0], ff); + mem[p + 6].int := mem[p + 2].int + takefraction(deltay[0], ff) + end; + if lt = 65536 then begin + if deltax[0] >= 0 then + mem[q + 3].int := mem[q + 1].int - ((deltax[0] + 1) div 3) + else + mem[q + 3].int := mem[q + 1].int - ((deltax[0] - 1) div 3); + if deltay[0] >= 0 then + mem[q + 4].int := mem[q + 2].int - ((deltay[0] + 1) div 3) + else + mem[q + 4].int := mem[q + 2].int - ((deltay[0] - 1) div 3) + end else begin + ff := makefraction(65536, 3 * lt); + mem[q + 3].int := mem[q + 1].int - takefraction(deltax[0], ff); + mem[q + 4].int := mem[q + 2].int - takefraction(deltay[0], ff) + end; + goto 10 + end else begin {:302} {294:} + cc := mem[s + 5].int; + lt := abs(mem[t + 4].int); + rt := abs(mem[s + 6].int); + if (rt = 65536) and (lt = 65536) then + uu[0] := makefraction((cc + cc) + 65536, cc + 131072) + else + uu[0] := curlratio(cc, rt, lt); + vv[0] := -takefraction(psi[1], uu[0]); + ww[0] := 0 + end {:294}; + 4: + begin + uu[0] := 0; + vv[0] := 0; + ww[0] := 268435456 + end + end {:285} + else + case mem[s].hh.b0 of + 5, 4: + begin {287:} {288:} + if abs(mem[r + 6].int) = 65536 then begin + aa := 134217728; + dd := 2 * delta[k] + end else begin + aa := makefraction(65536, (3 * abs(mem[r + 6].int)) - 65536); + dd := takefraction(delta[k], 805306368 - makefraction(65536, abs(mem[r + 6].int))) + end; + if abs(mem[t + 4].int) = 65536 then begin + bb := 134217728; + ee := 2 * delta[k - 1] + end else begin + bb := makefraction(65536, (3 * abs(mem[t + 4].int)) - 65536); + ee := takefraction(delta[k - 1], 805306368 - makefraction(65536, abs(mem[t + 4].int))) + end; + cc := 268435456 - takefraction(uu[k - 1], aa) {:288}; {289:} + dd := takefraction(dd, cc); + lt := abs(mem[s + 4].int); + rt := abs(mem[s + 6].int); + if lt <> rt then + if lt < rt then begin + ff := makefraction(lt, rt); + ff := takefraction(ff, ff); + dd := takefraction(dd, ff) + end else begin + ff := makefraction(rt, lt); + ff := takefraction(ff, ff); + ee := takefraction(ee, ff) + end; + ff := makefraction(ee, ee + dd) {:289}; + uu[k] := takefraction(ff, bb); {290:} + acc := -takefraction(psi[k + 1], uu[k]); + if mem[r].hh.b1 = 3 then begin + ww[k] := 0; + vv[k] := acc - takefraction(psi[1], 268435456 - ff) + end else begin + ff := makefraction(268435456 - ff, cc); + acc := acc - takefraction(psi[k], ff); + ff := takefraction(ff, aa); + vv[k] := acc - takefraction(vv[k - 1], ff); + if ww[k - 1] = 0 then + ww[k] := 0 + else + ww[k] := -takefraction(ww[k - 1], ff) + end {:290}; + if mem[s].hh.b0 = 5 then begin {291:} + aa := 0; + bb := 268435456; + repeat + k := k - 1; + if k = 0 then + k := n; + aa := vv[k] - takefraction(aa, uu[k]); + bb := ww[k] - takefraction(bb, uu[k]) + until k = n; + aa := makefraction(aa, 268435456 - bb); + theta[n] := aa; + vv[0] := aa; + for k := 1 to n - 1 do + vv[k] := vv[k] + takefraction(aa, ww[k]); + goto 40 + end {:291} + end; {:287} + 3: + begin {295:} + cc := mem[s + 3].int; + lt := abs(mem[s + 4].int); + rt := abs(mem[r + 6].int); + if (rt = 65536) and (lt = 65536) then + ff := makefraction((cc + cc) + 65536, cc + 131072) + else + ff := curlratio(cc, lt, rt); + theta[n] := -makefraction(takefraction(vv[n - 1], ff), 268435456 - takefraction(ff, uu[n - 1])); + goto 40 + end; {:295} + 2: + begin {292:} + theta[n] := mem[s + 3].int - narg(deltax[n - 1], deltay[n - 1]); + if abs(theta[n]) > 188743680 then + if theta[n] > 0 then + theta[n] := theta[n] - 377487360 + else + theta[n] := theta[n] + 377487360; + goto 40 + end + end {:292}; + r := s; + s := t; + k := k + 1 + end; + 40: {297:} + for k := n - 1 downto 0 do + theta[k] := vv[k] - takefraction(theta[k + 1], uu[k]); + s := p; + k := 0; + repeat + t := mem[s].hh.rh; + nsincos(theta[k]); + st := nsin; + ct := ncos; + nsincos((-psi[k + 1]) - theta[k + 1]); + sf := nsin; + cf := ncos; + setcontrols(s, t, k); + k := k + 1; + s := t + until k = n {:297}; + 10: + + end; {:284} + + procedure makechoices(knots: halfword); + label + 30; + var + h: halfword; + p, q: halfword; {280:} + k, n: 0..pathsize; + r, s, t: halfword; + delx, dely: scaled; + sine, cosine: fraction; {:280} + begin + begin + if aritherror then + cleararith + end; + if internal[4] > 0 then + printpath(knots, 393, true); {271:} + p := knots; + repeat + q := mem[p].hh.rh; + if mem[p + 1].int = mem[q + 1].int then + if mem[p + 2].int = mem[q + 2].int then + if mem[p].hh.b1 > 1 then begin + mem[p].hh.b1 := 1; + if mem[p].hh.b0 = 4 then begin + mem[p].hh.b0 := 3; + mem[p + 3].int := 65536 + end; + mem[q].hh.b0 := 1; + if mem[q].hh.b1 = 4 then begin + mem[q].hh.b1 := 3; + mem[q + 5].int := 65536 + end; + mem[p + 5].int := mem[p + 1].int; + mem[q + 3].int := mem[p + 1].int; + mem[p + 6].int := mem[p + 2].int; + mem[q + 4].int := mem[p + 2].int + end; + p := q + until p = knots {:271}; {272:} + h := knots; + while true do begin + if mem[h].hh.b0 <> 4 then + goto 30; + if mem[h].hh.b1 <> 4 then + goto 30; + h := mem[h].hh.rh; + if h = knots then begin + mem[h].hh.b0 := 5; + goto 30 + end + end; + 30: {:272} + ; + p := h; {273:} + repeat + q := mem[p].hh.rh; + if mem[p].hh.b1 >= 2 then begin + while (mem[q].hh.b0 = 4) and (mem[q].hh.b1 = 4) do + q := mem[q].hh.rh; {278:} {281:} + k := 0; + s := p; + n := pathsize; + repeat + t := mem[s].hh.rh; + deltax[k] := mem[t + 1].int - mem[s + 1].int; + deltay[k] := mem[t + 2].int - mem[s + 2].int; + delta[k] := pythadd(deltax[k], deltay[k]); + if k > 0 then begin + sine := makefraction(deltay[k - 1], delta[k - 1]); + cosine := makefraction(deltax[k - 1], delta[k - 1]); + psi[k] := narg(takefraction(deltax[k], cosine) + takefraction(deltay[k], sine), takefraction(deltay[k], cosine) - takefraction(deltax[k], sine)) + end; + k := k + 1; + s := t; + if k = pathsize then + overflow(398, pathsize); + if s = q then + n := k + until (k >= n) and (mem[s].hh.b0 <> 5); + if k = n then + psi[n] := 0 + else + psi[k] := psi[1] {:281}; {282:} + if mem[q].hh.b0 = 4 then begin + delx := mem[q + 5].int - mem[q + 1].int; + dely := mem[q + 6].int - mem[q + 2].int; + if (delx = 0) and (dely = 0) then begin + mem[q].hh.b0 := 3; + mem[q + 3].int := 65536 + end else begin + mem[q].hh.b0 := 2; + mem[q + 3].int := narg(delx, dely) + end + end; + if (mem[p].hh.b1 = 4) and (mem[p].hh.b0 = 1) then begin + delx := mem[p + 1].int - mem[p + 3].int; + dely := mem[p + 2].int - mem[p + 4].int; + if (delx = 0) and (dely = 0) then begin + mem[p].hh.b1 := 3; + mem[p + 5].int := 65536 + end else begin + mem[p].hh.b1 := 2; + mem[p + 5].int := narg(delx, dely) + end + end {:282}; + solvechoices(p, q, n) {:278} + end; + p := q {:273} + until p = h; + if internal[4] > 0 then + printpath(knots, 394, true); + if aritherror then begin {270:} + begin + if interaction = 3 then + ; + printnl(133); + print(395) + end; + begin + helpptr := 2; + helpline[1] := 396; + helpline[0] := 397 + end; + putgeterror; + aritherror := false + end {:270} + end; {:269} {311:} + + {------------------------------------------------------------------- + procedure makemoves(xx0, xx1, xx2, xx3, yy0, yy1, yy2, yy3: scaled; xicorr, etacorr: smallnumber); + + moved to mf2ps3.p + -------------------------------------------------------------------} + + procedure smoothmoves(b, t: integer); + var + k: 1..movesize; + a, aa, aaa: integer; + begin + if (t - b) >= 3 then begin + k := b + 2; + aa := move[k - 1]; + aaa := move[k - 2]; + repeat + a := move[k]; + if abs(a - aa) > 1 then {322:} + if a > aa then begin + if aaa >= aa then + if a >= move[k + 1] then begin + move[k - 1] := move[k - 1] + 1; + move[k] := a - 1 + end + end else begin + if aaa <= aa then + if a <= move[k + 1] then begin + move[k - 1] := move[k - 1] - 1; + move[k] := a + 1 + end + end {:322}; + k := k + 1; + aaa := aa; + aa := a + until k = t + end + end; {:321} {326:} + + procedure initedges(h: halfword); + begin + mem[h].hh.lh := h; + mem[h].hh.rh := h; + mem[h + 1].hh.lh := 8191; + mem[h + 1].hh.rh := 1; + mem[h + 2].hh.lh := 8191; + mem[h + 2].hh.rh := 1; + mem[h + 3].hh.lh := 4096; + mem[h + 3].hh.rh := 0; + mem[h + 4].int := 0; + mem[h + 5].hh.rh := h; + mem[h + 5].hh.lh := 0 + end; {:326} {328:} + + procedure fixoffset; + var + p, q: halfword; + delta: integer; + begin + delta := 8 * (mem[curedges + 3].hh.lh - 4096); + mem[curedges + 3].hh.lh := 4096; + q := mem[curedges].hh.rh; + while q <> curedges do begin + p := mem[q + 1].hh.rh; + while p <> 30000 do begin + mem[p].hh.lh := mem[p].hh.lh - delta; + p := mem[p].hh.rh + end; + p := mem[q + 1].hh.lh; + while p > (-29999) do begin + mem[p].hh.lh := mem[p].hh.lh - delta; + p := mem[p].hh.rh + end; + q := mem[q].hh.rh + end + end; {:328} {329:} + + procedure edgeprep(ml, mr, nl, nr: integer); + var + delta: halfword; + p, q: halfword; + begin + ml := ml + 4096; + mr := mr + 4096; + nl := nl + 4096; + nr := nr + 4095; + if ml < mem[curedges + 2].hh.lh then + mem[curedges + 2].hh.lh := ml; + if mr > mem[curedges + 2].hh.rh then + mem[curedges + 2].hh.rh := mr; + if (not (abs((mem[curedges + 2].hh.lh + mem[curedges + 3].hh.lh) - 8192) < 4096)) or (not (abs((mem[curedges + 2].hh.rh + mem[curedges + 3].hh.lh) - 8192) < 4096)) then + fixoffset; + if mem[curedges].hh.rh = curedges then begin + mem[curedges + 1].hh.lh := nr + 1; + mem[curedges + 1].hh.rh := nr + end; + if nl < mem[curedges + 1].hh.lh then begin {330:} + delta := mem[curedges + 1].hh.lh - nl; + mem[curedges + 1].hh.lh := nl; + p := mem[curedges].hh.rh; + repeat + q := getnode(2); + mem[q + 1].hh.rh := 30000; + mem[q + 1].hh.lh := -29999; + mem[p].hh.lh := q; + mem[q].hh.rh := p; + p := q; + delta := delta - 1 + until delta = 0; + mem[p].hh.lh := curedges; + mem[curedges].hh.rh := p; + if mem[curedges + 5].hh.rh = curedges then + mem[curedges + 5].hh.lh := nl - 1 + end {:330}; + if nr > mem[curedges + 1].hh.rh then begin {331:} + delta := nr - mem[curedges + 1].hh.rh; + mem[curedges + 1].hh.rh := nr; + p := mem[curedges].hh.lh; + repeat + q := getnode(2); + mem[q + 1].hh.rh := 30000; + mem[q + 1].hh.lh := -29999; + mem[p].hh.rh := q; + mem[q].hh.lh := p; + p := q; + delta := delta - 1 + until delta = 0; + mem[p].hh.rh := curedges; + mem[curedges].hh.lh := p; + if mem[curedges + 5].hh.rh = curedges then + mem[curedges + 5].hh.lh := nr + 1 + end {:331} + end; {:329} {334:} + + function copyedges(h: halfword): halfword; + var + p, r: halfword; + hh, pp, qq, rr, ss: halfword; + begin + hh := getnode(6); + mem[hh + 1] := mem[h + 1]; + mem[hh + 2] := mem[h + 2]; + mem[hh + 3] := mem[h + 3]; + mem[hh + 4] := mem[h + 4]; + mem[hh + 5].hh.lh := mem[hh + 1].hh.rh + 1; + mem[hh + 5].hh.rh := hh; + p := mem[h].hh.rh; + qq := hh; + while p <> h do begin + pp := getnode(2); + mem[qq].hh.rh := pp; + mem[pp].hh.lh := qq; +{335:} + r := mem[p + 1].hh.rh; + rr := pp + 1; + while r <> 30000 do begin + ss := getavail; + mem[rr].hh.rh := ss; + rr := ss; + mem[rr].hh.lh := mem[r].hh.lh; + r := mem[r].hh.rh + end; + mem[rr].hh.rh := 30000; + r := mem[p + 1].hh.lh; + rr := 29999; + while r > (-29999) do begin + ss := getavail; + mem[rr].hh.rh := ss; + rr := ss; + mem[rr].hh.lh := mem[r].hh.lh; + r := mem[r].hh.rh + end; + mem[rr].hh.rh := r; + mem[pp + 1].hh.lh := mem[29999].hh.rh {:335}; + p := mem[p].hh.rh; + qq := pp + end; + mem[qq].hh.rh := hh; + mem[hh].hh.lh := qq; + copyedges := hh + end; {:334} {336:} + + procedure yreflectedges; + var + p, q, r: halfword; + begin + p := mem[curedges + 1].hh.lh; + mem[curedges + 1].hh.lh := 8191 - mem[curedges + 1].hh.rh; + mem[curedges + 1].hh.rh := 8191 - p; + mem[curedges + 5].hh.lh := 8191 - mem[curedges + 5].hh.lh; + p := mem[curedges].hh.rh; + q := curedges; + repeat + r := mem[p].hh.rh; + mem[p].hh.rh := q; + mem[q].hh.lh := p; + q := p; + p := r + until q = curedges; + mem[curedges + 4].int := 0 + end; {:336} {337:} + + procedure xreflectedges; + var + p, q, r, s: halfword; + m: integer; + begin + p := mem[curedges + 2].hh.lh; + mem[curedges + 2].hh.lh := 8192 - mem[curedges + 2].hh.rh; + mem[curedges + 2].hh.rh := 8192 - p; + m := ((4096 + mem[curedges + 3].hh.lh) * 8) - 65528; + mem[curedges + 3].hh.lh := 4096; + p := mem[curedges].hh.rh; {339:} + repeat + q := mem[p + 1].hh.rh; + r := 30000; + while q <> 30000 do begin + s := mem[q].hh.rh; + mem[q].hh.rh := r; + r := q; + mem[r].hh.lh := m - mem[q].hh.lh; + q := s + end; + mem[p + 1].hh.rh := r {:339}; {338:} + q := mem[p + 1].hh.lh; + while q > (-29999) do begin + mem[q].hh.lh := m - mem[q].hh.lh; + q := mem[q].hh.rh + end {:338}; + p := mem[p].hh.rh + until p = curedges; + mem[curedges + 4].int := 0 + end; { xreflectedges } +{:337} + {340:} + + procedure yscaleedges(s: integer); + var + p, q, pp, r, rr, ss: halfword; + t: integer; + begin + if ((s * (mem[curedges + 1].hh.rh - 4095)) >= 4096) or ((s * (mem[curedges + 1].hh.lh - 4096)) <= (-4096)) then begin + begin + if interaction = 3 then + ; + printnl(133); + print(402) + end; + begin + helpptr := 3; + helpline[2] := 403; + helpline[1] := 404; + helpline[0] := 405 + end; + putgeterror + end else begin + mem[curedges + 1].hh.rh := (s * (mem[curedges + 1].hh.rh - 4095)) + 4095; + mem[curedges + 1].hh.lh := (s * (mem[curedges + 1].hh.lh - 4096)) + 4096; {341:} + p := curedges; + repeat + q := p; + p := mem[p].hh.rh; + for t := 2 to s do begin + pp := getnode(2); + mem[q].hh.rh := pp; + mem[p].hh.lh := pp; + mem[pp].hh.rh := p; + mem[pp].hh.lh := q; + q := pp; {335:} + r := mem[p + 1].hh.rh; + rr := pp + 1; + while r <> 30000 do begin + ss := getavail; + mem[rr].hh.rh := ss; + rr := ss; + mem[rr].hh.lh := mem[r].hh.lh; + r := mem[r].hh.rh + end; + mem[rr].hh.rh := 30000; + r := mem[p + 1].hh.lh; + rr := 29999; + while r > (-29999) do begin + ss := getavail; + mem[rr].hh.rh := ss; + rr := ss; + mem[rr].hh.lh := mem[r].hh.lh; + r := mem[r].hh.rh + end; + mem[rr].hh.rh := r; + mem[pp + 1].hh.lh := mem[29999].hh.rh {:335} + end + until mem[p].hh.rh = curedges {:341}; + mem[curedges + 4].int := 0 + end + end; {:340} +{342:} + + procedure xscaleedges(s: integer); + var + p, q: halfword; + t: 0..65535; + w: 0..7; + delta: integer; + begin + if ((s * (mem[curedges + 2].hh.rh - 4096)) >= 4096) or ((s * (mem[curedges + 2].hh.lh - 4096)) <= (-4096)) then begin + begin + if interaction = 3 then + ; + printnl(133); + print(402) + end; + begin + helpptr := 3; + helpline[2] := 406; + helpline[1] := 404; + helpline[0] := 405 + end; + putgeterror + end else if (mem[curedges + 2].hh.rh <> 4096) or (mem[curedges + 2].hh.lh <> 4096) then begin + mem[curedges + 2].hh.rh := (s * (mem[curedges + 2].hh.rh - 4096)) + 4096; + mem[curedges + 2].hh.lh := (s * (mem[curedges + 2].hh.lh - 4096)) + 4096; + delta := (8 * (4096 - (s * mem[curedges + 3].hh.lh))) - 32768; + mem[curedges + 3].hh.lh := 4096; {343:} + q := mem[curedges].hh.rh; + repeat + p := mem[q + 1].hh.rh; + while p <> 30000 do begin + t := mem[p].hh.lh + 32768; + w := t mod 8; + mem[p].hh.lh := (((t - w) * s) + w) + delta; + p := mem[p].hh.rh + end; + p := mem[q + 1].hh.lh; + while p > (-29999) do begin + t := mem[p].hh.lh + 32768; + w := t mod 8; + mem[p].hh.lh := (((t - w) * s) + w) + delta; + p := mem[p].hh.rh + end; + q := mem[q].hh.rh + until q = curedges {:343}; + mem[curedges + 4].int := 0 + end + end; { xscaleedges } +{:342} + {344:} + + procedure negateedges(h: halfword); + label + 30; + var + p, q, r, s, t, u: halfword; + begin + p := mem[h].hh.rh; + while p <> h do begin + q := mem[p + 1].hh.lh; + while q > (-29999) do begin + mem[q].hh.lh := (8 - (2 * ((mem[q].hh.lh + 32768) mod 8))) + mem[q].hh.lh; + q := mem[q].hh.rh + end; + q := mem[p + 1].hh.rh; + if q <> 30000 then begin + repeat + mem[q].hh.lh := (8 - (2 * ((mem[q].hh.lh + 32768) mod 8))) + mem[q].hh.lh; + q := mem[q].hh.rh + until q = 30000; {345:} + u := p + 1; + q := mem[u].hh.rh; + r := q; + s := mem[r].hh.rh; + while true do + if mem[s].hh.lh > mem[r].hh.lh then begin + mem[u].hh.rh := q; + if s = 30000 then + goto 30; + u := r; + q := s; + r := q; + s := mem[r].hh.rh + end else begin + t := s; + s := mem[t].hh.rh; + mem[t].hh.rh := q; + q := t + end; + 30: + mem[r].hh.rh := 30000 {:345} + end; + p := mem[p].hh.rh + end; + mem[h + 4].int := 0 + end; {:344} {346:} + + procedure sortedges(h: halfword); + label + 30; + var + k: halfword; + p, q, r, s: halfword; + begin + r := mem[h + 1].hh.lh; + mem[h + 1].hh.lh := -30000; + p := mem[r].hh.rh; + mem[r].hh.rh := 30000; + mem[29999].hh.rh := r; + while p > (-29999) do begin + k := mem[p].hh.lh; + q := 29999; + repeat + r := q; + q := mem[r].hh.rh + until k <= mem[q].hh.lh; + mem[r].hh.rh := p; + r := mem[p].hh.rh; + mem[p].hh.rh := q; + p := r + end; {347:} + begin + r := h + 1; + q := mem[r].hh.rh; + p := mem[29999].hh.rh; + while true do begin + k := mem[p].hh.lh; + while k > mem[q].hh.lh do begin + r := q; + q := mem[r].hh.rh + end; + mem[r].hh.rh := p; + s := mem[p].hh.rh; + mem[p].hh.rh := q; + if s = 30000 then + goto 30; + r := p; + p := s + end; + 30: {:347} + + end + end; {:346} {348:} + + procedure culledges(wlo, whi, wout, win: integer); + label + 30; + var + p, q, r, s: halfword; + w: integer; + d: integer; + m: integer; + mm: integer; + ww: integer; + prevw: integer; + n, minn, maxn: halfword; + mind, maxd: halfword; + begin + mind := 32767; + maxd := -32768; + minn := 32767; + maxn := -32768; + p := mem[curedges].hh.rh; + n := mem[curedges + 1].hh.lh; + while p <> curedges do begin + if mem[p + 1].hh.lh > (-29999) then + sortedges(p); + if mem[p + 1].hh.rh <> 30000 then begin {349:} + r := 29999; + q := mem[p + 1].hh.rh; + ww := 0; + m := 1000000; + prevw := 0; + while true do begin + if q = 30000 then + mm := 1000000 + else begin + d := mem[q].hh.lh + 32768; + mm := d div 8; + ww := (ww + (d mod 8)) - 4 + end; + if mm > m then begin {350:} + if w <> prevw then begin + s := getavail; + mem[r].hh.rh := s; + mem[s].hh.lh := (((8 * m) - 32764) + w) - prevw; + r := s; + prevw := w + end {:350}; + if q = 30000 then + goto 30 + end; + m := mm; + if ww >= wlo then + if ww <= whi then + w := win + else + w := wout + else + w := wout; + s := mem[q].hh.rh; + begin + mem[q].hh.rh := avail; + avail := q + end {dynused:=dynused-1;}; + q := s + end; + 30: + mem[r].hh.rh := 30000; + mem[p + 1].hh.rh := mem[29999].hh.rh; + if r <> 29999 then begin {351:} + if minn = 32767 then + minn := n; + maxn := n; + if mind > mem[mem[29999].hh.rh].hh.lh then + mind := mem[mem[29999].hh.rh].hh.lh; + if maxd < mem[r].hh.lh then + maxd := mem[r].hh.lh + end {:351} + end {:349}; + p := mem[p].hh.rh; + n := n + 1 + end; {352:} + if minn > maxn then begin {353:} + p := mem[curedges].hh.rh; + while p <> curedges do begin + q := mem[p].hh.rh; + freenode(p, 2); + p := q + end; + initedges(curedges) + end else begin {:353} + n := mem[curedges + 1].hh.lh; + mem[curedges + 1].hh.lh := minn; + while minn > n do begin + p := mem[curedges].hh.rh; + mem[curedges].hh.rh := mem[p].hh.rh; + mem[mem[p].hh.rh].hh.lh := curedges; + freenode(p, 2); + n := n + 1 + end; + n := mem[curedges + 1].hh.rh; + mem[curedges + 1].hh.rh := maxn; + mem[curedges + 5].hh.lh := maxn + 1; + mem[curedges + 5].hh.rh := curedges; + while maxn < n do begin + p := mem[curedges].hh.lh; + mem[curedges].hh.lh := mem[p].hh.lh; + mem[mem[p].hh.lh].hh.rh := curedges; + freenode(p, 2); + n := n - 1 + end; + mem[curedges + 2].hh.lh := (((mind + 32768) div 8) - mem[curedges + 3].hh.lh) + 4096; + mem[curedges + 2].hh.rh := (((maxd + 32768) div 8) - mem[curedges + 3].hh.lh) + 4096 + end {:352}; + mem[curedges + 4].int := 0 + end; {:348} {354:} + + procedure xyswapedges; + label + 30; + var + mmagic, nmagic: integer; + p, q, r, s: halfword; {357:} + mspread: integer; + j, jj: 0..movesize; + m, mm: integer; + pd, rd: integer; + pm, rm: integer; + w: integer; + ww: integer; + dw: integer; {:357} {363:} + extras: integer; + xw: -3..3; + k: integer; {:363} {356:} + begin + mspread := mem[curedges + 2].hh.rh - mem[curedges + 2].hh.lh; + if mspread > movesize then + overflow(407, movesize); + for j := 0 to mspread do + move[j] := 30000 {:356}; {355:} + p := getnode(2); + mem[p + 1].hh.rh := 30000; + mem[p + 1].hh.lh := -30000; + mem[p].hh.lh := curedges; + mem[mem[curedges].hh.rh].hh.lh := p; + p := getnode(2); + mem[p + 1].hh.rh := 30000; + mem[p].hh.lh := mem[curedges].hh.lh; {:355} {365:} + mmagic := (mem[curedges + 2].hh.lh + mem[curedges + 3].hh.lh) - 4096; + nmagic := (8 * mem[curedges + 1].hh.rh) - 32756 {:365}; + repeat + q := mem[p].hh.lh; + if mem[q + 1].hh.lh > (-29999) then + sortedges(q); {358:} + r := mem[p + 1].hh.rh; + freenode(p, 2); + p := r; + pd := mem[p].hh.lh + 32768; + pm := pd div 8; + r := mem[q + 1].hh.rh; + rd := mem[r].hh.lh + 32768; + rm := rd div 8; + w := 0; + while true do begin + if pm < rm then + mm := pm + else + mm := rm; + if w <> 0 then {362:} + if m <> mm then begin + if (mm - mmagic) >= movesize then + confusion(377); + extras := (abs(w) - 1) div 3; + if extras > 0 then begin + if w > 0 then + xw := +3 + else + xw := -3; + ww := w - (extras * xw) + end else + ww := w; + repeat + j := m - mmagic; + for k := 1 to extras do begin + s := getavail; + mem[s].hh.lh := nmagic + xw; + mem[s].hh.rh := move[j]; + move[j] := s + end; + s := getavail; + mem[s].hh.lh := nmagic + ww; + mem[s].hh.rh := move[j]; + move[j] := s; + m := m + 1 + until m = mm + end {:362}; + if pd < rd then begin + dw := (pd mod 8) - 4; {360:} + s := mem[p].hh.rh; + begin + mem[p].hh.rh := avail; + avail := p + end {dynused:=dynused-1;}; + p := s; + pd := mem[p].hh.lh + 32768; + pm := pd div 8 {:360} + end else begin + if r = 30000 then + goto 30; + dw := -((rd mod 8) - 4); {359:} + r := mem[r].hh.rh; + rd := mem[r].hh.lh + 32768; + rm := rd div 8 {:359} + end; + m := mm; + w := w + dw + end; + 30: {:358} + ; + p := q; + nmagic := nmagic - 8 + until mem[p].hh.lh = curedges; + freenode(p, 2); {364:} + move[mspread] := 0; + j := 0; + while move[j] = 30000 do + j := j + 1; + if j = mspread then + initedges(curedges) + else begin + mm := mem[curedges + 2].hh.lh; + mem[curedges + 2].hh.lh := mem[curedges + 1].hh.lh; + mem[curedges + 2].hh.rh := mem[curedges + 1].hh.rh + 1; + mem[curedges + 3].hh.lh := 4096; + jj := mspread - 1; + while move[jj] = 30000 do + jj := jj - 1; + mem[curedges + 1].hh.lh := j + mm; + mem[curedges + 1].hh.rh := jj + mm; + q := curedges; + repeat + p := getnode(2); + mem[q].hh.rh := p; + mem[p].hh.lh := q; + mem[p + 1].hh.rh := move[j]; + mem[p + 1].hh.lh := -30000; + j := j + 1; + q := p + until j > jj; + mem[q].hh.rh := curedges; + mem[curedges].hh.lh := q; + mem[curedges + 5].hh.lh := mem[curedges + 1].hh.rh + 1; + mem[curedges + 5].hh.rh := curedges; + mem[curedges + 4].int := 0 + end + end; {:364} +{:354} + {366:} + + procedure mergeedges(h: halfword); + label + 30; + var + p, q, r, pp, qq, rr: halfword; + n: integer; + k: halfword; + delta: integer; + begin + if mem[h].hh.rh <> h then begin + if (((mem[h + 2].hh.lh < mem[curedges + 2].hh.lh) or (mem[h + 2].hh.rh > mem[curedges + 2].hh.rh)) or (mem[h + 1].hh.lh < mem[curedges + 1].hh.lh)) or (mem[h + 1].hh.rh > mem[curedges + 1].hh.rh) then + edgeprep(mem[h + 2].hh.lh - 4096, mem[h + 2].hh.rh - 4096, mem[h + 1].hh.lh - 4096, mem[h + 1].hh.rh - 4095); + if mem[h + 3].hh.lh <> mem[curedges + 3].hh.lh then begin {367:} + pp := mem[h].hh.rh; + delta := 8 * (mem[curedges + 3].hh.lh - mem[h + 3].hh.lh); + repeat + qq := mem[pp + 1].hh.rh; + while qq <> 30000 do begin + mem[qq].hh.lh := mem[qq].hh.lh + delta; + qq := mem[qq].hh.rh + end; + qq := mem[pp + 1].hh.lh; + while qq > (-29999) do begin + mem[qq].hh.lh := mem[qq].hh.lh + delta; + qq := mem[qq].hh.rh + end; + pp := mem[pp].hh.rh + until pp = h + end {:367}; + n := mem[curedges + 1].hh.lh; + p := mem[curedges].hh.rh; + pp := mem[h].hh.rh; + while n < mem[h + 1].hh.lh do begin + n := n + 1; + p := mem[p].hh.rh + end; {368:} + repeat + qq := mem[pp + 1].hh.lh; + if qq > (-29999) then + if mem[p + 1].hh.lh <= (-29999) then + mem[p + 1].hh.lh := qq + else begin + while mem[qq].hh.rh > (-29999) do + qq := mem[qq].hh.rh; + mem[qq].hh.rh := mem[p + 1].hh.lh; + mem[p + 1].hh.lh := mem[pp + 1].hh.lh + end; + mem[pp + 1].hh.lh := -30000; + qq := mem[pp + 1].hh.rh; + if qq <> 30000 then begin + if mem[p + 1].hh.lh = (-29999) then + mem[p + 1].hh.lh := -30000; + mem[pp + 1].hh.rh := 30000; + r := p + 1; + q := mem[r].hh.rh; + if q = 30000 then + mem[p + 1].hh.rh := qq + else + while true do begin + k := mem[qq].hh.lh; + while k > mem[q].hh.lh do begin + r := q; + q := mem[r].hh.rh + end; + mem[r].hh.rh := qq; + rr := mem[qq].hh.rh; + mem[qq].hh.rh := q; + if rr = 30000 then + goto 30; + r := qq; + qq := rr + end + end; + 30: {:368} + ; + pp := mem[pp].hh.rh; + p := mem[p].hh.rh + until pp = h + end + end; {:366} {369:} + + function totalweight(h: halfword): integer; + var + p, q: halfword; + n: integer; + m: 0..65535; + begin + n := 0; + p := mem[h].hh.rh; + while p <> h do begin + q := mem[p + 1].hh.rh; + while q <> 30000 do begin {370:} + m := mem[q].hh.lh + 32768; + n := n - (((m mod 8) - 4) * (m div 8)); + q := mem[q].hh.rh + end {:370}; + q := mem[p + 1].hh.lh; + while q > (-29999) do begin {370:} + m := mem[q].hh.lh + 32768; + n := n - (((m mod 8) - 4) * (m div 8)); + q := mem[q].hh.rh + end {:370}; + p := mem[p].hh.rh + end; + totalweight := n + end; {:369} +{372:} + + procedure beginedgetracing; + begin + printdiagnostic(408, 155, true); + print(409); + printint(curwt); + printchar(41); + tracex := -4096 + end; { beginedgetracing } + + procedure traceacorner; + begin + if fileoffset > (maxprintline - 13) then + printnl(155); + printchar(40); + printint(tracex); + printchar(44); + printint(traceyy); + printchar(41); + tracey := traceyy + end; + + procedure endedgetracing; + begin + if tracex = (-4096) then + printnl(410) + else begin + traceacorner; + printchar(46) + end; + enddiagnostic(true) + end; {:372} {373:} + + procedure tracenewedge(r: halfword; n: integer); + var + d: integer; + w: -3..3; + m, n0, n1: integer; + begin + d := mem[r].hh.lh + 32768; + w := (d mod 8) - 4; + m := (d div 8) - mem[curedges + 3].hh.lh; + if w = curwt then begin + n0 := n + 1; + n1 := n + end else begin + n0 := n; + n1 := n + 1 + end; + if m <> tracex then begin + if tracex = (-4096) then begin + printnl(155); + traceyy := n0 + end else if traceyy <> n0 then + printchar(63) + else + traceacorner; + tracex := m; + traceacorner + end else begin + if n0 <> traceyy then + printchar(33); + if ((n0 < n1) and (tracey > traceyy)) or ((n0 > n1) and (tracey < traceyy)) then + traceacorner + end; + traceyy := n1 + end; {:373} {374:} + + procedure lineedges(x0, y0, x1, y1: scaled); + label + 30, 31; + var + m0, n0, m1, n1: integer; + delx, dely: scaled; + yt: scaled; + tx: scaled; + p, r: halfword; + base: integer; + n: integer; + begin + n0 := roundunscaled(y0); + n1 := roundunscaled(y1); + if n0 <> n1 then begin + m0 := roundunscaled(x0); + m1 := roundunscaled(x1); + delx := x1 - x0; + dely := y1 - y0; + yt := (n0 * 65536) - 32768; + y0 := y0 - yt; + y1 := y1 - yt; + if n0 < n1 then begin {375:} + base := ((8 * mem[curedges + 3].hh.lh) - 32764) - curwt; + if m0 <= m1 then + edgeprep(m0, m1, n0, n1) + else + edgeprep(m1, m0, n0, n1); {377:} + n := mem[curedges + 5].hh.lh - 4096; + p := mem[curedges + 5].hh.rh; + if n <> n0 then + if n < n0 then + repeat + n := n + 1; + p := mem[p].hh.rh + until n = n0 + else + repeat + n := n - 1; + p := mem[p].hh.lh + until n = n0 {:377}; + y0 := 65536 - y0; + while true do begin + r := getavail; + mem[r].hh.rh := mem[p + 1].hh.lh; + mem[p + 1].hh.lh := r; + tx := takefraction(delx, makefraction(y0, dely)); + if abvscd(delx, y0, dely, tx) < 0 then + tx := tx - 1; + mem[r].hh.lh := (8 * roundunscaled(x0 + tx)) + base; + y1 := y1 - 65536; + if internal[10] > 0 then + tracenewedge(r, n); + if y1 < 65536 then + goto 30; + p := mem[p].hh.rh; + y0 := y0 + 65536; + n := n + 1 + end; + 30: {:375} + + end else begin {376:} + base := ((8 * mem[curedges + 3].hh.lh) - 32764) + curwt; + if m0 <= m1 then + edgeprep(m0, m1, n1, n0) + else + edgeprep(m1, m0, n1, n0); + n0 := n0 - 1; +{377:} + n := mem[curedges + 5].hh.lh - 4096; + p := mem[curedges + 5].hh.rh; + if n <> n0 then + if n < n0 then + repeat + n := n + 1; + p := mem[p].hh.rh + until n = n0 + else + repeat + n := n - 1; + p := mem[p].hh.lh + until n = n0 {:377}; + while true do begin + r := getavail; + mem[r].hh.rh := mem[p + 1].hh.lh; + mem[p + 1].hh.lh := r; + tx := takefraction(delx, makefraction(y0, dely)); + if abvscd(delx, y0, dely, tx) < 0 then + tx := tx + 1; + mem[r].hh.lh := (8 * roundunscaled(x0 - tx)) + base; + y1 := y1 + 65536; + if internal[10] > 0 then + tracenewedge(r, n); + if y1 >= 0 then + goto 31; + p := mem[p].hh.lh; + y0 := y0 + 65536; + n := n - 1 + end; + 31: {:376} + + end; + mem[curedges + 5].hh.rh := p; + mem[curedges + 5].hh.lh := n + 4096 + end + end; {:374} +{378:} + + procedure movetoedges(m0, n0, m1, n1: integer); + label + 60, 61, 62, 63, 30; + var + delta: 0..movesize; + k: 0..movesize; + p, r: halfword; + dx: integer; + edgeandweight: integer; + j: integer; + n: integer; {sum:integer;} + {sum:=move[0]; + for k:=1 to delta do sum:=sum+abs(move[k]); + if sum<>m1-m0 then confusion(48);} + begin + delta := n1 - n0; + {380:} + case octant of + 1: + begin + dx := 8; + edgeprep(m0, m1, n0, n1); + goto 60 + end; + 5: + begin + dx := 8; + edgeprep(n0, n1, m0, m1); + goto 62 + end; + 6: + begin + dx := -8; + edgeprep(-n1, -n0, m0, m1); + n0 := -n0; + goto 62 + end; + 2: + begin + dx := -8; + edgeprep(-m1, -m0, n0, n1); + m0 := -m0; + goto 60 + end; + 4: + begin + dx := -8; + edgeprep(-m1, -m0, -n1, -n0); + m0 := -m0; + goto 61 + end; + 8: + begin + dx := -8; + edgeprep(-n1, -n0, -m1, -m0); + n0 := -n0; + goto 63 + end; + 7: + begin + dx := 8; + edgeprep(n0, n1, -m1, -m0); + goto 63 + end; + 3: + begin + dx := 8; + edgeprep(m0, m1, -n1, -n0); + goto 61 + end + end; {:380} + 60: {381:} {377:} + n := mem[curedges + 5].hh.lh - 4096; + p := mem[curedges + 5].hh.rh; + if n <> n0 then + if n < n0 then + repeat + n := n + 1; + p := mem[p].hh.rh + until n = n0 + else + repeat + n := n - 1; + p := mem[p].hh.lh + until n = n0 {:377}; + if delta > 0 then begin + k := 0; + edgeandweight := ((8 * (m0 + mem[curedges + 3].hh.lh)) - 32764) - curwt; + repeat + edgeandweight := edgeandweight + (dx * move[k]); + begin + r := avail; + if r = (-30000) then + r := getavail + else begin + avail := mem[r].hh.rh; + mem[r].hh.rh := -30000 + end {dynused:=dynused+1;} + end; + mem[r].hh.rh := mem[p + 1].hh.lh; + mem[r].hh.lh := edgeandweight; + if internal[10] > 0 then + tracenewedge(r, n); + mem[p + 1].hh.lh := r; + p := mem[p].hh.rh; + k := k + 1; + n := n + 1 + until k = delta + end; + goto 30 {:381}; + 61: {382:} + n0 := (-n0) - 1; {377:} + n := mem[curedges + 5].hh.lh - 4096; + p := mem[curedges + 5].hh.rh; + if n <> n0 then + if n < n0 then + repeat + n := n + 1; + p := mem[p].hh.rh + until n = n0 + else + repeat + n := n - 1; + p := mem[p].hh.lh + until n = n0 {:377}; + if delta > 0 then begin + k := 0; + edgeandweight := ((8 * (m0 + mem[curedges + 3].hh.lh)) - 32764) + curwt; + repeat + edgeandweight := edgeandweight + (dx * move[k]); + begin + r := avail; + if r = (-30000) then + r := getavail + else begin + avail := mem[r].hh.rh; + mem[r].hh.rh := -30000 + end {dynused:=dynused+1;} + end; + mem[r].hh.rh := mem[p + 1].hh.lh; + mem[r].hh.lh := edgeandweight; + if internal[10] > 0 then + tracenewedge(r, n); + mem[p + 1].hh.lh := r; + p := mem[p].hh.lh; + k := k + 1; + n := n - 1 + until k = delta + end; + goto 30 {:382}; + 62: {383:} + edgeandweight := ((8 * (n0 + mem[curedges + 3].hh.lh)) - 32764) - curwt; + n0 := m0; + k := 0; +{377:} + n := mem[curedges + 5].hh.lh - 4096; + p := mem[curedges + 5].hh.rh; + if n <> n0 then + if n < n0 then + repeat + n := n + 1; + p := mem[p].hh.rh + until n = n0 + else + repeat + n := n - 1; + p := mem[p].hh.lh + until n = n0 {:377}; + repeat + j := move[k]; + while j > 0 do begin + begin + r := avail; + if r = (-30000) then + r := getavail + else begin + avail := mem[r].hh.rh; + mem[r].hh.rh := -30000 + end {dynused:=dynused+1;} + end; + mem[r].hh.rh := mem[p + 1].hh.lh; + mem[r].hh.lh := edgeandweight; + if internal[10] > 0 then + tracenewedge(r, n); + mem[p + 1].hh.lh := r; + p := mem[p].hh.rh; + j := j - 1; + n := n + 1 + end; + edgeandweight := edgeandweight + dx; + k := k + 1 + until k > delta; + goto 30 {:383}; + 63: {384:} + edgeandweight := ((8 * (n0 + mem[curedges + 3].hh.lh)) - 32764) + curwt; + n0 := (-m0) - 1; + k := 0; +{377:} + n := mem[curedges + 5].hh.lh - 4096; + p := mem[curedges + 5].hh.rh; + if n <> n0 then + if n < n0 then + repeat + n := n + 1; + p := mem[p].hh.rh + until n = n0 + else + repeat + n := n - 1; + p := mem[p].hh.lh + until n = n0 {:377}; + repeat + j := move[k]; + while j > 0 do begin + begin + r := avail; + if r = (-30000) then + r := getavail + else begin + avail := mem[r].hh.rh; + mem[r].hh.rh := -30000 + end {dynused:=dynused+1;} + end; + mem[r].hh.rh := mem[p + 1].hh.lh; + mem[r].hh.lh := edgeandweight; + if internal[10] > 0 then + tracenewedge(r, n); + mem[p + 1].hh.lh := r; + p := mem[p].hh.lh; + j := j - 1; + n := n - 1 + end; + edgeandweight := edgeandweight + dx; + k := k + 1 + until k > delta; + goto 30 {:384}; + 30: + mem[curedges + 5].hh.lh := n + 4096; + mem[curedges + 5].hh.rh := p + end; {:378} {387:} + + procedure skew(x, y: scaled; octant: smallnumber); + begin + case octant of + 1: + begin + curx := x - y; + cury := y + end; + 5: + begin + curx := y - x; + cury := x + end; + 6: + begin + curx := y + x; + cury := -x + end; + 2: + begin + curx := (-x) - y; + cury := y + end; + 4: + begin + curx := (-x) + y; + cury := -y + end; + 8: + begin + curx := (-y) + x; + cury := -x + end; + 7: + begin + curx := (-y) - x; + cury := x + end; + 3: + begin + curx := x + y; + cury := -y + end + end + end; {:387} {390:} + + procedure abnegate(x, y: scaled; octantbefore, octantafter: smallnumber); + begin + if odd(octantbefore) = odd(octantafter) then + curx := x + else + curx := -x; + if (octantbefore > 2) = (octantafter > 2) then + cury := y + else + cury := -y + end; {:390} +{391:} + + function crossingpoint(a, b, c: integer): fraction; + label + 10; + var + d: integer; + x, xx, x0, x1, x2: integer; + begin + if a < 0 then begin + crossingpoint := 0; + goto 10 + end; + if c >= 0 then begin + if b >= 0 then + if c > 0 then begin + crossingpoint := 268435457; + goto 10 + end else if (a = 0) and (b = 0) then begin + crossingpoint := 268435457; + goto 10 + end else begin + crossingpoint := 268435456; + goto 10 + end; + if a = 0 then begin + crossingpoint := 0; + goto 10 + end + end else if a = 0 then + if b <= 0 then begin + crossingpoint := 0; + goto 10 + end; +{392:} + d := 1; + x0 := a; + x1 := a - b; + x2 := b - c; + repeat + x := (x1 + x2) div 2; + if (x1 - x0) > x0 then begin + x2 := x; + x0 := x0 + x0; + d := d + d + end else begin + xx := (x1 + x) - x0; + if xx > x0 then begin + x2 := x; + x0 := x0 + x0; + d := d + d + end else begin + x0 := x0 - xx; + if x <= x0 then + if (x + x2) <= x0 then begin + crossingpoint := 268435457; + goto 10 + end; + x1 := x; + d := (d + d) + 1 + end + end + until d >= 268435456; + crossingpoint := d - 268435456 {:392}; + 10: + + end; {:391} {394:} + + procedure printspec(s: strnumber); + label + 45, 30; + var + p, q: halfword; + octant: smallnumber; + begin + printdiagnostic(411, s, true); + p := curspec; + octant := mem[p + 3].int; + println; + unskew(mem[curspec + 1].int, mem[curspec + 2].int, octant); + printtwo(curx, cury); + print(412); + while true do begin + print(octantdir[octant]); + printchar(39); + while true do begin + q := mem[p].hh.rh; + if mem[p].hh.b1 = 0 then + goto 45; +{397:} + begin + printnl(423); + unskew(mem[p + 5].int, mem[p + 6].int, octant); + printtwo(curx, cury); + print(390); + unskew(mem[q + 3].int, mem[q + 4].int, octant); + printtwo(curx, cury); + printnl(387); + unskew(mem[q + 1].int, mem[q + 2].int, octant); + printtwo(curx, cury); + print(424); + printint(mem[q].hh.b0 - 1) + end {:397}; + p := q + end; + 45: + if q = curspec then + goto 30; + p := q; + octant := mem[p + 3].int; + printnl(413) + end; + 30: + printnl(414); + enddiagnostic(true) + end; {:394} {398:} + + procedure printstrange(s: strnumber); + var + p: halfword; + f: halfword; + q: halfword; + t: integer; + begin + if interaction = 3 then + ; + printnl(62); {399:} + p := curspec; + t := 128; + repeat + p := mem[p].hh.rh; + if mem[p].hh.b0 <> 0 then begin + if mem[p].hh.b0 < t then + f := p; + t := mem[p].hh.b0 + end + until p = curspec {:399}; {400:} + p := curspec; + q := p; + repeat + p := mem[p].hh.rh; + if mem[p].hh.b0 = 0 then + q := p + until p = f {:400}; + t := 0; + repeat + if mem[p].hh.b0 <> 0 then begin + if mem[p].hh.b0 <> t then begin + t := mem[p].hh.b0; + printchar(32); + printint(t - 1) + end; + if q <> (-30000) then begin {401:} + if mem[mem[q].hh.rh].hh.b0 = 0 then begin + print(425); + print(octantdir[mem[q + 3].int]); + q := mem[q].hh.rh; + while mem[mem[q].hh.rh].hh.b0 = 0 do begin + printchar(32); + print(octantdir[mem[q + 3].int]); + q := mem[q].hh.rh + end; + printchar(41) + end {:401}; + printchar(32); + print(octantdir[mem[q + 3].int]); + q := -30000 + end + end else if q = (-30000) then + q := p; + p := mem[p].hh.rh + until p = f; + printchar(32); + printint(mem[p].hh.b0 - 1); + if q <> (-30000) then {401:} + if mem[mem[q].hh.rh].hh.b0 = 0 then begin + print(425); + print(octantdir[mem[q + 3].int]); + q := mem[q].hh.rh; + while mem[mem[q].hh.rh].hh.b0 = 0 do begin + printchar(32); + print(octantdir[mem[q + 3].int]); + q := mem[q].hh.rh + end; + printchar(41) + end {:401}; + begin + if interaction = 3 then + ; + printnl(133); + print(s) + end + end; { printstrange } +{:398} + {402:} + {405:} + + procedure removecubic(p: halfword); + var + q: halfword; + begin + q := mem[p].hh.rh; + mem[p].hh.b1 := mem[q].hh.b1; + mem[p].hh.rh := mem[q].hh.rh; + mem[p + 1].int := mem[q + 1].int; + mem[p + 2].int := mem[q + 2].int; + mem[p + 5].int := mem[q + 5].int; + mem[p + 6].int := mem[q + 6].int; + freenode(q, 7) + end; {:405} {406:} {410:} + + procedure splitcubic(p: halfword; t: fraction; xq, yq: scaled); + var + v: scaled; + q, r: halfword; + begin + q := mem[p].hh.rh; + r := getnode(7); + mem[p].hh.rh := r; + mem[r].hh.rh := q; + mem[r].hh.b0 := mem[q].hh.b0; + mem[r].hh.b1 := mem[p].hh.b1; + v := mem[p + 5].int - takefraction(mem[p + 5].int - mem[q + 3].int, t); + mem[p + 5].int := mem[p + 1].int - takefraction(mem[p + 1].int - mem[p + 5].int, t); + mem[q + 3].int := mem[q + 3].int - takefraction(mem[q + 3].int - xq, t); + mem[r + 3].int := mem[p + 5].int - takefraction(mem[p + 5].int - v, t); + mem[r + 5].int := v - takefraction(v - mem[q + 3].int, t); + mem[r + 1].int := mem[r + 3].int - takefraction(mem[r + 3].int - mem[r + 5].int, t); + v := mem[p + 6].int - takefraction(mem[p + 6].int - mem[q + 4].int, t); + mem[p + 6].int := mem[p + 2].int - takefraction(mem[p + 2].int - mem[p + 6].int, t); + mem[q + 4].int := mem[q + 4].int - takefraction(mem[q + 4].int - yq, t); + mem[r + 4].int := mem[p + 6].int - takefraction(mem[p + 6].int - v, t); + mem[r + 6].int := v - takefraction(v - mem[q + 4].int, t); + mem[r + 2].int := mem[r + 4].int - takefraction(mem[r + 4].int - mem[r + 6].int, t) + end; {:410} + + procedure quadrantsubdivide; + label + 22, 10; + var + p, q, r, s, pp, qq: halfword; + firstx, firsty: scaled; + del1, del2, del3, del, dmax: scaled; + t: fraction; + destx, desty: scaled; + constantx: boolean; + begin + p := curspec; + firstx := mem[curspec + 1].int; + firsty := mem[curspec + 2].int; + repeat + 22: + q := mem[p].hh.rh; {407:} + if q = curspec then begin + destx := firstx; + desty := firsty + end else begin + destx := mem[q + 1].int; + desty := mem[q + 2].int + end; + del1 := mem[p + 5].int - mem[p + 1].int; + del2 := mem[q + 3].int - mem[p + 5].int; + del3 := destx - mem[q + 3].int; {408:} + if del1 <> 0 then + del := del1 + else if del2 <> 0 then + del := del2 + else + del := del3; + if del <> 0 then begin + dmax := abs(del1); + if abs(del2) > dmax then + dmax := abs(del2); + if abs(del3) > dmax then + dmax := abs(del3); + while dmax < 134217728 do begin + dmax := dmax + dmax; + del1 := del1 + del1; + del2 := del2 + del2; + del3 := del3 + del3 + end + end {:408}; + if del = 0 then + constantx := true + else begin + constantx := false; + if del < 0 then begin {409:} + mem[p + 1].int := -mem[p + 1].int; + mem[p + 5].int := -mem[p + 5].int; + mem[q + 3].int := -mem[q + 3].int; + del1 := -del1; + del2 := -del2; + del3 := -del3; + destx := -destx; + mem[p].hh.b1 := 2 + end {:409}; + t := crossingpoint(del1, del2, del3); + if t < 268435456 then begin {411:} + splitcubic(p, t, destx, desty); + r := mem[p].hh.rh; + if mem[r].hh.b1 > 1 then + mem[r].hh.b1 := 1 + else + mem[r].hh.b1 := 2; + if mem[r + 1].int < mem[p + 1].int then + mem[r + 1].int := mem[p + 1].int; + mem[r + 3].int := mem[r + 1].int; + mem[r + 1].int := -mem[r + 1].int; + mem[r + 5].int := mem[r + 1].int; + mem[q + 3].int := -mem[q + 3].int; + destx := -destx; + del2 := del2 - takefraction(del2 - del3, t); + if del2 > 0 then + del2 := 0; + t := crossingpoint(0, -del2, -del3); + if t < 268435456 then begin {412:} + splitcubic(r, t, destx, desty); + s := mem[r].hh.rh; + if mem[s + 1].int < destx then + mem[s + 1].int := destx; + if mem[s + 1].int < mem[r + 1].int then + mem[s + 1].int := mem[r + 1].int; + mem[s].hh.b1 := mem[p].hh.b1; + mem[s + 3].int := mem[s + 1].int; + mem[s + 1].int := -mem[s + 1].int; + mem[s + 5].int := mem[s + 1].int; + mem[q + 3].int := -mem[q + 3].int + end else if mem[r + 1].int > destx then {:412} + mem[r + 1].int := destx + end {:411} + end {:407}; +{413:} + pp := p; + repeat + qq := mem[pp].hh.rh; + abnegate(mem[qq + 1].int, mem[qq + 2].int, mem[qq].hh.b1, mem[pp].hh.b1); + destx := curx; + desty := cury; + del1 := mem[pp + 6].int - mem[pp + 2].int; + del2 := mem[qq + 4].int - mem[pp + 6].int; + del3 := desty - mem[qq + 4].int; {408:} + if del1 <> 0 then + del := del1 + else if del2 <> 0 then + del := del2 + else + del := del3; + if del <> 0 then begin + dmax := abs(del1); + if abs(del2) > dmax then + dmax := abs(del2); + if abs(del3) > dmax then + dmax := abs(del3); + while dmax < 134217728 do begin + dmax := dmax + dmax; + del1 := del1 + del1; + del2 := del2 + del2; + del3 := del3 + del3 + end + end {:408}; + if del <> 0 then begin + if del < 0 then begin {414:} + mem[pp + 2].int := -mem[pp + 2].int; + mem[pp + 6].int := -mem[pp + 6].int; + mem[qq + 4].int := -mem[qq + 4].int; + del1 := -del1; + del2 := -del2; + del3 := -del3; + desty := -desty; + mem[pp].hh.b1 := mem[pp].hh.b1 + 2 + end {:414}; + t := crossingpoint(del1, del2, del3); + if t < 268435456 then begin {415:} + splitcubic(pp, t, destx, desty); + r := mem[pp].hh.rh; + if mem[r].hh.b1 > 2 then + mem[r].hh.b1 := mem[r].hh.b1 - 2 + else + mem[r].hh.b1 := mem[r].hh.b1 + 2; + if mem[r + 1].int > destx then + mem[r + 1].int := destx + else if mem[r + 1].int < mem[pp + 1].int then + mem[r + 1].int := mem[pp + 1].int; + if mem[r + 2].int < mem[pp + 2].int then + mem[r + 2].int := mem[pp + 2].int; + mem[r + 4].int := mem[r + 2].int; + mem[r + 2].int := -mem[r + 2].int; + mem[r + 6].int := mem[r + 2].int; + mem[qq + 4].int := -mem[qq + 4].int; + desty := -desty; + del2 := del2 - takefraction(del2 - del3, t); + if del2 > 0 then + del2 := 0; + t := crossingpoint(0, -del2, -del3); + if t < 268435456 then begin {416:} + splitcubic(r, t, destx, desty); + s := mem[r].hh.rh; + if mem[s + 1].int > destx then + mem[s + 1].int := destx + else if mem[s + 1].int < mem[r + 1].int then + mem[s + 1].int := mem[r + 1].int; + if mem[s + 2].int < desty then + mem[s + 2].int := desty; + if mem[s + 2].int < mem[r + 2].int then + mem[s + 2].int := mem[r + 2].int; + mem[s].hh.b1 := mem[pp].hh.b1; + mem[s + 4].int := mem[s + 2].int; + mem[s + 2].int := -mem[s + 2].int; + mem[s + 6].int := mem[s + 2].int; + mem[qq + 4].int := -mem[qq + 4].int + end else if mem[r + 2].int > desty then {:416} + mem[r + 2].int := desty + end {:415} + end else if constantx then begin {417:} + if q <> p then begin + removecubic(p); + if curspec <> q then + goto 22 + else begin + curspec := p; + goto 10 + end + end + end else if not odd(mem[pp].hh.b1) then begin {414:} + mem[pp + 2].int := -mem[pp + 2].int; + mem[pp + 6].int := -mem[pp + 6].int; + mem[qq + 4].int := -mem[qq + 4].int; + del1 := -del1; + del2 := -del2; + del3 := -del3; + desty := -desty; + mem[pp].hh.b1 := mem[pp].hh.b1 + 2 + end {:414} {:417}; + pp := qq + until pp = q; + if constantx then begin {418:} + pp := p; + repeat + qq := mem[pp].hh.rh; + if mem[pp].hh.b1 > 2 then begin + mem[pp].hh.b1 := mem[pp].hh.b1 + 1; + mem[pp + 1].int := -mem[pp + 1].int; + mem[pp + 5].int := -mem[pp + 5].int; + mem[qq + 3].int := -mem[qq + 3].int + end; + pp := qq + until pp = q + end {:418} {:413}; + p := q + until p = curspec; + 10: + + end; {:406} {419:} + + procedure octantsubdivide; + var + p, q, r, s: halfword; + del1, del2, del3, del, dmax: scaled; + t: fraction; + destx, desty: scaled; + begin + p := curspec; + repeat + q := mem[p].hh.rh; + mem[p + 1].int := mem[p + 1].int - mem[p + 2].int; + mem[p + 5].int := mem[p + 5].int - mem[p + 6].int; + mem[q + 3].int := mem[q + 3].int - mem[q + 4].int; {420:} {421:} + if q = curspec then begin + unskew(mem[q + 1].int, mem[q + 2].int, mem[q].hh.b1); + skew(curx, cury, mem[p].hh.b1); + destx := curx; + desty := cury + end else begin + abnegate(mem[q + 1].int, mem[q + 2].int, mem[q].hh.b1, mem[p].hh.b1); + destx := curx - cury; + desty := cury + end; + del1 := mem[p + 5].int - mem[p + 1].int; + del2 := mem[q + 3].int - mem[p + 5].int; + del3 := destx - mem[q + 3].int {:421}; {408:} + if del1 <> 0 then + del := del1 + else if del2 <> 0 then + del := del2 + else + del := del3; + if del <> 0 then begin + dmax := abs(del1); + if abs(del2) > dmax then + dmax := abs(del2); + if abs(del3) > dmax then + dmax := abs(del3); + while dmax < 134217728 do begin + dmax := dmax + dmax; + del1 := del1 + del1; + del2 := del2 + del2; + del3 := del3 + del3 + end + end {:408}; + if del <> 0 then begin + if del < 0 then begin {423:} + mem[p + 2].int := mem[p + 1].int + mem[p + 2].int; + mem[p + 1].int := -mem[p + 1].int; + mem[p + 6].int := mem[p + 5].int + mem[p + 6].int; + mem[p + 5].int := -mem[p + 5].int; + mem[q + 4].int := mem[q + 3].int + mem[q + 4].int; + mem[q + 3].int := -mem[q + 3].int; + del1 := -del1; + del2 := -del2; + del3 := -del3; + desty := destx + desty; + destx := -destx; + mem[p].hh.b1 := mem[p].hh.b1 + 4 + end {:423}; + t := crossingpoint(del1, del2, del3); + if t < 268435456 then begin {424:} + splitcubic(p, t, destx, desty); + r := mem[p].hh.rh; + if mem[r].hh.b1 > 4 then + mem[r].hh.b1 := mem[r].hh.b1 - 4 + else + mem[r].hh.b1 := mem[r].hh.b1 + 4; + if mem[r + 2].int > desty then + mem[r + 2].int := desty + else if mem[r + 2].int < mem[p + 2].int then + mem[r + 2].int := mem[p + 2].int; + if mem[r + 1].int < mem[p + 1].int then + mem[r + 1].int := mem[p + 1].int; + mem[r + 3].int := mem[r + 1].int; + mem[r + 2].int := mem[r + 2].int + mem[r + 1].int; + mem[r + 1].int := -mem[r + 1].int; + mem[r + 5].int := mem[r + 1].int; + mem[r + 6].int := mem[r + 6].int - mem[r + 5].int; + mem[q + 4].int := mem[q + 4].int + mem[q + 3].int; + mem[q + 3].int := -mem[q + 3].int; + desty := desty + destx; + destx := -destx; + del2 := del2 - takefraction(del2 - del3, t); + if del2 > 0 then + del2 := 0; + t := crossingpoint(0, -del2, -del3); + if t < 268435456 then begin {425:} + splitcubic(r, t, destx, desty); + s := mem[r].hh.rh; + if mem[s + 2].int > desty then + mem[s + 2].int := desty + else if mem[s + 2].int < mem[r + 2].int then + mem[s + 2].int := mem[r + 2].int; + if mem[s + 1].int < destx then + mem[s + 1].int := destx; + if mem[s + 1].int < mem[r + 1].int then + mem[s + 1].int := mem[r + 1].int; + mem[s].hh.b1 := mem[p].hh.b1; + mem[s + 3].int := mem[s + 1].int; + mem[s + 2].int := mem[s + 2].int + mem[s + 1].int; + mem[s + 1].int := -mem[s + 1].int; + mem[s + 6].int := mem[s + 6].int - mem[s + 1].int; + mem[s + 5].int := mem[s + 1].int; + mem[q + 4].int := mem[q + 4].int + mem[q + 3].int; + mem[q + 3].int := -mem[q + 3].int + end else if mem[r + 1].int > destx then {:425} + mem[r + 1].int := destx {:424} + end + end {:420}; + p := q + until p = curspec + end; {:419} {426:} + + procedure makesafe; + var + k: 0..maxwiggle; + allsafe: boolean; + nexta: scaled; + deltaa, deltab: scaled; + begin + before[curroundingptr] := before[0]; + nodetoround[curroundingptr] := nodetoround[0]; + repeat + after[curroundingptr] := after[0]; + allsafe := true; + nexta := after[0]; + for k := 0 to curroundingptr - 1 do begin + deltab := before[k + 1] - before[k]; + if deltab >= 0 then + deltaa := after[k + 1] - nexta + else + deltaa := nexta - after[k + 1]; + nexta := after[k + 1]; + if (deltaa < 0) or (deltaa > abs(deltab + deltab)) then begin + allsafe := false; + after[k] := before[k]; + if k = (curroundingptr - 1) then + after[0] := before[0] + else + after[k + 1] := before[k + 1] + end + end + until allsafe + end; {:426} {429:} + + procedure beforeandafter(b, a: scaled; p: halfword); + begin + if curroundingptr = maxroundingptr then + if maxroundingptr < maxwiggle then + maxroundingptr := maxroundingptr + 1 + else + overflow(435, maxwiggle); + after[curroundingptr] := a; + before[curroundingptr] := b; + nodetoround[curroundingptr] := p; + curroundingptr := curroundingptr + 1 + end; { beforeandafter } +{:429} + {431:} + + function goodval(b, o: scaled): scaled; + var + a: scaled; + begin + a := b + o; + if a >= 0 then + a := (a - (a mod curgran)) - o + else + a := (((a + ((-(a + 1)) mod curgran)) - curgran) + 1) - o; + if (b - a) < ((a + curgran) - b) then + goodval := a + else + goodval := a + curgran + end; {:431} {432:} + + function compromise(u, v: scaled): scaled; + begin + compromise := goodval(u + u, (-u) - v) div 2 + end; {:432} {433:} + + procedure xyround; + var + p, q: halfword; + b, a: scaled; + penedge: scaled; + alpha: fraction; + begin + curgran := abs(internal[37]); + if curgran = 0 then + curgran := 65536; + p := curspec; + curroundingptr := 0; + repeat + q := mem[p].hh.rh; {434:} + if odd(mem[p].hh.b1) <> odd(mem[q].hh.b1) then begin + if odd(mem[q].hh.b1) then + b := mem[q + 1].int + else + b := -mem[q + 1].int; + if (abs(mem[q + 1].int - mem[q + 5].int) < 655) or (abs(mem[q + 1].int + mem[q + 3].int) < 655) then begin {435:} + if curpen = (-29997) then + penedge := 0 + else if curpathtype = 0 then + penedge := compromise(mem[mem[curpen + 5].hh.rh + 2].int, mem[mem[curpen + 7].hh.rh + 2].int) + else if odd(mem[q].hh.b1) then + penedge := mem[mem[curpen + 7].hh.rh + 2].int + else + penedge := mem[mem[curpen + 5].hh.rh + 2].int; + a := goodval(b, penedge) + end else {:435} + a := b; + if abs(a) > maxallowed then + if a > 0 then + a := maxallowed + else + a := -maxallowed; + beforeandafter(b, a, q) + end {:434}; + p := q + until p = curspec; + if curroundingptr > 0 then begin {436:} + makesafe; + repeat + curroundingptr := curroundingptr - 1; + if (after[curroundingptr] <> before[curroundingptr]) or (after[curroundingptr + 1] <> before[curroundingptr + 1]) then begin + p := nodetoround[curroundingptr]; + if odd(mem[p].hh.b1) then begin + b := before[curroundingptr]; + a := after[curroundingptr] + end else begin + b := -before[curroundingptr]; + a := -after[curroundingptr] + end; + if before[curroundingptr] = before[curroundingptr + 1] then + alpha := 268435456 + else + alpha := makefraction(after[curroundingptr + 1] - after[curroundingptr], before[curroundingptr + 1] - before[curroundingptr]); + repeat + mem[p + 1].int := takefraction(alpha, mem[p + 1].int - b) + a; + mem[p + 5].int := takefraction(alpha, mem[p + 5].int - b) + a; + p := mem[p].hh.rh; + mem[p + 3].int := takefraction(alpha, mem[p + 3].int - b) + a + until p = nodetoround[curroundingptr + 1] + end + until curroundingptr = 0 + end {:436}; + p := curspec; + curroundingptr := 0; + repeat + q := mem[p].hh.rh; {437:} + if (mem[p].hh.b1 > 2) <> (mem[q].hh.b1 > 2) then begin + if mem[q].hh.b1 <= 2 then + b := mem[q + 2].int + else + b := -mem[q + 2].int; + if (abs(mem[q + 2].int - mem[q + 6].int) < 655) or (abs(mem[q + 2].int + mem[q + 4].int) < 655) then begin {438:} + if curpen = (-29997) then + penedge := 0 + else if curpathtype = 0 then + penedge := compromise(mem[mem[curpen + 2].hh.rh + 2].int, mem[mem[curpen + 1].hh.rh + 2].int) + else if mem[q].hh.b1 <= 2 then + penedge := mem[mem[curpen + 1].hh.rh + 2].int + else + penedge := mem[mem[curpen + 2].hh.rh + 2].int; + a := goodval(b, penedge) + end else {:438} + a := b; + if abs(a) > maxallowed then + if a > 0 then + a := maxallowed + else + a := -maxallowed; + beforeandafter(b, a, q) + end {:437}; + p := q + until p = curspec; + if curroundingptr > 0 then begin {439:} + makesafe; + repeat + curroundingptr := curroundingptr - 1; + if (after[curroundingptr] <> before[curroundingptr]) or (after[curroundingptr + 1] <> before[curroundingptr + 1]) then begin + p := nodetoround[curroundingptr]; + if mem[p].hh.b1 <= 2 then begin + b := before[curroundingptr]; + a := after[curroundingptr] + end else begin + b := -before[curroundingptr]; + a := -after[curroundingptr] + end; + if before[curroundingptr] = before[curroundingptr + 1] then + alpha := 268435456 + else + alpha := makefraction(after[curroundingptr + 1] - after[curroundingptr], before[curroundingptr + 1] - before[curroundingptr]); + repeat + mem[p + 2].int := takefraction(alpha, mem[p + 2].int - b) + a; + mem[p + 6].int := takefraction(alpha, mem[p + 6].int - b) + a; + p := mem[p].hh.rh; + mem[p + 4].int := takefraction(alpha, mem[p + 4].int - b) + a + until p = nodetoround[curroundingptr + 1] + end + until curroundingptr = 0 + end {:439} + end; {:433} {440:} + + procedure diaground; + var + p, q, pp: halfword; + b, a, bb, aa, d, c, dd, cc: scaled; + penedge: scaled; + alpha, beta: fraction; + nexta: scaled; + allsafe: boolean; + k: 0..maxwiggle; + firstx, firsty: scaled; + begin + p := curspec; + curroundingptr := 0; + repeat + q := mem[p].hh.rh; {441:} + if mem[p].hh.b1 <> mem[q].hh.b1 then begin + if mem[q].hh.b1 > 4 then + b := -mem[q + 1].int + else + b := mem[q + 1].int; + if abs(mem[q].hh.b1 - mem[p].hh.b1) = 4 then + if (abs(mem[q + 1].int - mem[q + 5].int) < 655) or (abs(mem[q + 1].int + mem[q + 3].int) < 655) then begin {442:} + if curpen = (-29997) then + penedge := 0 + else if curpathtype = 0 then {443:} + case mem[q].hh.b1 of + 1, 5: + penedge := compromise(mem[mem[mem[curpen + 1].hh.rh].hh.lh + 1].int, -mem[mem[mem[curpen + 4].hh.rh].hh.lh + 1].int); + 4, 8: + penedge := -compromise(mem[mem[mem[curpen + 1].hh.rh].hh.lh + 1].int, -mem[mem[mem[curpen + 4].hh.rh].hh.lh + 1].int); + 6, 2: + penedge := compromise(mem[mem[mem[curpen + 2].hh.rh].hh.lh + 1].int, -mem[mem[mem[curpen + 3].hh.rh].hh.lh + 1].int); + 7, 3: + penedge := -compromise(mem[mem[mem[curpen + 2].hh.rh].hh.lh + 1].int, -mem[mem[mem[curpen + 3].hh.rh].hh.lh + 1].int) + end {:443} + else if mem[q].hh.b1 <= 4 then + penedge := mem[mem[mem[curpen + mem[q].hh.b1].hh.rh].hh.lh + 1].int + else + penedge := -mem[mem[mem[curpen + mem[q].hh.b1].hh.rh].hh.lh + 1].int; + if odd(mem[q].hh.b1) then + a := goodval(b, penedge + (curgran div 2)) + else + a := goodval(b - 1, penedge + (curgran div 2)) + end else {:442} + a := b + else + a := b; + beforeandafter(b, a, q) + end {:441}; + p := q + until p = curspec; + if curroundingptr > 0 then begin {444:} + p := nodetoround[0]; + firstx := mem[p + 1].int; + firsty := mem[p + 2].int; {446:} + before[curroundingptr] := before[0]; + nodetoround[curroundingptr] := nodetoround[0]; + repeat + after[curroundingptr] := after[0]; + allsafe := true; + nexta := after[0]; + for k := 0 to curroundingptr - 1 do begin + a := nexta; + b := before[k]; + nexta := after[k + 1]; + aa := nexta; + bb := before[k + 1]; + if (a <> b) or (aa <> bb) then begin + p := nodetoround[k]; + pp := nodetoround[k + 1]; +{445:} + if aa = bb then begin + if pp = nodetoround[0] then + unskew(firstx, firsty, mem[pp].hh.b1) + else + unskew(mem[pp + 1].int, mem[pp + 2].int, mem[pp].hh.b1); + skew(curx, cury, mem[p].hh.b1); + bb := curx; + aa := bb; + dd := cury; + cc := dd; + if mem[p].hh.b1 > 4 then begin + b := -b; + a := -a + end + end else begin + if mem[p].hh.b1 > 4 then begin + bb := -bb; + aa := -aa; + b := -b; + a := -a + end; + if pp = nodetoround[0] then + dd := firsty - bb + else + dd := mem[pp + 2].int - bb; + if odd(aa - bb) then + if mem[p].hh.b1 > 4 then + cc := dd - (((aa - bb) + 1) div 2) + else + cc := dd - (((aa - bb) - 1) div 2) + else + cc := dd - ((aa - bb) div 2) + end; + d := mem[p + 2].int; + if odd(a - b) then + if mem[p].hh.b1 > 4 then + c := d - (((a - b) - 1) div 2) + else + c := d - (((a - b) + 1) div 2) + else + c := d - ((a - b) div 2) {:445}; + if (((aa < a) or (cc < c)) or ((aa - a) > (2 * (bb - b)))) or ((cc - c) > (2 * (dd - d))) then begin + allsafe := false; + after[k] := before[k]; + if k = (curroundingptr - 1) then + after[0] := before[0] + else + after[k + 1] := before[k + 1] + end + end + end + until allsafe {:446}; + for k := 0 to curroundingptr - 1 do begin + a := after[k]; + b := before[k]; + aa := after[k + 1]; + bb := before[k + 1]; + if (a <> b) or (aa <> bb) then begin + p := nodetoround[k]; + pp := nodetoround[k + 1]; +{445:} + if aa = bb then begin + if pp = nodetoround[0] then + unskew(firstx, firsty, mem[pp].hh.b1) + else + unskew(mem[pp + 1].int, mem[pp + 2].int, mem[pp].hh.b1); + skew(curx, cury, mem[p].hh.b1); + bb := curx; + aa := bb; + dd := cury; + cc := dd; + if mem[p].hh.b1 > 4 then begin + b := -b; + a := -a + end + end else begin + if mem[p].hh.b1 > 4 then begin + bb := -bb; + aa := -aa; + b := -b; + a := -a + end; + if pp = nodetoround[0] then + dd := firsty - bb + else + dd := mem[pp + 2].int - bb; + if odd(aa - bb) then + if mem[p].hh.b1 > 4 then + cc := dd - (((aa - bb) + 1) div 2) + else + cc := dd - (((aa - bb) - 1) div 2) + else + cc := dd - ((aa - bb) div 2) + end; + d := mem[p + 2].int; + if odd(a - b) then + if mem[p].hh.b1 > 4 then + c := d - (((a - b) - 1) div 2) + else + c := d - (((a - b) + 1) div 2) + else + c := d - ((a - b) div 2) {:445}; + if b = bb then + alpha := 268435456 + else + alpha := makefraction(aa - a, bb - b); + if d = dd then + beta := 268435456 + else + beta := makefraction(cc - c, dd - d); + repeat + mem[p + 1].int := takefraction(alpha, mem[p + 1].int - b) + a; + mem[p + 2].int := takefraction(beta, mem[p + 2].int - d) + c; + mem[p + 5].int := takefraction(alpha, mem[p + 5].int - b) + a; + mem[p + 6].int := takefraction(beta, mem[p + 6].int - d) + c; + p := mem[p].hh.rh; + mem[p + 3].int := takefraction(alpha, mem[p + 3].int - b) + a; + mem[p + 4].int := takefraction(beta, mem[p + 4].int - d) + c + until p = pp + end + end + end {:444} + end; {:440} {451:} + + procedure newboundary(p: halfword; octant: smallnumber); + var + q, r: halfword; + begin + q := mem[p].hh.rh; + r := getnode(7); + mem[r].hh.rh := q; + mem[p].hh.rh := r; + mem[r].hh.b0 := mem[q].hh.b0; + mem[r + 3].int := mem[q + 3].int; + mem[r + 4].int := mem[q + 4].int; + mem[r].hh.b1 := 0; + mem[q].hh.b0 := 0; + mem[r + 5].int := octant; + mem[q + 3].int := mem[q].hh.b1; + unskew(mem[q + 1].int, mem[q + 2].int, mem[q].hh.b1); + skew(curx, cury, octant); + mem[r + 1].int := curx; + mem[r + 2].int := cury + end; {:451} + + function makespec(h: halfword; safetymargin: scaled; tracing: integer): halfword; + label + 22, 30; + var + p, q, r, s: halfword; + k: integer; + chopped: boolean; {453:} + o1, o2: smallnumber; + clockwise: boolean; + dx1, dy1, dx2, dy2: integer; + dmax, del: integer; {:453} + begin + curspec := h; + if tracing > 0 then + printpath(curspec, 426, true); + maxallowed := 268402687 - safetymargin; {404:} + p := curspec; + k := 1; + chopped := false; + repeat + if abs(mem[p + 3].int) > maxallowed then begin + chopped := true; + if mem[p + 3].int > 0 then + mem[p + 3].int := maxallowed + else + mem[p + 3].int := -maxallowed + end; + if abs(mem[p + 4].int) > maxallowed then begin + chopped := true; + if mem[p + 4].int > 0 then + mem[p + 4].int := maxallowed + else + mem[p + 4].int := -maxallowed + end; + if abs(mem[p + 1].int) > maxallowed then begin + chopped := true; + if mem[p + 1].int > 0 then + mem[p + 1].int := maxallowed + else + mem[p + 1].int := -maxallowed + end; + if abs(mem[p + 2].int) > maxallowed then begin + chopped := true; + if mem[p + 2].int > 0 then + mem[p + 2].int := maxallowed + else + mem[p + 2].int := -maxallowed + end; + if abs(mem[p + 5].int) > maxallowed then begin + chopped := true; + if mem[p + 5].int > 0 then + mem[p + 5].int := maxallowed + else + mem[p + 5].int := -maxallowed + end; + if abs(mem[p + 6].int) > maxallowed then begin + chopped := true; + if mem[p + 6].int > 0 then + mem[p + 6].int := maxallowed + else + mem[p + 6].int := -maxallowed + end; + p := mem[p].hh.rh; + mem[p].hh.b0 := k; + if k < 127 then + k := k + 1 + else + k := 1 + until p = curspec; + if chopped then begin + begin + if interaction = 3 then + ; + printnl(133); + print(430) + end; + begin + helpptr := 4; + helpline[3] := 431; + helpline[2] := 432; + helpline[1] := 433; + helpline[0] := 434 + end; + putgeterror + end {:404}; + quadrantsubdivide; + if internal[36] > 0 then + xyround; + octantsubdivide; + if internal[36] > 65536 then + diaground; {447:} + p := curspec; + repeat + 22: + q := mem[p].hh.rh; + if p <> q then begin + if mem[p + 1].int = mem[p + 5].int then + if mem[p + 2].int = mem[p + 6].int then + if mem[p + 1].int = mem[q + 3].int then + if mem[p + 2].int = mem[q + 4].int then begin + unskew(mem[q + 1].int, mem[q + 2].int, mem[q].hh.b1); + skew(curx, cury, mem[p].hh.b1); + if mem[p + 1].int = curx then + if mem[p + 2].int = cury then begin + removecubic(p); + if q <> curspec then + goto 22; + curspec := p; + q := p + end + end + end; + p := q + until p = curspec; {:447} {450:} + turningnumber := 0; + p := curspec; + q := mem[p].hh.rh; + repeat + r := mem[q].hh.rh; + if (mem[p].hh.b1 <> mem[q].hh.b1) or (q = r) then begin {452:} + newboundary(p, mem[p].hh.b1); + s := mem[p].hh.rh; + o1 := octantnumber[mem[p].hh.b1]; + o2 := octantnumber[mem[q].hh.b1]; + case o2 - o1 of + 1, -7, 7, -1: + goto 30; + 2, -6: + clockwise := false; + 3, -5, 4, -4, 5, -3: + begin {454:} {457:} + dx1 := mem[s + 1].int - mem[s + 3].int; + dy1 := mem[s + 2].int - mem[s + 4].int; + if dx1 = 0 then + if dy1 = 0 then begin + dx1 := mem[s + 1].int - mem[p + 5].int; + dy1 := mem[s + 2].int - mem[p + 6].int; + if dx1 = 0 then + if dy1 = 0 then begin + dx1 := mem[s + 1].int - mem[p + 1].int; + dy1 := mem[s + 2].int - mem[p + 2].int + end + end; + dmax := abs(dx1); + if abs(dy1) > dmax then + dmax := abs(dy1); + while dmax < 268435456 do begin + dmax := dmax + dmax; + dx1 := dx1 + dx1; + dy1 := dy1 + dy1 + end; + dx2 := mem[q + 5].int - mem[q + 1].int; + dy2 := mem[q + 6].int - mem[q + 2].int; + if dx2 = 0 then + if dy2 = 0 then begin + dx2 := mem[r + 3].int - mem[q + 1].int; + dy2 := mem[r + 4].int - mem[q + 2].int; + if dx2 = 0 then + if dy2 = 0 then begin + if mem[r].hh.b1 = 0 then begin + curx := mem[r + 1].int; + cury := mem[r + 2].int + end else begin + unskew(mem[r + 1].int, mem[r + 2].int, mem[r].hh.b1); + skew(curx, cury, mem[q].hh.b1) + end; + dx2 := curx - mem[q + 1].int; + dy2 := cury - mem[q + 2].int + end + end; + dmax := abs(dx2); + if abs(dy2) > dmax then + dmax := abs(dy2); + while dmax < 268435456 do begin + dmax := dmax + dmax; + dx2 := dx2 + dx2; + dy2 := dy2 + dy2 + end {:457}; + unskew(dx1, dy1, mem[p].hh.b1); + del := pythadd(curx, cury); + dx1 := makefraction(curx, del); + dy1 := makefraction(cury, del); + unskew(dx2, dy2, mem[q].hh.b1); + del := pythadd(curx, cury); + dx2 := makefraction(curx, del); + dy2 := makefraction(cury, del); + del := takefraction(dx1, dy2) - takefraction(dx2, dy1); + if del > 4684844 then + clockwise := false + else if del < (-4684844) then + clockwise := true + else + clockwise := revturns + end; {:454} + 6, -2: + clockwise := true; + 0: + clockwise := revturns + end; {458:} + while true do begin + if clockwise then + if o1 = 1 then + o1 := 8 + else + o1 := o1 - 1 + else if o1 = 8 then + o1 := 1 + else + o1 := o1 + 1; + if o1 = o2 then + goto 30; + newboundary(s, octantcode[o1]); + s := mem[s].hh.rh; + mem[s + 3].int := mem[s + 5].int + end {:458}; + 30: + if q = r then begin + q := mem[q].hh.rh; + r := q; + p := s; + mem[s].hh.rh := q; + mem[q + 3].int := mem[q + 5].int; + mem[q].hh.b0 := 0; + freenode(curspec, 7); + curspec := q + end; {459:} + p := mem[p].hh.rh; + repeat + s := mem[p].hh.rh; + o1 := octantnumber[mem[p + 5].int]; + o2 := octantnumber[mem[s + 3].int]; + if abs(o1 - o2) = 1 then begin + if o2 < o1 then + o2 := o1; + if odd(o2) then + mem[p + 6].int := 0 + else + mem[p + 6].int := 1 + end else begin + if o1 = 8 then + turningnumber := turningnumber + 1 + else + turningnumber := turningnumber - 1; + mem[p + 6].int := 0 + end; + mem[s + 4].int := mem[p + 6].int; + p := s + until p = q {:459} + end {:452}; + p := q; + q := r + until p = curspec; {:450} + while mem[curspec].hh.b0 <> 0 do + curspec := mem[curspec].hh.rh; + if tracing > 0 then + if internal[36] <= 0 then + printspec(427) + else if internal[36] > 65536 then + printspec(428) + else + printspec(429); + makespec := curspec + end; { makespec } +{:402} + {463:} + + procedure endround(x, y: scaled); + begin + y := (y + 32768) - ycorr[octant]; + x := (x + y) - xcorr[octant]; + m1 := floorunscaled(x); + n1 := floorunscaled(y); + if (x - (65536 * m1)) >= ((y - (65536 * n1)) + zcorr[octant]) then + d1 := 1 + else + d1 := 0 + end; {:463} +{465:} + + procedure fillspec(h: halfword); + var + p, q, r, s: halfword; + begin + if internal[10] > 0 then + beginedgetracing; + p := h; + {------------------------------------} + print_start(psfile); { Start cycle } + {------------------------------------} + repeat + octant := mem[p + 3].int; {466:} + q := p; + while mem[q].hh.b1 <> 0 do + q := mem[q].hh.rh {:466}; + if q <> p then begin {467:} + endround(mem[p + 1].int, mem[p + 2].int); + m0 := m1; + n0 := n1; + d0 := d1; + endround(mem[q + 1].int, mem[q + 2].int) {:467}; {468:} + if (n1 - n0) >= movesize then + overflow(407, movesize); + move[0] := d0; + moveptr := 0; + r := p; + repeat + s := mem[r].hh.rh; + makemoves(mem[r + 1].int, mem[r + 5].int, mem[s + 3].int, mem[s + 1].int, mem[r + 2].int + 32768, mem[r + 6].int + 32768, mem[s + 4].int + 32768, mem[s + 2].int + 32768, xycorr[octant], ycorr[octant],465,octant); + r := s + until r = q; + move[moveptr] := move[moveptr] - d1; + if internal[35] > 0 then + smoothmoves(0, moveptr) {:468}; + movetoedges(m0, n0, m1, n1) + end; + p := mem[q].hh.rh + until p = h; + {------------------------------------} + print_end(psfile); { End cycle } + {------------------------------------} + tossknotlist(h); + if internal[10] > 0 then + endedgetracing + end; {:465} {476:} + + procedure dupoffset(w: halfword); + var + r: halfword; + begin + r := getnode(3); + mem[r + 1].int := mem[w + 1].int; + mem[r + 2].int := mem[w + 2].int; + mem[r].hh.rh := mem[w].hh.rh; + mem[mem[w].hh.rh].hh.lh := r; + mem[r].hh.lh := w; + mem[w].hh.rh := r + end; {:476} {477:} + + function makepen(h: halfword): halfword; + label + 30, 31, 45, 40; + var + o, oo, k: smallnumber; + p: halfword; + q, r, s, w, hh: halfword; + n: integer; + dx, dy: scaled; + mc: scaled; {479:} + begin + q := h; + r := mem[q].hh.rh; + mc := abs(mem[h + 1].int); + if q = r then begin + hh := h; + mem[h].hh.b1 := 0; + if mc < abs(mem[h + 2].int) then + mc := abs(mem[h + 2].int) + end else begin + o := 0; + hh := -30000; + while true do begin + s := mem[r].hh.rh; + if mc < abs(mem[r + 1].int) then + mc := abs(mem[r + 1].int); + if mc < abs(mem[r + 2].int) then + mc := abs(mem[r + 2].int); + dx := mem[r + 1].int - mem[q + 1].int; + dy := mem[r + 2].int - mem[q + 2].int; + if dx = 0 then + if dy = 0 then + goto 45; + if abvscd(dx, mem[s + 2].int - mem[r + 2].int, dy, mem[s + 1].int - mem[r + 1].int) < 0 then + goto 45; {480:} + if dx > 0 then + octant := 1 + else if dx = 0 then + if dy > 0 then + octant := 1 + else + octant := 2 + else begin + dx := -dx; + octant := 2 + end; + if dy < 0 then begin + dy := -dy; + octant := octant + 2 + end else if dy = 0 then + if octant > 1 then + octant := 4; + if dx < dy then + octant := octant + 4 {:480}; + mem[q].hh.b1 := octant; + oo := octantnumber[octant]; + if o > oo then begin + if hh <> (-30000) then + goto 45; + hh := q + end; + o := oo; + if (q = h) and (hh <> (-30000)) then + goto 30; + q := r; + r := s + end; + 30: {:479} + + end; + if mc >= 268402688 then + goto 45; + p := getnode(10); + q := hh; + mem[p + 9].int := mc; + mem[p].hh.lh := -30000; + if mem[q].hh.rh <> q then + mem[p].hh.rh := -29999; + for k := 1 to 8 do begin {481:} + octant := octantcode[k]; + n := 0; + h := p + octant; + while true do begin + r := getnode(3); + skew(mem[q + 1].int, mem[q + 2].int, octant); + mem[r + 1].int := curx; + mem[r + 2].int := cury; + if n = 0 then + mem[h].hh.rh := r {482:} + else if odd(k) then begin + mem[w].hh.rh := r; + mem[r].hh.lh := w + end else begin + mem[w].hh.lh := r; + mem[r].hh.rh := w + end {:482}; + w := r; + if mem[q].hh.b1 <> octant then + goto 31; + q := mem[q].hh.rh; + n := n + 1 + end; + 31: {483:} + r := mem[h].hh.rh; + if odd(k) then begin + mem[w].hh.rh := r; + mem[r].hh.lh := w + end else begin + mem[w].hh.lh := r; + mem[r].hh.rh := w; + mem[h].hh.rh := w; + r := w + end; + if (mem[r + 2].int <> mem[mem[r].hh.rh + 2].int) or (n = 0) then begin + dupoffset(r); + n := n + 1 + end; + r := mem[r].hh.lh; + {: + 483} + if mem[r + 1].int <> mem[mem[r].hh.lh + 1].int then + dupoffset(r) + else + n := n - 1; + if n >= 127 then + overflow(446, 127); + mem[h].hh.lh := n + end {:481}; + goto 40; + 45: + p := -29997; {478:} + if mc >= 268402688 then begin + begin + if interaction = 3 then + ; + printnl(133); + print(440) + end; + begin + helpptr := 2; + helpline[1] := 441; + helpline[0] := 442 + end + end else begin + begin + if interaction = 3 then + ; + printnl(133); + print(443) + end; + begin + helpptr := 3; + helpline[2] := 444; + helpline[1] := 445; + helpline[0] := 442 + end + end; {:478} + putgeterror; + 40: + if internal[6] > 0 then + printpen(p, 439, true); + makepen := p + end; {:477} {484:} {486:} + + function trivialknot(x, y: scaled): halfword; + var + p: halfword; + begin + p := getnode(7); + mem[p].hh.b0 := 1; + mem[p].hh.b1 := 1; + mem[p + 1].int := x; + mem[p + 3].int := x; + mem[p + 5].int := x; + mem[p + 2].int := y; + mem[p + 4].int := y; + mem[p + 6].int := y; + trivialknot := p + end; {:486} + + function makepath(penhead: halfword): halfword; + var + p: halfword; + k: 1..8; + h: halfword; + m, n: integer; + w, ww: halfword; + begin + p := 29999; + for k := 1 to 8 do begin + octant := octantcode[k]; + h := penhead + octant; + n := mem[h].hh.lh; + w := mem[h].hh.rh; + if not odd(k) then + w := mem[w].hh.lh; + for m := 1 to n + 1 do begin + if odd(k) then + ww := mem[w].hh.rh + else + ww := mem[w].hh.lh; + if (mem[ww + 1].int <> mem[w + 1].int) or (mem[ww + 2].int <> mem[w + 2].int) then begin {485:} + unskew(mem[ww + 1].int, mem[ww + 2].int, octant); + mem[p].hh.rh := trivialknot(curx, cury); + p := mem[p].hh.rh + end {:485}; + w := ww + end + end; + if p = 29999 then begin + w := mem[penhead + 1].hh.rh; + p := trivialknot(mem[w + 1].int + mem[w + 2].int, mem[w + 2].int); + mem[29999].hh.rh := p + end; + mem[p].hh.rh := mem[29999].hh.rh; + makepath := mem[29999].hh.rh + end; {:484} {488:} + + procedure findoffset(x, y: scaled; p: halfword); + label + 30, 10; + var + octant: 1..8; + s: -1..+1; + n: integer; + h, w, ww: halfword; {489:} + begin + if x > 0 then + octant := 1 + else if x = 0 then + if y <= 0 then + if y = 0 then begin + curx := 0; + cury := 0; + goto 10 + end else + octant := 2 + else + octant := 1 + else begin + x := -x; + if y = 0 then + octant := 4 + else + octant := 2 + end; + if y < 0 then begin + octant := octant + 2; + y := -y + end; + if x >= y then + x := x - y + else begin + octant := octant + 4; + x := y - x; + y := y - x + end {:489}; + if odd(octantnumber[octant]) then + s := -1 + else + s := +1; + h := p + octant; + w := mem[mem[h].hh.rh].hh.rh; + ww := mem[w].hh.rh; + n := mem[h].hh.lh; + while n > 1 do begin + if abvscd(x, mem[ww + 2].int - mem[w + 2].int, y, mem[ww + 1].int - mem[w + 1].int) <> s then + goto 30; + w := ww; + ww := mem[w].hh.rh; + n := n - 1 + end; + 30: + unskew(mem[w + 1].int, mem[w + 2].int, octant); + 10: + + end; {:488} {491:} {493:} + + procedure splitforoffset(p: halfword; t: fraction); + var + q: halfword; + r: halfword; + begin + q := mem[p].hh.rh; + splitcubic(p, t, mem[q + 1].int, mem[q + 2].int); + r := mem[p].hh.rh; + if mem[r + 2].int < mem[p + 2].int then + mem[r + 2].int := mem[p + 2].int + else if mem[r + 2].int > mem[q + 2].int then + mem[r + 2].int := mem[q + 2].int; + if mem[r + 1].int < mem[p + 1].int then + mem[r + 1].int := mem[p + 1].int + else if mem[r + 1].int > mem[q + 1].int then + mem[r + 1].int := mem[q + 1].int + end; {:493} {497:} + + procedure finoffsetprep(p: halfword; k: halfword; w: halfword; x0, x1, x2, y0, y1, y2: integer; rising: boolean; n: integer); + label + 10; + var + q, ww: halfword; + du, dv: scaled; + t0, t1, t2: integer; + t: fraction; + s: fraction; + v: integer; + begin + while true do begin + q := mem[p].hh.rh; + mem[p].hh.b1 := k; + if rising then + if k = n then + goto 10 + else + ww := mem[w].hh.rh + else if k = 1 then + goto 10 + else + ww := mem[w].hh.lh; {498:} + du := mem[ww + 1].int - mem[w + 1].int; + dv := mem[ww + 2].int - mem[w + 2].int; + if abs(du) >= abs(dv) then begin + s := makefraction(dv, du); + t0 := takefraction(x0, s) - y0; + t1 := takefraction(x1, s) - y1; + t2 := takefraction(x2, s) - y2 + end else begin + s := makefraction(du, dv); + t0 := x0 - takefraction(y0, s); + t1 := x1 - takefraction(y1, s); + t2 := x2 - takefraction(y2, s) + end {:498}; + t := crossingpoint(t0, t1, t2); + if t >= 268435456 then + goto 10; {499:} + begin + splitforoffset(p, t); + mem[p].hh.b1 := k; + p := mem[p].hh.rh; + v := x0 - takefraction(x0 - x1, t); + x1 := x1 - takefraction(x1 - x2, t); + x0 := v - takefraction(v - x1, t); + v := y0 - takefraction(y0 - y1, t); + y1 := y1 - takefraction(y1 - y2, t); + y0 := v - takefraction(v - y1, t); + t1 := t1 - takefraction(t1 - t2, t); + if t1 > 0 then + t1 := 0; + t := crossingpoint(0, -t1, -t2); + if t < 268435456 then begin + splitforoffset(p, t); + mem[mem[p].hh.rh].hh.b1 := k; + v := x1 - takefraction(x1 - x2, t); + x1 := x0 - takefraction(x0 - x1, t); + x2 := x1 - takefraction(x1 - v, t); + v := y1 - takefraction(y1 - y2, t); + y1 := y0 - takefraction(y0 - y1, t); + y2 := y1 - takefraction(y1 - v, t) + end + end {:499}; + if rising then + k := k + 1 + else + k := k - 1; + w := ww + end; + 10: + + end; {:497} + + procedure offsetprep(c, h: halfword); + label + 30, 45; + var + n: halfword; + p, q, r, lh, ww: halfword; + k: halfword; + w: halfword; {495:} + x0, x1, x2, y0, y1, y2: integer; + t0, t1, t2: integer; + du, dv, dx, dy: integer; + maxcoef: integer; + x0a, x1a, x2a, y0a, y1a, y2a: integer; + t: fraction; + s: fraction; +{:495} + begin + p := c; + n := mem[h].hh.lh; + lh := mem[h].hh.rh; + while mem[p].hh.b1 <> 0 do begin + q := mem[p].hh.rh; {494:} + if n <= 1 then + mem[p].hh.b1 := 1 + else begin {496:} + x0 := mem[p + 5].int - mem[p + 1].int; + x2 := mem[q + 1].int - mem[q + 3].int; + x1 := mem[q + 3].int - mem[p + 5].int; + y0 := mem[p + 6].int - mem[p + 2].int; + y2 := mem[q + 2].int - mem[q + 4].int; + y1 := mem[q + 4].int - mem[p + 6].int; + maxcoef := abs(x0); + if abs(x1) > maxcoef then + maxcoef := abs(x1); + if abs(x2) > maxcoef then + maxcoef := abs(x2); + if abs(y0) > maxcoef then + maxcoef := abs(y0); + if abs(y1) > maxcoef then + maxcoef := abs(y1); + if abs(y2) > maxcoef then + maxcoef := abs(y2); + if maxcoef = 0 then + goto 45; + while maxcoef < 268435456 do begin + maxcoef := maxcoef + maxcoef; + x0 := x0 + x0; + x1 := x1 + x1; + x2 := x2 + x2; + y0 := y0 + y0; + y1 := y1 + y1; + y2 := y2 + y2 + end {:496}; {501:} + dx := x0; + dy := y0; + if dx = 0 then + if dy = 0 then begin + dx := x1; + dy := y1; + if dx = 0 then + if dy = 0 then begin + dx := x2; + dy := y2 + end + end {:501}; + if dx = 0 then {505:} + finoffsetprep(p, n, mem[mem[lh].hh.lh].hh.lh, -x0, -x1, -x2, -y0, -y1, -y2, false, n) {:505} + else begin {502:} + k := 1; + w := mem[lh].hh.rh; + while true do begin + if k = n then + goto 30; + ww := mem[w].hh.rh; + if abvscd(dy, abs(mem[ww + 1].int - mem[w + 1].int), dx, abs(mem[ww + 2].int - mem[w + 2].int)) >= 0 then begin + k := k + 1; + w := ww + end else + goto 30 + end; + 30: {:502} + ; +{503:} + if k = 1 then + t := 268435457 + else begin + ww := mem[w].hh.lh; {498:} + du := mem[ww + 1].int - mem[w + 1].int; + dv := mem[ww + 2].int - mem[w + 2].int; + if abs(du) >= abs(dv) then begin + s := makefraction(dv, du); + t0 := takefraction(x0, s) - y0; + t1 := takefraction(x1, s) - y1; + t2 := takefraction(x2, s) - y2 + end else begin + s := makefraction(du, dv); + t0 := x0 - takefraction(y0, s); + t1 := x1 - takefraction(y1, s); + t2 := x2 - takefraction(y2, s) + end {:498}; + t := crossingpoint(-t0, -t1, -t2) + end; + if t >= 268435456 then + finoffsetprep(p, k, w, x0, x1, x2, y0, y1, y2, true, n) + else begin + splitforoffset(p, t); + r := mem[p].hh.rh; + x1a := x0 - takefraction(x0 - x1, t); + x1 := x1 - takefraction(x1 - x2, t); + x2a := x1a - takefraction(x1a - x1, t); + y1a := y0 - takefraction(y0 - y1, t); + y1 := y1 - takefraction(y1 - y2, t); + y2a := y1a - takefraction(y1a - y1, t); + finoffsetprep(p, k, w, x0, x1a, x2a, y0, y1a, y2a, true, n); + x0 := x2a; + y0 := y2a; + t1 := t1 - takefraction(t1 - t2, t); + if t1 < 0 then + t1 := 0; + t := crossingpoint(0, t1, t2); + if t < 268435456 then begin {504:} + splitforoffset(r, t); + x1a := x1 - takefraction(x1 - x2, t); + x1 := x0 - takefraction(x0 - x1, t); + x0a := x1 - takefraction(x1 - x1a, t); + y1a := y1 - takefraction(y1 - y2, t); + y1 := y0 - takefraction(y0 - y1, t); + y0a := y1 - takefraction(y1 - y1a, t); + finoffsetprep(mem[r].hh.rh, k, w, x0a, x1a, x2, y0a, y1a, y2, true, n); + x2 := x0a; + y2 := y0a + end {:504}; + finoffsetprep(r, k - 1, ww, -x0, -x1, -x2, -y0, -y1, -y2, false, n) + end {:503} + end; + 45: {:494} + + end; {492:} + repeat + r := mem[p].hh.rh; + if mem[p + 1].int = mem[p + 5].int then + if mem[p + 2].int = mem[p + 6].int then + if mem[p + 1].int = mem[r + 3].int then + if mem[p + 2].int = mem[r + 4].int then + if mem[p + 1].int = mem[r + 1].int then + if mem[p + 2].int = mem[r + 2].int then begin + removecubic(p); + if r = q then + q := p; + r := p + end; + p := r + until p = q {:492} + end + end; { offsetprep } +{:491} + {506:} + {510:} + + procedure skewlineedges(p, w, ww: halfword); + var + x0, y0, x1, y1: scaled; + begin + if (mem[w + 1].int <> mem[ww + 1].int) or (mem[w + 2].int <> mem[ww + 2].int) then begin + x0 := mem[p + 1].int + mem[w + 1].int; + y0 := mem[p + 2].int + mem[w + 2].int; + x1 := mem[p + 1].int + mem[ww + 1].int; + y1 := mem[p + 2].int + mem[ww + 2].int; + {-------------------------------------} + sendline(x0,y0,x1,y1,octant,510); + {-------------------------------------} + unskew(x0, y0, octant); + x0 := curx; + y0 := cury; + unskew(x1, y1, octant); +{if internal[10]>65536 then begin printnl(451);printtwo(x0,y0); +print(450);printtwo(curx,cury);printnl(155);end;} + lineedges(x0, y0, curx, cury) + end + end; {:510} {518:} + + procedure dualmoves(h, p, q: halfword); + label + 30, 31; + var + r, s: halfword; {511:} + m, n: integer; + mm0, mm1: integer; + k: integer; + w, ww: halfword; + smoothbot, smoothtop: 0..movesize; + xx, yy, xp, yp, delx, dely, tx, ty: scaled; +{:511} {519:} + begin + k := mem[h].hh.lh + 1; + ww := mem[h].hh.rh; + w := mem[ww].hh.lh; + mm0 := floorunscaled((mem[p + 1].int + mem[w + 1].int) - xycorr[octant]); + mm1 := floorunscaled((mem[q + 1].int + mem[ww + 1].int) - xycorr[octant]); + for n := 1 to (n1 - n0) + 1 do + envmove[n] := mm1; + envmove[0] := mm0; + moveptr := 0; + m := mm0 {:519}; + r := p; + while true do begin + if r = q then + smoothtop := moveptr; + while mem[r].hh.b1 <> k do begin {521:} + xx := mem[r + 1].int + mem[w + 1].int; + yy := (mem[r + 2].int + mem[w + 2].int) + 32768; +{if internal[10]>65536 then begin printnl(452);printint(k);print(453); +unskew(xx,yy-32768,octant);printtwo(curx,cury);end;} + {------------} + my_xx := xx; + my_yy := yy; + {------------} + if mem[r].hh.b1 < k then begin + k := k - 1; + w := mem[w].hh.lh; + xp := mem[r + 1].int + mem[w + 1].int; + yp := (mem[r + 2].int + mem[w + 2].int) + 32768; + if yp <> yy then begin {522:} + ty := floorscaled(yy - ycorr[octant]); + dely := yp - yy; + yy := yy - ty; + ty := (yp - ycorr[octant]) - ty; + if ty >= 65536 then begin + delx := xp - xx; + yy := 65536 - yy; + while true do begin + if m < envmove[moveptr] then + envmove[moveptr] := m; + tx := takefraction(delx, makefraction(yy, dely)); + if (abvscd(tx, dely, delx, yy) + xycorr[octant]) > 0 then + tx := tx - 1; + m := floorunscaled(xx + tx); + ty := ty - 65536; + moveptr := moveptr + 1; + if ty < 65536 then + goto 31; + yy := yy + 65536 + end; + 31: + if m < envmove[moveptr] then + envmove[moveptr] := m + end + end {:522} + end else begin + k := k + 1; + w := mem[w].hh.rh; + xp := mem[r + 1].int + mem[w + 1].int; + yp := (mem[r + 2].int + mem[w + 2].int) + 32768; + end; +{if internal[10]>65536 then begin print(450);unskew(xp,yp-32768,octant); +printtwo(curx,cury);printnl(155);end;} + {---------------------------------------------------} + sendline(my_xx,my_yy-32768,xp,yp-32768,octant,521); + {---------------------------------------------------} + m := floorunscaled(xp - xycorr[octant]); + moveptr := floorunscaled(yp - ycorr[octant]) - n0; + if m < envmove[moveptr] then + envmove[moveptr] := m + end {:521}; + if r = p then + smoothbot := moveptr; + if r = q then + goto 30; + move[moveptr] := 1; + n := moveptr; + s := mem[r].hh.rh; + makemoves(mem[r + 1].int + mem[w + 1].int, mem[r + 5].int + mem[w + 1].int, mem[s + 3].int + mem[w + 1].int, mem[s + 1].int + mem[w + 1].int, (mem[r + 2].int + mem[w + 2].int) + 32768, (mem[r + 6].int + mem[w + 2].int) + 32768, (mem[s + 4].int + mem[w + 2].int) + 32768, (mem[s + 2].int + mem[w + 2].int) + 32768, xycorr[octant], ycorr[octant],518,octant); {520:} + repeat + if m < envmove[n] then + envmove[n] := m; + m := (m + move[n]) - 1; + n := n + 1 + until n > moveptr {:520}; + r := s + end; + 30: {523:} +{if(m<>mm1)or(moveptr<>n1-n0)then confusion(50);} + move[0] := (d0 + envmove[1]) - mm0; + for n := 1 to moveptr do + move[n] := (envmove[n + 1] - envmove[n]) + 1; + move[moveptr] := move[moveptr] - d1; + if internal[35] > 0 then + smoothmoves(smoothbot, smoothtop); + movetoedges(m0, n0, m1, n1); + if mem[q + 6].int = 1 then begin + w := mem[h].hh.rh; + skewlineedges(q, w, mem[w].hh.lh) + end {:523} + end; {:518} + + procedure fillenvelope(spechead: halfword); + label + 30, 31; + var + p, q, r, s: halfword; + h: halfword; + www: halfword; {511:} + m, n: integer; + mm0, mm1: integer; + k: integer; + w, ww: halfword; + smoothbot, smoothtop: 0..movesize; + xx, yy, xp, yp, delx, dely, tx, ty: scaled; {:511} + begin + if internal[10] > 0 then + beginedgetracing; + {------------------------------------} + print_start(psfile); { Start cycle } + {------------------------------------} + p := spechead; + repeat + octant := mem[p + 3].int; + h := curpen + octant; {466:} + q := p; + while mem[q].hh.b1 <> 0 do + q := mem[q].hh.rh {:466}; {508:} + w := mem[h].hh.rh; + if mem[p + 4].int = 1 then + w := mem[w].hh.lh; +{if internal[10]>65536 then[509:]begin printnl(447); +print(octantdir[octant]);print(425);printint(mem[h].hh.lh);print(448); +if mem[h].hh.lh<>1 then printchar(115);print(449); +unskew(mem[p+1].int+mem[w+1].int,mem[p+2].int+mem[w+2].int,octant); +printtwo(curx,cury);ww:=mem[h].hh.rh; +if mem[q+6].int=1 then ww:=mem[ww].hh.lh;print(450); +unskew(mem[q+1].int+mem[ww+1].int,mem[q+2].int+mem[ww+2].int,octant); +printtwo(curx,cury);end[:509];} + ww := mem[h].hh.rh; + www := ww; + if odd(octantnumber[octant]) then + www := mem[www].hh.lh + else + ww := mem[ww].hh.lh; + if w <> ww then + skewlineedges(p, w, ww); + endround(mem[p + 1].int + mem[ww + 1].int, mem[p + 2].int + mem[ww + 2].int); + m0 := m1; + n0 := n1; + d0 := d1; + endround(mem[q + 1].int + mem[www + 1].int, mem[q + 2].int + mem[www + 2].int); + if (n1 - n0) >= movesize then + overflow(407, movesize) {:508}; + offsetprep(p, h); +{466:} + q := p; + while mem[q].hh.b1 <> 0 do + q := mem[q].hh.rh {:466}; {512:} + if odd(octantnumber[octant]) then begin {513:} + k := 0; + w := mem[h].hh.rh; + ww := mem[w].hh.lh; + mm0 := floorunscaled((mem[p + 1].int + mem[w + 1].int) - xycorr[octant]); + mm1 := floorunscaled((mem[q + 1].int + mem[ww + 1].int) - xycorr[octant]); + for n := 0 to n1 - n0 do + envmove[n] := mm0; + envmove[n1 - n0] := mm1; + moveptr := 0; + m := mm0 {:513}; + r := p; + mem[q].hh.b1 := mem[h].hh.lh + 1; + while true do begin + if r = q then + smoothtop := moveptr; + while mem[r].hh.b1 <> k do begin {515:} + xx := mem[r + 1].int + mem[w + 1].int; + yy := (mem[r + 2].int + mem[w + 2].int) + 32768; +{if internal[10]>65536 then begin printnl(452);printint(k);print(453); +unskew(xx,yy-32768,octant);printtwo(curx,cury);end;} + {------------} + my_xx := xx; + my_yy := yy; + {------------} + if mem[r].hh.b1 > k then begin + k := k + 1; + w := mem[w].hh.rh; + xp := mem[r + 1].int + mem[w + 1].int; + yp := (mem[r + 2].int + mem[w + 2].int) + 32768; + if yp <> yy then begin {516:} + ty := floorscaled(yy - ycorr[octant]); + dely := yp - yy; + yy := yy - ty; + ty := (yp - ycorr[octant]) - ty; + if ty >= 65536 then begin + delx := xp - xx; + yy := 65536 - yy; + while true do begin + tx := takefraction(delx, makefraction(yy, dely)); + if (abvscd(tx, dely, delx, yy) + xycorr[octant]) > 0 then + tx := tx - 1; + m := floorunscaled(xx + tx); + if m > envmove[moveptr] then + envmove[moveptr] := m; + ty := ty - 65536; + if ty < 65536 then + goto 31; + yy := yy + 65536; + moveptr := moveptr + 1 + end; + 31: + + end + end {:516} + end else begin + k := k - 1; + w := mem[w].hh.lh; + xp := mem[r + 1].int + mem[w + 1].int; + yp := (mem[r + 2].int + mem[w + 2].int) + 32768; + end; +{if internal[10]>65536 then begin print(450);unskew(xp,yp-32768,octant); +printtwo(curx,cury);printnl(155);end;} + {---------------------------------------------------} + sendline(my_xx,my_yy-32768,xp,yp-32768,octant,515); + {---------------------------------------------------} + m := floorunscaled(xp - xycorr[octant]); + moveptr := floorunscaled(yp - ycorr[octant]) - n0; + if m > envmove[moveptr] then + envmove[moveptr] := m + end {:515}; + if r = p then + smoothbot := moveptr; + if r = q then + goto 30; + move[moveptr] := 1; + n := moveptr; + s := mem[r].hh.rh; + makemoves(mem[r + 1].int + mem[w + 1].int, mem[r + 5].int + mem[w + 1].int, mem[s + 3].int + mem[w + 1].int, mem[s + 1].int + mem[w + 1].int, (mem[r + 2].int + mem[w + 2].int) + 32768, (mem[r + 6].int + mem[w + 2].int) + 32768, (mem[s + 4].int + mem[w + 2].int) + 32768, (mem[s + 2].int + mem[w + 2].int) + 32768, xycorr[octant], ycorr[octant],512,octant); {514:} + repeat + m := (m + move[n]) - 1; + if m > envmove[n] then + envmove[n] := m; + n := n + 1 + until n > moveptr {:514}; + r := s + end; + 30: {517:} +{if(m<>mm1)or(moveptr<>n1-n0)then confusion(49);} + move[0] := (d0 + envmove[0]) - mm0; + for n := 1 to moveptr do + move[n] := (envmove[n] - envmove[n - 1]) + 1; + move[moveptr] := move[moveptr] - d1; + if internal[35] > 0 then + smoothmoves(smoothbot, smoothtop); + movetoedges(m0, n0, m1, n1); + if mem[q + 6].int = 0 then begin + w := mem[h].hh.rh; + skewlineedges(q, mem[w].hh.lh, w) + end {:517} + end else + dualmoves(h, p, q); + mem[q].hh.b1 := 0 {:512}; + p := mem[q].hh.rh + until p = spechead; + {------------------------------------} + print_end(psfile); { End cycle } + {------------------------------------} + if internal[10] > 0 then + endedgetracing; + tossknotlist(spechead) + end; {:506} +{527:} + + function makeellipse(majoraxis, minoraxis: scaled; theta: angle): halfword; + label + 30, 31, 40; + var + p, q, r, s: halfword; + h: halfword; + alpha, beta, gamma, delta: integer; + c, d: integer; + u, v: integer; + symmetric: boolean; {528:} + begin {530:} + if (majoraxis = minoraxis) or ((theta mod 94371840) = 0) then begin + symmetric := true; + alpha := 0; + if odd(theta div 94371840) then begin + beta := majoraxis; + gamma := minoraxis; + nsin := 268435456; + ncos := 0 + end else begin + beta := minoraxis; + gamma := majoraxis + end + end else begin + symmetric := false; + nsincos(theta); + gamma := takefraction(majoraxis, nsin); + delta := takefraction(minoraxis, ncos); + beta := pythadd(gamma, delta); + alpha := takefraction(takefraction(majoraxis, makefraction(gamma, beta)), ncos) - takefraction(takefraction(minoraxis, makefraction(delta, beta)), nsin); + alpha := (alpha + 32768) div 65536; + gamma := pythadd(takefraction(majoraxis, ncos), takefraction(minoraxis, nsin)) + end; + beta := (beta + 32768) div 65536; + gamma := (gamma + 32768) div 65536 {:530}; + p := getnode(7); + q := getnode(7); + r := getnode(7); + if symmetric then + s := -30000 + else + s := getnode(7); + h := p; + mem[p].hh.rh := q; + mem[q].hh.rh := r; + mem[r].hh.rh := s; {529:} + if beta = 0 then + beta := 1; + if gamma = 0 then + gamma := 1; + if gamma <= abs(alpha) then + if alpha > 0 then + alpha := gamma - 1 + else + alpha := 1 - gamma {:529}; + mem[p + 1].int := -(alpha * 32768); + mem[p + 2].int := -(beta * 32768); + mem[q + 1].int := gamma * 32768; + mem[q + 2].int := mem[p + 2].int; + mem[r + 1].int := mem[q + 1].int; + mem[p + 5].int := 0; + mem[q + 3].int := -32768; + mem[q + 5].int := 32768; + mem[r + 3].int := 0; + mem[r + 5].int := 0; + mem[p + 6].int := beta; + mem[q + 6].int := gamma; + mem[r + 6].int := beta; + mem[q + 4].int := gamma + alpha; + if symmetric then begin + mem[r + 2].int := 0; + mem[r + 4].int := beta + end else begin + mem[r + 2].int := -mem[p + 2].int; + mem[r + 4].int := beta + beta; + mem[s + 1].int := -mem[p + 1].int; + mem[s + 2].int := mem[r + 2].int; + mem[s + 3].int := 32768; + mem[s + 4].int := gamma - alpha + end {:528}; {531:} + while true do begin + u := mem[p + 5].int + mem[q + 5].int; + v := mem[q + 3].int + mem[r + 3].int; + c := mem[p + 6].int + mem[q + 6].int; {533:} + delta := pythadd(u, v); + if majoraxis = minoraxis then + d := majoraxis + else begin + if theta = 0 then begin + alpha := u; + beta := v + end else begin + alpha := takefraction(u, ncos) + takefraction(v, nsin); + beta := takefraction(v, ncos) - takefraction(u, nsin) + end; + alpha := makefraction(alpha, delta); + beta := makefraction(beta, delta); + d := pythadd(takefraction(majoraxis, alpha), takefraction(minoraxis, beta)) + end; + d := takefraction(d, delta); + alpha := abs(u); + beta := abs(v); + if alpha < beta then begin + delta := alpha; + alpha := beta; + beta := delta + end; + if internal[38] <> 0 then + d := d - takefraction(internal[38], beta + beta); + d := (d + 4) div 8; + alpha := alpha div 32768; + if d < alpha then + d := alpha {:533}; + delta := c - d; + if delta > 0 then begin + if delta > mem[r + 4].int then + delta := mem[r + 4].int; + if delta >= mem[q + 4].int then begin {534:} + delta := mem[q + 4].int; + mem[p + 6].int := c - delta; + mem[p + 5].int := u; + mem[q + 3].int := v; + mem[q + 1].int := mem[q + 1].int - (delta * mem[r + 3].int); + mem[q + 2].int := mem[q + 2].int + (delta * mem[q + 5].int); + mem[r + 4].int := mem[r + 4].int - delta + end else begin {:534} {535:} + s := getnode(7); + mem[p].hh.rh := s; + mem[s].hh.rh := q; + mem[s + 1].int := mem[q + 1].int + (delta * mem[q + 3].int); + mem[s + 2].int := mem[q + 2].int - (delta * mem[p + 5].int); + mem[q + 1].int := mem[q + 1].int - (delta * mem[r + 3].int); + mem[q + 2].int := mem[q + 2].int + (delta * mem[q + 5].int); + mem[s + 3].int := mem[q + 3].int; + mem[s + 5].int := u; + mem[q + 3].int := v; + mem[s + 6].int := c - delta; + mem[s + 4].int := mem[q + 4].int - delta; + mem[q + 4].int := delta; + mem[r + 4].int := mem[r + 4].int - delta + end {:535} + end else + p := q; {532:} + while true do begin + q := mem[p].hh.rh; + if q = (-30000) then + goto 30; + if mem[q + 4].int = 0 then begin + mem[p].hh.rh := mem[q].hh.rh; + mem[p + 6].int := mem[q + 6].int; + mem[p + 5].int := mem[q + 5].int; + freenode(q, 7) + end else begin + r := mem[q].hh.rh; + if r = (-30000) then + goto 30; + if mem[r + 4].int = 0 then begin + mem[p].hh.rh := r; + freenode(q, 7); + p := r + end else + goto 40 + end + end; + 40: {:532} + + end; + 30: {:531} + ; + if symmetric then begin {536:} + s := -30000; + q := h; + while true do begin + r := getnode(7); + mem[r].hh.rh := s; + s := r; + mem[s + 1].int := mem[q + 1].int; + mem[s + 2].int := -mem[q + 2].int; + if q = p then + goto 31; + q := mem[q].hh.rh; + if mem[q + 2].int = 0 then + goto 31 + end; + 31: + mem[p].hh.rh := s; + beta := -mem[h + 2].int; + while mem[p + 2].int <> beta do + p := mem[p].hh.rh; + q := mem[p].hh.rh + end {:536}; +{537:} + if q <> (-30000) then begin + if mem[h + 5].int = 0 then begin + p := h; + h := mem[h].hh.rh; + freenode(p, 7); + mem[q + 1].int := -mem[h + 1].int + end; + p := q + end else + q := p; + r := mem[h].hh.rh; + repeat + s := getnode(7); + mem[p].hh.rh := s; + p := s; + mem[p + 1].int := -mem[r + 1].int; + mem[p + 2].int := -mem[r + 2].int; + r := mem[r].hh.rh + until r = q; + mem[p].hh.rh := h {:537}; + makeellipse := h + end; {:527} {539:} + + function finddirectiontime(x, y: scaled; h: halfword): scaled; + label + 10, 40, 45, 30; + var + max: scaled; + p, q: halfword; + n: scaled; + tt: scaled; {542:} + x1, x2, x3, y1, y2, y3: scaled; + theta, phi: angle; + t: fraction; {:542} {540:} + begin + if abs(x) < abs(y) then begin + x := makefraction(x, abs(y)); + if y > 0 then + y := 268435456 + else + y := -268435456 + end else if x = 0 then begin + finddirectiontime := 0; + goto 10 + end else begin + y := makefraction(y, abs(x)); + if x > 0 then + x := 268435456 + else + x := -268435456 + end {:540}; + n := 0; + p := h; + while true do begin + if mem[p].hh.b1 = 0 then + goto 45; + q := mem[p].hh.rh; +{541:} + tt := 0; {543:} + x1 := mem[p + 5].int - mem[p + 1].int; + x2 := mem[q + 3].int - mem[p + 5].int; + x3 := mem[q + 1].int - mem[q + 3].int; + y1 := mem[p + 6].int - mem[p + 2].int; + y2 := mem[q + 4].int - mem[p + 6].int; + y3 := mem[q + 2].int - mem[q + 4].int; + max := abs(x1); + if abs(x2) > max then + max := abs(x2); + if abs(x3) > max then + max := abs(x3); + if abs(y1) > max then + max := abs(y1); + if abs(y2) > max then + max := abs(y2); + if abs(y3) > max then + max := abs(y3); + if max = 0 then + goto 40; + while max < 134217728 do begin + max := max + max; + x1 := x1 + x1; + x2 := x2 + x2; + x3 := x3 + x3; + y1 := y1 + y1; + y2 := y2 + y2; + y3 := y3 + y3 + end; + t := x1; + x1 := takefraction(x1, x) + takefraction(y1, y); + y1 := takefraction(y1, x) - takefraction(t, y); + t := x2; + x2 := takefraction(x2, x) + takefraction(y2, y); + y2 := takefraction(y2, x) - takefraction(t, y); + t := x3; + x3 := takefraction(x3, x) + takefraction(y3, y); + y3 := takefraction(y3, x) - takefraction(t, y) {:543}; + if y1 = 0 then + if x1 >= 0 then + goto 40; + if n > 0 then begin {544:} + theta := narg(x1, y1); + if theta >= 0 then + if phi <= 0 then + if phi >= (theta - 188743680) then + goto 40; + {: + 544} + if theta <= 0 then + if phi >= 0 then + if phi <= (theta + 188743680) then + goto 40; + if p = h then + goto 45 + end; + if (x3 <> 0) or (y3 <> 0) then + phi := narg(x3, y3); +{546:} + if x1 < 0 then + if x2 < 0 then + if x3 < 0 then + goto 30; + if abvscd(y1, y3, y2, y2) = 0 then begin {548:} + if abvscd(y1, y2, 0, 0) < 0 then begin + t := makefraction(y1, y1 - y2); + x1 := x1 - takefraction(x1 - x2, t); + x2 := x2 - takefraction(x2 - x3, t); + if (x1 - takefraction(x1 - x2, t)) >= 0 then begin + tt := (t + 2048) div 4096; + goto 40 + end + end else if y3 = 0 then + if y1 = 0 then begin {549:} + t := crossingpoint(-x1, -x2, -x3); + if t <= 268435456 then begin + tt := (t + 2048) div 4096; + goto 40 + end; + if abvscd(x1, x3, x2, x2) <= 0 then begin + t := makefraction(x1, x1 - x2); + begin + tt := (t + 2048) div 4096; + goto 40 + end + end + end else if x3 >= 0 then begin {:549} + tt := 65536; + goto 40 + end; + goto 30 + end {:548}; + if y1 <= 0 then + if y1 < 0 then begin + y1 := -y1; + y2 := -y2; + y3 := -y3 + end else if y2 > 0 then begin + y2 := -y2; + y3 := -y3 + end; {547:} + t := crossingpoint(y1, y2, y3); + if t > 268435456 then + goto 30; + y2 := y2 - takefraction(y2 - y3, t); + x1 := x1 - takefraction(x1 - x2, t); + x2 := x2 - takefraction(x2 - x3, t); + x1 := x1 - takefraction(x1 - x2, t); + if x1 >= 0 then begin + tt := (t + 2048) div 4096; + goto 40 + end; + if y2 > 0 then + y2 := 0; + tt := t; + t := crossingpoint(0, -y2, -y3); + if t > 268435456 then + goto 30; + x1 := x1 - takefraction(x1 - x2, t); + x2 := x2 - takefraction(x2 - x3, t); + if (x1 - takefraction(x1 - x2, t)) >= 0 then begin + t := tt - takefraction(tt - 268435456, t); + begin + tt := (t + 2048) div 4096; + goto 40 + end + end {:547}; + 30: {:546} +{:541} + ; + p := q; + n := n + 65536 + end; + 45: + finddirectiontime := -65536; + goto 10; + 40: + finddirectiontime := n + tt; + 10: + + end; {:539} {556:} + + procedure cubicintersection(p, pp: halfword); + label + 22, 45, 10; + var + q, qq: halfword; + begin + timetogo := 5000; + maxt := 2; {558:} + q := mem[p].hh.rh; + qq := mem[pp].hh.rh; + bisectptr := 20; + bisectstack[bisectptr - 5] := mem[p + 5].int - mem[p + 1].int; + bisectstack[bisectptr - 4] := mem[q + 3].int - mem[p + 5].int; + bisectstack[bisectptr - 3] := mem[q + 1].int - mem[q + 3].int; + if bisectstack[bisectptr - 5] < 0 then + if bisectstack[bisectptr - 3] >= 0 then begin + if bisectstack[bisectptr - 4] < 0 then + bisectstack[bisectptr - 2] := bisectstack[bisectptr - 5] + bisectstack[bisectptr - 4] + else + bisectstack[bisectptr - 2] := bisectstack[bisectptr - 5]; + bisectstack[bisectptr - 1] := (bisectstack[bisectptr - 5] + bisectstack[bisectptr - 4]) + bisectstack[bisectptr - 3]; + if bisectstack[bisectptr - 1] < 0 then + bisectstack[bisectptr - 1] := 0 + end else begin + bisectstack[bisectptr - 2] := (bisectstack[bisectptr - 5] + bisectstack[bisectptr - 4]) + bisectstack[bisectptr - 3]; + if bisectstack[bisectptr - 2] > bisectstack[bisectptr - 5] then + bisectstack[bisectptr - 2] := bisectstack[bisectptr - 5]; + bisectstack[bisectptr - 1] := bisectstack[bisectptr - 5] + bisectstack[bisectptr - 4]; + if bisectstack[bisectptr - 1] < 0 then + bisectstack[bisectptr - 1] := 0 + end + else if bisectstack[bisectptr - 3] <= 0 then begin + if bisectstack[bisectptr - 4] > 0 then + bisectstack[bisectptr - 1] := bisectstack[bisectptr - 5] + bisectstack[bisectptr - 4] + else + bisectstack[bisectptr - 1] := bisectstack[bisectptr - 5]; + bisectstack[bisectptr - 2] := (bisectstack[bisectptr - 5] + bisectstack[bisectptr - 4]) + bisectstack[bisectptr - 3]; + if bisectstack[bisectptr - 2] > 0 then + bisectstack[bisectptr - 2] := 0 + end else begin + bisectstack[bisectptr - 1] := (bisectstack[bisectptr - 5] + bisectstack[bisectptr - 4]) + bisectstack[bisectptr - 3]; + if bisectstack[bisectptr - 1] < bisectstack[bisectptr - 5] then + bisectstack[bisectptr - 1] := bisectstack[bisectptr - 5]; + bisectstack[bisectptr - 2] := bisectstack[bisectptr - 5] + bisectstack[bisectptr - 4]; + if bisectstack[bisectptr - 2] > 0 then + bisectstack[bisectptr - 2] := 0 + end; + bisectstack[bisectptr - 10] := mem[p + 6].int - mem[p + 2].int; + bisectstack[bisectptr - 9] := mem[q + 4].int - mem[p + 6].int; + bisectstack[bisectptr - 8] := mem[q + 2].int - mem[q + 4].int; + if bisectstack[bisectptr - 10] < 0 then + if bisectstack[bisectptr - 8] >= 0 then begin + if bisectstack[bisectptr - 9] < 0 then + bisectstack[bisectptr - 7] := bisectstack[bisectptr - 10] + bisectstack[bisectptr - 9] + else + bisectstack[bisectptr - 7] := bisectstack[bisectptr - 10]; + bisectstack[bisectptr - 6] := (bisectstack[bisectptr - 10] + bisectstack[bisectptr - 9]) + bisectstack[bisectptr - 8]; + if bisectstack[bisectptr - 6] < 0 then + bisectstack[bisectptr - 6] := 0 + end else begin + bisectstack[bisectptr - 7] := (bisectstack[bisectptr - 10] + bisectstack[bisectptr - 9]) + bisectstack[bisectptr - 8]; + if bisectstack[bisectptr - 7] > bisectstack[bisectptr - 10] then + bisectstack[bisectptr - 7] := bisectstack[bisectptr - 10]; + bisectstack[bisectptr - 6] := bisectstack[bisectptr - 10] + bisectstack[bisectptr - 9]; + if bisectstack[bisectptr - 6] < 0 then + bisectstack[bisectptr - 6] := 0 + end + else if bisectstack[bisectptr - 8] <= 0 then begin + if bisectstack[bisectptr - 9] > 0 then + bisectstack[bisectptr - 6] := bisectstack[bisectptr - 10] + bisectstack[bisectptr - 9] + else + bisectstack[bisectptr - 6] := bisectstack[bisectptr - 10]; + bisectstack[bisectptr - 7] := (bisectstack[bisectptr - 10] + bisectstack[bisectptr - 9]) + bisectstack[bisectptr - 8]; + if bisectstack[bisectptr - 7] > 0 then + bisectstack[bisectptr - 7] := 0 + end else begin + bisectstack[bisectptr - 6] := (bisectstack[bisectptr - 10] + bisectstack[bisectptr - 9]) + bisectstack[bisectptr - 8]; + if bisectstack[bisectptr - 6] < bisectstack[bisectptr - 10] then + bisectstack[bisectptr - 6] := bisectstack[bisectptr - 10]; + bisectstack[bisectptr - 7] := bisectstack[bisectptr - 10] + bisectstack[bisectptr - 9]; + if bisectstack[bisectptr - 7] > 0 then + bisectstack[bisectptr - 7] := 0 + end; + bisectstack[bisectptr - 15] := mem[pp + 5].int - mem[pp + 1].int; + bisectstack[bisectptr - 14] := mem[qq + 3].int - mem[pp + 5].int; + bisectstack[bisectptr - 13] := mem[qq + 1].int - mem[qq + 3].int; + if bisectstack[bisectptr - 15] < 0 then + if bisectstack[bisectptr - 13] >= 0 then begin + if bisectstack[bisectptr - 14] < 0 then + bisectstack[bisectptr - 12] := bisectstack[bisectptr - 15] + bisectstack[bisectptr - 14] + else + bisectstack[bisectptr - 12] := bisectstack[bisectptr - 15]; + bisectstack[bisectptr - 11] := (bisectstack[bisectptr - 15] + bisectstack[bisectptr - 14]) + bisectstack[bisectptr - 13]; + if bisectstack[bisectptr - 11] < 0 then + bisectstack[bisectptr - 11] := 0 + end else begin + bisectstack[bisectptr - 12] := (bisectstack[bisectptr - 15] + bisectstack[bisectptr - 14]) + bisectstack[bisectptr - 13]; + if bisectstack[bisectptr - 12] > bisectstack[bisectptr - 15] then + bisectstack[bisectptr - 12] := bisectstack[bisectptr - 15]; + bisectstack[bisectptr - 11] := bisectstack[bisectptr - 15] + bisectstack[bisectptr - 14]; + if bisectstack[bisectptr - 11] < 0 then + bisectstack[bisectptr - 11] := 0 + end + else if bisectstack[bisectptr - 13] <= 0 then begin + if bisectstack[bisectptr - 14] > 0 then + bisectstack[bisectptr - 11] := bisectstack[bisectptr - 15] + bisectstack[bisectptr - 14] + else + bisectstack[bisectptr - 11] := bisectstack[bisectptr - 15]; + bisectstack[bisectptr - 12] := (bisectstack[bisectptr - 15] + bisectstack[bisectptr - 14]) + bisectstack[bisectptr - 13]; + if bisectstack[bisectptr - 12] > 0 then + bisectstack[bisectptr - 12] := 0 + end else begin + bisectstack[bisectptr - 11] := (bisectstack[bisectptr - 15] + bisectstack[bisectptr - 14]) + bisectstack[bisectptr - 13]; + if bisectstack[bisectptr - 11] < bisectstack[bisectptr - 15] then + bisectstack[bisectptr - 11] := bisectstack[bisectptr - 15]; + bisectstack[bisectptr - 12] := bisectstack[bisectptr - 15] + bisectstack[bisectptr - 14]; + if bisectstack[bisectptr - 12] > 0 then + bisectstack[bisectptr - 12] := 0 + end; + bisectstack[bisectptr - 20] := mem[pp + 6].int - mem[pp + 2].int; + bisectstack[bisectptr - 19] := mem[qq + 4].int - mem[pp + 6].int; + bisectstack[bisectptr - 18] := mem[qq + 2].int - mem[qq + 4].int; + if bisectstack[bisectptr - 20] < 0 then + if bisectstack[bisectptr - 18] >= 0 then begin + if bisectstack[bisectptr - 19] < 0 then + bisectstack[bisectptr - 17] := bisectstack[bisectptr - 20] + bisectstack[bisectptr - 19] + else + bisectstack[bisectptr - 17] := bisectstack[bisectptr - 20]; + bisectstack[bisectptr - 16] := (bisectstack[bisectptr - 20] + bisectstack[bisectptr - 19]) + bisectstack[bisectptr - 18]; + if bisectstack[bisectptr - 16] < 0 then + bisectstack[bisectptr - 16] := 0 + end else begin + bisectstack[bisectptr - 17] := (bisectstack[bisectptr - 20] + bisectstack[bisectptr - 19]) + bisectstack[bisectptr - 18]; + if bisectstack[bisectptr - 17] > bisectstack[bisectptr - 20] then + bisectstack[bisectptr - 17] := bisectstack[bisectptr - 20]; + bisectstack[bisectptr - 16] := bisectstack[bisectptr - 20] + bisectstack[bisectptr - 19]; + if bisectstack[bisectptr - 16] < 0 then + bisectstack[bisectptr - 16] := 0 + end + else if bisectstack[bisectptr - 18] <= 0 then begin + if bisectstack[bisectptr - 19] > 0 then + bisectstack[bisectptr - 16] := bisectstack[bisectptr - 20] + bisectstack[bisectptr - 19] + else + bisectstack[bisectptr - 16] := bisectstack[bisectptr - 20]; + bisectstack[bisectptr - 17] := (bisectstack[bisectptr - 20] + bisectstack[bisectptr - 19]) + bisectstack[bisectptr - 18]; + if bisectstack[bisectptr - 17] > 0 then + bisectstack[bisectptr - 17] := 0 + end else begin + bisectstack[bisectptr - 16] := (bisectstack[bisectptr - 20] + bisectstack[bisectptr - 19]) + bisectstack[bisectptr - 18]; + if bisectstack[bisectptr - 16] < bisectstack[bisectptr - 20] then + bisectstack[bisectptr - 16] := bisectstack[bisectptr - 20]; + bisectstack[bisectptr - 17] := bisectstack[bisectptr - 20] + bisectstack[bisectptr - 19]; + if bisectstack[bisectptr - 17] > 0 then + bisectstack[bisectptr - 17] := 0 + end; + delx := mem[p + 1].int - mem[pp + 1].int; + dely := mem[p + 2].int - mem[pp + 2].int; + tol := 0; + uv := bisectptr; + xy := bisectptr; + threel := 0; + curt := 1; + curtt := 1 {:558}; + while true do begin + 22: + if (delx - tol) <= (bisectstack[xy - 11] - bisectstack[uv - 2]) then + if (delx + tol) >= (bisectstack[xy - 12] - bisectstack[uv - 1]) then + if (dely - tol) <= (bisectstack[xy - 16] - bisectstack[uv - 7]) then + if (dely + tol) >= (bisectstack[xy - 17] - bisectstack[uv - 6]) then begin + if curt >= maxt then begin + if maxt = 131072 then begin + curt := (curt + 1) div 2; + curtt := (curtt + 1) div 2; + goto 10 + end; + maxt := maxt + maxt; + apprt := curt; + apprtt := curtt + end; {559:} + bisectstack[bisectptr] := delx; + bisectstack[bisectptr + 1] := dely; + bisectstack[bisectptr + 2] := tol; + bisectstack[bisectptr + 3] := uv; + bisectstack[bisectptr + 4] := xy; + bisectptr := bisectptr + 45; + curt := curt + curt; + curtt := curtt + curtt; + bisectstack[bisectptr - 25] := bisectstack[uv - 5]; + bisectstack[bisectptr - 3] := bisectstack[uv - 3]; + bisectstack[bisectptr - 24] := (bisectstack[bisectptr - 25] + bisectstack[uv - 4]) div 2; + bisectstack[bisectptr - 4] := (bisectstack[bisectptr - 3] + bisectstack[uv - 4]) div 2; + bisectstack[bisectptr - 23] := (bisectstack[bisectptr - 24] + bisectstack[bisectptr - 4]) div 2; + bisectstack[bisectptr - 5] := bisectstack[bisectptr - 23]; + if bisectstack[bisectptr - 25] < 0 then + if bisectstack[bisectptr - 23] >= 0 then begin + if bisectstack[bisectptr - 24] < 0 then + bisectstack[bisectptr - 22] := bisectstack[bisectptr - 25] + bisectstack[bisectptr - 24] + else + bisectstack[bisectptr - 22] := bisectstack[bisectptr - 25]; + bisectstack[bisectptr - 21] := (bisectstack[bisectptr - 25] + bisectstack[bisectptr - 24]) + bisectstack[bisectptr - 23]; + if bisectstack[bisectptr - 21] < 0 then + bisectstack[bisectptr - 21] := 0 + end else begin + bisectstack[bisectptr - 22] := (bisectstack[bisectptr - 25] + bisectstack[bisectptr - 24]) + bisectstack[bisectptr - 23]; + if bisectstack[bisectptr - 22] > bisectstack[bisectptr - 25] then + bisectstack[bisectptr - 22] := bisectstack[bisectptr - 25]; + bisectstack[bisectptr - 21] := bisectstack[bisectptr - 25] + bisectstack[bisectptr - 24]; + if bisectstack[bisectptr - 21] < 0 then + bisectstack[bisectptr - 21] := 0 + end + else if bisectstack[bisectptr - 23] <= 0 then begin + if bisectstack[bisectptr - 24] > 0 then + bisectstack[bisectptr - 21] := bisectstack[bisectptr - 25] + bisectstack[bisectptr - 24] + else + bisectstack[bisectptr - 21] := bisectstack[bisectptr - 25]; + bisectstack[bisectptr - 22] := (bisectstack[bisectptr - 25] + bisectstack[bisectptr - 24]) + bisectstack[bisectptr - 23]; + if bisectstack[bisectptr - 22] > 0 then + bisectstack[bisectptr - 22] := 0 + end else begin + bisectstack[bisectptr - 21] := (bisectstack[bisectptr - 25] + bisectstack[bisectptr - 24]) + bisectstack[bisectptr - 23]; + if bisectstack[bisectptr - 21] < bisectstack[bisectptr - 25] then + bisectstack[bisectptr - 21] := bisectstack[bisectptr - 25]; + bisectstack[bisectptr - 22] := bisectstack[bisectptr - 25] + bisectstack[bisectptr - 24]; + if bisectstack[bisectptr - 22] > 0 then + bisectstack[bisectptr - 22] := 0 + end; + if bisectstack[bisectptr - 5] < 0 then + if bisectstack[bisectptr - 3] >= 0 then begin + if bisectstack[bisectptr - 4] < 0 then + bisectstack[bisectptr - 2] := bisectstack[bisectptr - 5] + bisectstack[bisectptr - 4] + else + bisectstack[bisectptr - 2] := bisectstack[bisectptr - 5]; + bisectstack[bisectptr - 1] := (bisectstack[bisectptr - 5] + bisectstack[bisectptr - 4]) + bisectstack[bisectptr - 3]; + if bisectstack[bisectptr - 1] < 0 then + bisectstack[bisectptr - 1] := 0 + end else begin + bisectstack[bisectptr - 2] := (bisectstack[bisectptr - 5] + bisectstack[bisectptr - 4]) + bisectstack[bisectptr - 3]; + if bisectstack[bisectptr - 2] > bisectstack[bisectptr - 5] then + bisectstack[bisectptr - 2] := bisectstack[bisectptr - 5]; + bisectstack[bisectptr - 1] := bisectstack[bisectptr - 5] + bisectstack[bisectptr - 4]; + if bisectstack[bisectptr - 1] < 0 then + bisectstack[bisectptr - 1] := 0 + end + else if bisectstack[bisectptr - 3] <= 0 then begin + if bisectstack[bisectptr - 4] > 0 then + bisectstack[bisectptr - 1] := bisectstack[bisectptr - 5] + bisectstack[bisectptr - 4] + else + bisectstack[bisectptr - 1] := bisectstack[bisectptr - 5]; + bisectstack[bisectptr - 2] := (bisectstack[bisectptr - 5] + bisectstack[bisectptr - 4]) + bisectstack[bisectptr - 3]; + if bisectstack[bisectptr - 2] > 0 then + bisectstack[bisectptr - 2] := 0 + end else begin + bisectstack[bisectptr - 1] := (bisectstack[bisectptr - 5] + bisectstack[bisectptr - 4]) + bisectstack[bisectptr - 3]; + if bisectstack[bisectptr - 1] < bisectstack[bisectptr - 5] then + bisectstack[bisectptr - 1] := bisectstack[bisectptr - 5]; + bisectstack[bisectptr - 2] := bisectstack[bisectptr - 5] + bisectstack[bisectptr - 4]; + if bisectstack[bisectptr - 2] > 0 then + bisectstack[bisectptr - 2] := 0 + end; + bisectstack[bisectptr - 30] := bisectstack[uv - 10]; + bisectstack[bisectptr - 8] := bisectstack[uv - 8]; + bisectstack[bisectptr - 29] := (bisectstack[bisectptr - 30] + bisectstack[uv - 9]) div 2; + bisectstack[bisectptr - 9] := (bisectstack[bisectptr - 8] + bisectstack[uv - 9]) div 2; + bisectstack[bisectptr - 28] := (bisectstack[bisectptr - 29] + bisectstack[bisectptr - 9]) div 2; + bisectstack[bisectptr - 10] := bisectstack[bisectptr - 28]; + if bisectstack[bisectptr - 30] < 0 then + if bisectstack[bisectptr - 28] >= 0 then begin + if bisectstack[bisectptr - 29] < 0 then + bisectstack[bisectptr - 27] := bisectstack[bisectptr - 30] + bisectstack[bisectptr - 29] + else + bisectstack[bisectptr - 27] := bisectstack[bisectptr - 30]; + bisectstack[bisectptr - 26] := (bisectstack[bisectptr - 30] + bisectstack[bisectptr - 29]) + bisectstack[bisectptr - 28]; + if bisectstack[bisectptr - 26] < 0 then + bisectstack[bisectptr - 26] := 0 + end else begin + bisectstack[bisectptr - 27] := (bisectstack[bisectptr - 30] + bisectstack[bisectptr - 29]) + bisectstack[bisectptr - 28]; + if bisectstack[bisectptr - 27] > bisectstack[bisectptr - 30] then + bisectstack[bisectptr - 27] := bisectstack[bisectptr - 30]; + bisectstack[bisectptr - 26] := bisectstack[bisectptr - 30] + bisectstack[bisectptr - 29]; + if bisectstack[bisectptr - 26] < 0 then + bisectstack[bisectptr - 26] := 0 + end + else if bisectstack[bisectptr - 28] <= 0 then begin + if bisectstack[bisectptr - 29] > 0 then + bisectstack[bisectptr - 26] := bisectstack[bisectptr - 30] + bisectstack[bisectptr - 29] + else + bisectstack[bisectptr - 26] := bisectstack[bisectptr - 30]; + bisectstack[bisectptr - 27] := (bisectstack[bisectptr - 30] + bisectstack[bisectptr - 29]) + bisectstack[bisectptr - 28]; + if bisectstack[bisectptr - 27] > 0 then + bisectstack[bisectptr - 27] := 0 + end else begin + bisectstack[bisectptr - 26] := (bisectstack[bisectptr - 30] + bisectstack[bisectptr - 29]) + bisectstack[bisectptr - 28]; + if bisectstack[bisectptr - 26] < bisectstack[bisectptr - 30] then + bisectstack[bisectptr - 26] := bisectstack[bisectptr - 30]; + bisectstack[bisectptr - 27] := bisectstack[bisectptr - 30] + bisectstack[bisectptr - 29]; + if bisectstack[bisectptr - 27] > 0 then + bisectstack[bisectptr - 27] := 0 + end; + if bisectstack[bisectptr - 10] < 0 then + if bisectstack[bisectptr - 8] >= 0 then begin + if bisectstack[bisectptr - 9] < 0 then + bisectstack[bisectptr - 7] := bisectstack[bisectptr - 10] + bisectstack[bisectptr - 9] + else + bisectstack[bisectptr - 7] := bisectstack[bisectptr - 10]; + bisectstack[bisectptr - 6] := (bisectstack[bisectptr - 10] + bisectstack[bisectptr - 9]) + bisectstack[bisectptr - 8]; + if bisectstack[bisectptr - 6] < 0 then + bisectstack[bisectptr - 6] := 0 + end else begin + bisectstack[bisectptr - 7] := (bisectstack[bisectptr - 10] + bisectstack[bisectptr - 9]) + bisectstack[bisectptr - 8]; + if bisectstack[bisectptr - 7] > bisectstack[bisectptr - 10] then + bisectstack[bisectptr - 7] := bisectstack[bisectptr - 10]; + bisectstack[bisectptr - 6] := bisectstack[bisectptr - 10] + bisectstack[bisectptr - 9]; + if bisectstack[bisectptr - 6] < 0 then + bisectstack[bisectptr - 6] := 0 + end + else if bisectstack[bisectptr - 8] <= 0 then begin + if bisectstack[bisectptr - 9] > 0 then + bisectstack[bisectptr - 6] := bisectstack[bisectptr - 10] + bisectstack[bisectptr - 9] + else + bisectstack[bisectptr - 6] := bisectstack[bisectptr - 10]; + bisectstack[bisectptr - 7] := (bisectstack[bisectptr - 10] + bisectstack[bisectptr - 9]) + bisectstack[bisectptr - 8]; + if bisectstack[bisectptr - 7] > 0 then + bisectstack[bisectptr - 7] := 0 + end else begin + bisectstack[bisectptr - 6] := (bisectstack[bisectptr - 10] + bisectstack[bisectptr - 9]) + bisectstack[bisectptr - 8]; + if bisectstack[bisectptr - 6] < bisectstack[bisectptr - 10] then + bisectstack[bisectptr - 6] := bisectstack[bisectptr - 10]; + bisectstack[bisectptr - 7] := bisectstack[bisectptr - 10] + bisectstack[bisectptr - 9]; + if bisectstack[bisectptr - 7] > 0 then + bisectstack[bisectptr - 7] := 0 + end; + bisectstack[bisectptr - 35] := bisectstack[xy - 15]; + bisectstack[bisectptr - 13] := bisectstack[xy - 13]; + bisectstack[bisectptr - 34] := (bisectstack[bisectptr - 35] + bisectstack[xy - 14]) div 2; + bisectstack[bisectptr - 14] := (bisectstack[bisectptr - 13] + bisectstack[xy - 14]) div 2; + bisectstack[bisectptr - 33] := (bisectstack[bisectptr - 34] + bisectstack[bisectptr - 14]) div 2; + bisectstack[bisectptr - 15] := bisectstack[bisectptr - 33]; + if bisectstack[bisectptr - 35] < 0 then + if bisectstack[bisectptr - 33] >= 0 then begin + if bisectstack[bisectptr - 34] < 0 then + bisectstack[bisectptr - 32] := bisectstack[bisectptr - 35] + bisectstack[bisectptr - 34] + else + bisectstack[bisectptr - 32] := bisectstack[bisectptr - 35]; + bisectstack[bisectptr - 31] := (bisectstack[bisectptr - 35] + bisectstack[bisectptr - 34]) + bisectstack[bisectptr - 33]; + if bisectstack[bisectptr - 31] < 0 then + bisectstack[bisectptr - 31] := 0 + end else begin + bisectstack[bisectptr - 32] := (bisectstack[bisectptr - 35] + bisectstack[bisectptr - 34]) + bisectstack[bisectptr - 33]; + if bisectstack[bisectptr - 32] > bisectstack[bisectptr - 35] then + bisectstack[bisectptr - 32] := bisectstack[bisectptr - 35]; + bisectstack[bisectptr - 31] := bisectstack[bisectptr - 35] + bisectstack[bisectptr - 34]; + if bisectstack[bisectptr - 31] < 0 then + bisectstack[bisectptr - 31] := 0 + end + else if bisectstack[bisectptr - 33] <= 0 then begin + if bisectstack[bisectptr - 34] > 0 then + bisectstack[bisectptr - 31] := bisectstack[bisectptr - 35] + bisectstack[bisectptr - 34] + else + bisectstack[bisectptr - 31] := bisectstack[bisectptr - 35]; + bisectstack[bisectptr - 32] := (bisectstack[bisectptr - 35] + bisectstack[bisectptr - 34]) + bisectstack[bisectptr - 33]; + if bisectstack[bisectptr - 32] > 0 then + bisectstack[bisectptr - 32] := 0 + end else begin + bisectstack[bisectptr - 31] := (bisectstack[bisectptr - 35] + bisectstack[bisectptr - 34]) + bisectstack[bisectptr - 33]; + if bisectstack[bisectptr - 31] < bisectstack[bisectptr - 35] then + bisectstack[bisectptr - 31] := bisectstack[bisectptr - 35]; + bisectstack[bisectptr - 32] := bisectstack[bisectptr - 35] + bisectstack[bisectptr - 34]; + if bisectstack[bisectptr - 32] > 0 then + bisectstack[bisectptr - 32] := 0 + end; + if bisectstack[bisectptr - 15] < 0 then + if bisectstack[bisectptr - 13] >= 0 then begin + if bisectstack[bisectptr - 14] < 0 then + bisectstack[bisectptr - 12] := bisectstack[bisectptr - 15] + bisectstack[bisectptr - 14] + else + bisectstack[bisectptr - 12] := bisectstack[bisectptr - 15]; + bisectstack[bisectptr - 11] := (bisectstack[bisectptr - 15] + bisectstack[bisectptr - 14]) + bisectstack[bisectptr - 13]; + if bisectstack[bisectptr - 11] < 0 then + bisectstack[bisectptr - 11] := 0 + end else begin + bisectstack[bisectptr - 12] := (bisectstack[bisectptr - 15] + bisectstack[bisectptr - 14]) + bisectstack[bisectptr - 13]; + if bisectstack[bisectptr - 12] > bisectstack[bisectptr - 15] then + bisectstack[bisectptr - 12] := bisectstack[bisectptr - 15]; + bisectstack[bisectptr - 11] := bisectstack[bisectptr - 15] + bisectstack[bisectptr - 14]; + if bisectstack[bisectptr - 11] < 0 then + bisectstack[bisectptr - 11] := 0 + end + else if bisectstack[bisectptr - 13] <= 0 then begin + if bisectstack[bisectptr - 14] > 0 then + bisectstack[bisectptr - 11] := bisectstack[bisectptr - 15] + bisectstack[bisectptr - 14] + else + bisectstack[bisectptr - 11] := bisectstack[bisectptr - 15]; + bisectstack[bisectptr - 12] := (bisectstack[bisectptr - 15] + bisectstack[bisectptr - 14]) + bisectstack[bisectptr - 13]; + if bisectstack[bisectptr - 12] > 0 then + bisectstack[bisectptr - 12] := 0 + end else begin + bisectstack[bisectptr - 11] := (bisectstack[bisectptr - 15] + bisectstack[bisectptr - 14]) + bisectstack[bisectptr - 13]; + if bisectstack[bisectptr - 11] < bisectstack[bisectptr - 15] then + bisectstack[bisectptr - 11] := bisectstack[bisectptr - 15]; + bisectstack[bisectptr - 12] := bisectstack[bisectptr - 15] + bisectstack[bisectptr - 14]; + if bisectstack[bisectptr - 12] > 0 then + bisectstack[bisectptr - 12] := 0 + end; + bisectstack[bisectptr - 40] := bisectstack[xy - 20]; + bisectstack[bisectptr - 18] := bisectstack[xy - 18]; + bisectstack[bisectptr - 39] := (bisectstack[bisectptr - 40] + bisectstack[xy - 19]) div 2; + bisectstack[bisectptr - 19] := (bisectstack[bisectptr - 18] + bisectstack[xy - 19]) div 2; + bisectstack[bisectptr - 38] := (bisectstack[bisectptr - 39] + bisectstack[bisectptr - 19]) div 2; + bisectstack[bisectptr - 20] := bisectstack[bisectptr - 38]; + if bisectstack[bisectptr - 40] < 0 then + if bisectstack[bisectptr - 38] >= 0 then begin + if bisectstack[bisectptr - 39] < 0 then + bisectstack[bisectptr - 37] := bisectstack[bisectptr - 40] + bisectstack[bisectptr - 39] + else + bisectstack[bisectptr - 37] := bisectstack[bisectptr - 40]; + bisectstack[bisectptr - 36] := (bisectstack[bisectptr - 40] + bisectstack[bisectptr - 39]) + bisectstack[bisectptr - 38]; + if bisectstack[bisectptr - 36] < 0 then + bisectstack[bisectptr - 36] := 0 + end else begin + bisectstack[bisectptr - 37] := (bisectstack[bisectptr - 40] + bisectstack[bisectptr - 39]) + bisectstack[bisectptr - 38]; + if bisectstack[bisectptr - 37] > bisectstack[bisectptr - 40] then + bisectstack[bisectptr - 37] := bisectstack[bisectptr - 40]; + bisectstack[bisectptr - 36] := bisectstack[bisectptr - 40] + bisectstack[bisectptr - 39]; + if bisectstack[bisectptr - 36] < 0 then + bisectstack[bisectptr - 36] := 0 + end + else if bisectstack[bisectptr - 38] <= 0 then begin + if bisectstack[bisectptr - 39] > 0 then + bisectstack[bisectptr - 36] := bisectstack[bisectptr - 40] + bisectstack[bisectptr - 39] + else + bisectstack[bisectptr - 36] := bisectstack[bisectptr - 40]; + bisectstack[bisectptr - 37] := (bisectstack[bisectptr - 40] + bisectstack[bisectptr - 39]) + bisectstack[bisectptr - 38]; + if bisectstack[bisectptr - 37] > 0 then + bisectstack[bisectptr - 37] := 0 + end else begin + bisectstack[bisectptr - 36] := (bisectstack[bisectptr - 40] + bisectstack[bisectptr - 39]) + bisectstack[bisectptr - 38]; + if bisectstack[bisectptr - 36] < bisectstack[bisectptr - 40] then + bisectstack[bisectptr - 36] := bisectstack[bisectptr - 40]; + bisectstack[bisectptr - 37] := bisectstack[bisectptr - 40] + bisectstack[bisectptr - 39]; + if bisectstack[bisectptr - 37] > 0 then + bisectstack[bisectptr - 37] := 0 + end; + if bisectstack[bisectptr - 20] < 0 then + if bisectstack[bisectptr - 18] >= 0 then begin + if bisectstack[bisectptr - 19] < 0 then + bisectstack[bisectptr - 17] := bisectstack[bisectptr - 20] + bisectstack[bisectptr - 19] + else + bisectstack[bisectptr - 17] := bisectstack[bisectptr - 20]; + bisectstack[bisectptr - 16] := (bisectstack[bisectptr - 20] + bisectstack[bisectptr - 19]) + bisectstack[bisectptr - 18]; + if bisectstack[bisectptr - 16] < 0 then + bisectstack[bisectptr - 16] := 0 + end else begin + bisectstack[bisectptr - 17] := (bisectstack[bisectptr - 20] + bisectstack[bisectptr - 19]) + bisectstack[bisectptr - 18]; + if bisectstack[bisectptr - 17] > bisectstack[bisectptr - 20] then + bisectstack[bisectptr - 17] := bisectstack[bisectptr - 20]; + bisectstack[bisectptr - 16] := bisectstack[bisectptr - 20] + bisectstack[bisectptr - 19]; + if bisectstack[bisectptr - 16] < 0 then + bisectstack[bisectptr - 16] := 0 + end + else if bisectstack[bisectptr - 18] <= 0 then begin + if bisectstack[bisectptr - 19] > 0 then + bisectstack[bisectptr - 16] := bisectstack[bisectptr - 20] + bisectstack[bisectptr - 19] + else + bisectstack[bisectptr - 16] := bisectstack[bisectptr - 20]; + bisectstack[bisectptr - 17] := (bisectstack[bisectptr - 20] + bisectstack[bisectptr - 19]) + bisectstack[bisectptr - 18]; + if bisectstack[bisectptr - 17] > 0 then + bisectstack[bisectptr - 17] := 0 + end else begin + bisectstack[bisectptr - 16] := (bisectstack[bisectptr - 20] + bisectstack[bisectptr - 19]) + bisectstack[bisectptr - 18]; + if bisectstack[bisectptr - 16] < bisectstack[bisectptr - 20] then + bisectstack[bisectptr - 16] := bisectstack[bisectptr - 20]; + bisectstack[bisectptr - 17] := bisectstack[bisectptr - 20] + bisectstack[bisectptr - 19]; + if bisectstack[bisectptr - 17] > 0 then + bisectstack[bisectptr - 17] := 0 + end; + uv := bisectptr - 20; + xy := bisectptr - 20; + delx := delx + delx; + dely := dely + dely; + tol := (tol - threel) + tolstep; + tol := tol + tol; + threel := threel + tolstep {:559}; + goto 22 + end; + if timetogo > 0 then + timetogo := timetogo - 1 + else begin + while apprt < 65536 do begin + apprt := apprt + apprt; + apprtt := apprtt + apprtt + end; + curt := apprt; + curtt := apprtt; + goto 10 + end; {560:} + 45: + if odd(curtt) then + if odd(curt) then begin {561:} + curt := curt div 2; + curtt := curtt div 2; + if curt = 0 then + goto 10; + bisectptr := bisectptr - 45; + threel := threel - tolstep; + delx := bisectstack[bisectptr]; + dely := bisectstack[bisectptr + 1]; + tol := bisectstack[bisectptr + 2]; + uv := bisectstack[bisectptr + 3]; + xy := bisectstack[bisectptr + 4]; + goto 45 + end else begin {:561} + curt := curt + 1; + delx := ((delx + bisectstack[uv - 5]) + bisectstack[uv - 4]) + bisectstack[uv - 3]; + dely := ((dely + bisectstack[uv - 10]) + bisectstack[uv - 9]) + bisectstack[uv - 8]; + uv := uv + 20; + curtt := curtt - 1; + xy := xy - 20; + delx := ((delx + bisectstack[xy - 15]) + bisectstack[xy - 14]) + bisectstack[xy - 13]; + dely := ((dely + bisectstack[xy - 20]) + bisectstack[xy - 19]) + bisectstack[xy - 18] + end + else begin + curtt := curtt + 1; + tol := tol + threel; + delx := ((delx - bisectstack[xy - 15]) - bisectstack[xy - 14]) - bisectstack[xy - 13]; + dely := ((dely - bisectstack[xy - 20]) - bisectstack[xy - 19]) - bisectstack[xy - 18]; + xy := xy + 20 + end {:560} + end; + 10: + + end; {:556} {562:} + + procedure pathintersection(h, hh: halfword); + label + 10; + var + p, pp: halfword; + n, nn: integer; {563:} + begin + if mem[h].hh.b1 = 0 then begin + mem[h + 5].int := mem[h + 1].int; + mem[h + 3].int := mem[h + 1].int; + mem[h + 6].int := mem[h + 2].int; + mem[h + 4].int := mem[h + 2].int; + mem[h].hh.b1 := 1 + end; + if mem[hh].hh.b1 = 0 then begin + mem[hh + 5].int := mem[hh + 1].int; + mem[hh + 3].int := mem[hh + 1].int; + mem[hh + 6].int := mem[hh + 2].int; + mem[hh + 4].int := mem[hh + 2].int; + mem[hh].hh.b1 := 1 + end; {:563} + tolstep := 0; + repeat + n := -65536; + p := h; + repeat + if mem[p].hh.b1 <> 0 then begin + nn := -65536; + pp := hh; + repeat + if mem[pp].hh.b1 <> 0 then begin + cubicintersection(p, pp); + if curt > 0 then begin + curt := curt + n; + curtt := curtt + nn; + goto 10 + end + end; + nn := nn + 65536; + pp := mem[pp].hh.rh + until pp = hh + end; + n := n + 65536; + p := mem[p].hh.rh + until p = h; + tolstep := tolstep + 3 + until tolstep > 3; + curt := -65536; + curtt := -65536; + 10: + + end; {:562} {574:} + + procedure openawindow(k: windownumber; r0, c0, r1, c1: scaled; x, y: scaled); + var + m, n: integer; {575:} + begin + if r0 < 0 then + r0 := 0 + else + r0 := roundunscaled(r0); + r1 := roundunscaled(r1); + if r1 > screendepth then + r1 := screendepth; + if r1 < r0 then + if r0 > screendepth then + r0 := r1 + else + r1 := r0; + if c0 < 0 then + c0 := 0 + else + c0 := roundunscaled(c0); + c1 := roundunscaled(c1); + if c1 > screenwidth then + c1 := screenwidth; + if c1 < c0 then + if c0 > screenwidth then + c0 := c1 + else + c1 := c0 {:575}; + windowopen[k] := true; + windowtime[k] := windowtime[k] + 1; + leftcol[k] := c0; + rightcol[k] := c1; + toprow[k] := r0; + botrow[k] := r1; {576:} + m := roundunscaled(x); + n := roundunscaled(y) - 1; + mwindow[k] := c0 - m; + nwindow[k] := r0 + n {:576}; + begin + if not screenstarted then begin + screenOK := initscreen; + screenstarted := true + end + end; + if screenOK then begin + blankrectangle(c0, c1, r0, r1); + updatescreen + end + end; { openawindow } +{:574} + {577:} + + procedure dispedges(k: windownumber); + label + 30, 40; + var + p, q: halfword; + alreadythere: boolean; + r: integer; {580:} + n: screencol; + w, ww: integer; + b: pixelcolor; + m, mm: integer; + d: integer; + madjustment: integer; + rightedge: integer; + mincol: screencol; {:580} + begin + if screenOK then + if leftcol[k] < rightcol[k] then + if toprow[k] < botrow[k] then begin + alreadythere := false; + if mem[curedges + 3].hh.rh = k then + if mem[curedges + 4].int = windowtime[k] then + alreadythere := true; + if not alreadythere then + blankrectangle(leftcol[k], rightcol[k], toprow[k], botrow[k]); {581:} + madjustment := mwindow[k] - mem[curedges + 3].hh.lh; + rightedge := 8 * (rightcol[k] - madjustment); + mincol := leftcol[k] {:581}; + p := mem[curedges].hh.rh; + r := nwindow[k] - (mem[curedges + 1].hh.lh - 4096); + while (p <> curedges) and (r >= toprow[k]) do begin + if r < botrow[k] then begin {578:} + if mem[p + 1].hh.lh > (-29999) then + sortedges(p) + else if mem[p + 1].hh.lh = (-29999) then + if alreadythere then + goto 30; + mem[p + 1].hh.lh := -29999; {582:} + n := 0; + ww := 0; + m := -1; + w := 0; + q := mem[p + 1].hh.rh; + rowtransition[0] := mincol; + while true do begin + if q = 30000 then + d := rightedge + else + d := mem[q].hh.lh + 32768; + mm := (d div 8) + madjustment; + if mm <> m then begin {583:} + if w <= 0 then begin + if ww > 0 then + if m > mincol then begin + if n = 0 then + if alreadythere then begin + b := 0; + n := n + 1 + end else + b := 1 + else + n := n + 1; + rowtransition[n] := m + end + end else if ww <= 0 then + if m > mincol then begin + if n = 0 then + b := 1; + n := n + 1; + rowtransition[n] := m + end {:583}; + m := mm; + w := ww + end; + if d >= rightedge then + goto 40; + ww := (ww + (d mod 8)) - 4; + q := mem[q].hh.rh + end; + 40: {584:} + if alreadythere or (ww > 0) then begin + if n = 0 then + if ww > 0 then + b := 1 + else + b := 0; + n := n + 1; + rowtransition[n] := rightcol[k] + end else if n = 0 then + goto 30 {:584}; {:582} + paintrow(r, b, rowtransition, n); + 30: {:578} + + end; + p := mem[p].hh.rh; + r := r - 1 + end; + updatescreen; + windowtime[k] := windowtime[k] + 1; + mem[curedges + 3].hh.rh := k; + mem[curedges + 4].int := windowtime[k] + end + end; {:577} {591:} + + function maxcoef(p: halfword): fraction; + var + x: fraction; + begin + x := 0; + while mem[p].hh.lh <> (-30000) do begin + if abs(mem[p + 1].int) > x then + x := abs(mem[p + 1].int); + p := mem[p].hh.rh + end; + maxcoef := x + end; {:591} {597:} + + function pplusq(p: halfword; q: halfword; t: smallnumber): halfword; + label + 30; + var + pp, qq: halfword; + r, s: halfword; + threshold: integer; + v: integer; + begin + if t = 17 then + threshold := 2685 + else + threshold := 8; + r := 29999; + pp := mem[p].hh.lh; + qq := mem[q].hh.lh; + while true do + if pp = qq then + if pp = (-30000) then + goto 30 {598:} + else begin + v := mem[p + 1].int + mem[q + 1].int; + mem[p + 1].int := v; + s := p; + p := mem[p].hh.rh; + pp := mem[p].hh.lh; + if abs(v) < threshold then + freenode(s, 2) + else begin + if abs(v) >= 626349397 then + if watchcoefs then begin + mem[qq].hh.b0 := 0; + fixneeded := true + end; + mem[r].hh.rh := s; + r := s + end; + q := mem[q].hh.rh; + qq := mem[q].hh.lh + end {:598} + else if mem[pp + 1].int < mem[qq + 1].int then begin + s := getnode(2); + mem[s].hh.lh := qq; + mem[s + 1].int := mem[q + 1].int; + q := mem[q].hh.rh; + qq := mem[q].hh.lh; + mem[r].hh.rh := s; + r := s + end else begin + mem[r].hh.rh := p; + r := p; + p := mem[p].hh.rh; + pp := mem[p].hh.lh + end; + 30: + mem[p + 1].int := slowadd(mem[p + 1].int, mem[q + 1].int); + mem[r].hh.rh := p; + depfinal := p; + pplusq := mem[29999].hh.rh + end; {:597} {599:} + + function ptimesv(p: halfword; v: integer; t0, t1: smallnumber; visscaled: boolean): halfword; + var + r, s: halfword; + w: integer; + threshold: integer; + scalingdown: boolean; + begin + if t0 <> t1 then + scalingdown := true + else + scalingdown := not visscaled; + if t1 = 17 then + threshold := 1342 + else + threshold := 4; + r := 29999; + while mem[p].hh.lh <> (-30000) do begin + if scalingdown then + w := takefraction(v, mem[p + 1].int) + else + w := takescaled(v, mem[p + 1].int); + if abs(w) <= threshold then begin + s := mem[p].hh.rh; + freenode(p, 2); + p := s + end else begin + if abs(w) >= 626349397 then begin + fixneeded := true; + mem[mem[p].hh.lh].hh.b0 := 0 + end; + mem[r].hh.rh := p; + r := p; + mem[p + 1].int := w; + p := mem[p].hh.rh + end + end; + mem[r].hh.rh := p; + if visscaled then + mem[p + 1].int := takescaled(mem[p + 1].int, v) + else + mem[p + 1].int := takefraction(mem[p + 1].int, v); + ptimesv := mem[29999].hh.rh + end; {:599} +{601:} + + function pwithxbecomingq(p, x, q: halfword; t: smallnumber): halfword; + var + r, s: halfword; + v: integer; + sx: integer; + begin + s := p; + r := 29999; + sx := mem[x + 1].int; + while mem[mem[s].hh.lh + 1].int > sx do begin + r := s; + s := mem[s].hh.rh + end; + if mem[s].hh.lh <> x then + pwithxbecomingq := p + else begin + mem[29999].hh.rh := p; + mem[r].hh.rh := mem[s].hh.rh; + v := mem[s + 1].int; + freenode(s, 2); + pwithxbecomingq := pplusfq(mem[29999].hh.rh, v, q, t, 17) + end + end; {:601} {606:} + + procedure newdep(q, p: halfword); + var + r: halfword; + begin + mem[q + 1].hh.rh := p; + mem[q + 1].hh.lh := -29987; + r := mem[-29987].hh.rh; + mem[depfinal].hh.rh := r; + mem[r + 1].hh.lh := depfinal; + mem[-29987].hh.rh := q + end; {:606} {607:} + + function constdependency(v: scaled): halfword; + begin + depfinal := getnode(2); + mem[depfinal + 1].int := v; + mem[depfinal].hh.lh := -30000; + constdependency := depfinal + end; {:607} {608:} + + function singledependency(p: halfword): halfword; + var + q: halfword; + m: integer; + begin + m := mem[p + 1].int mod 64; + if m > 28 then + singledependency := constdependency(0) + else begin + q := getnode(2); + mem[q + 1].int := twotothe[28 - m]; + mem[q].hh.lh := p; + mem[q].hh.rh := constdependency(0); + singledependency := q + end + end; {:608} +{609:} + + function copydeplist(p: halfword): halfword; + label + 30; + var + q: halfword; + begin + q := getnode(2); + depfinal := q; + while true do begin + mem[depfinal].hh.lh := mem[p].hh.lh; + mem[depfinal + 1].int := mem[p + 1].int; + if mem[depfinal].hh.lh = (-30000) then + goto 30; + mem[depfinal].hh.rh := getnode(2); + depfinal := mem[depfinal].hh.rh; + p := mem[p].hh.rh + end; + 30: + copydeplist := q + end; {:609} {610:} + + procedure lineareq(p: halfword; t: smallnumber); + var + q, r, s: halfword; + x: halfword; + n: integer; + v: integer; + prevr: halfword; + finalnode: halfword; + w: integer; {611:} + begin + q := p; + r := mem[p].hh.rh; + v := mem[q + 1].int; + while mem[r].hh.lh <> (-30000) do begin + if abs(mem[r + 1].int) > abs(v) then begin + q := r; + v := mem[r + 1].int + end; + r := mem[r].hh.rh + end {:611}; + x := mem[q].hh.lh; + n := mem[x + 1].int mod 64; {612:} + s := 29999; + mem[s].hh.rh := p; + r := p; + repeat + if r = q then begin + mem[s].hh.rh := mem[r].hh.rh; + freenode(r, 2) + end else begin + w := makefraction(mem[r + 1].int, v); + if abs(w) <= 1342 then begin + mem[s].hh.rh := mem[r].hh.rh; + freenode(r, 2) + end else begin + mem[r + 1].int := -w; + s := r + end + end; + r := mem[s].hh.rh + until mem[r].hh.lh = (-30000); + if t = 18 then + mem[r + 1].int := -makescaled(mem[r + 1].int, v) + else if v <> (-268435456) then + mem[r + 1].int := -makefraction(mem[r + 1].int, v); + finalnode := r; + p := mem[29999].hh.rh {:612}; + if internal[2] > 0 then {613:} + if interesting(x) then begin + begindiagnostic; + printnl(462); + printvariablename(x); + w := n; + while w > 0 do begin + print(455); + w := w - 2 + end; + printchar(61); + printdependency(p, 17); + enddiagnostic(false) + end {:613}; +{614:} + prevr := -29987; + r := mem[-29987].hh.rh; + while r <> (-29987) do begin + s := mem[r + 1].hh.rh; + q := pwithxbecomingq(s, x, p, mem[r].hh.b0); + if mem[q].hh.lh = (-30000) then + makeknown(r, q) + else begin + mem[r + 1].hh.rh := q; + repeat + q := mem[q].hh.rh + until mem[q].hh.lh = (-30000); + prevr := q + end; + r := mem[prevr].hh.rh + end {:614}; {615:} + if n > 0 then begin {616:} + s := 29999; + mem[29999].hh.rh := p; + r := p; + repeat + if n > 30 then + w := 0 + else + w := mem[r + 1].int div twotothe[n]; + if (abs(w) <= 1342) and (mem[r].hh.lh <> (-30000)) then begin + mem[s].hh.rh := mem[r].hh.rh; + freenode(r, 2) + end else begin + mem[r + 1].int := w; + s := r + end; + r := mem[s].hh.rh + until mem[s].hh.lh = (-30000); + p := mem[29999].hh.rh + end {:616}; + if mem[p].hh.lh = (-30000) then begin + mem[x].hh.b0 := 16; + mem[x + 1].int := mem[p + 1].int; + if abs(mem[x + 1].int) >= 268435456 then + valtoobig(mem[x + 1].int); + freenode(p, 2); + if curexp = x then + if curtype = 19 then begin + curexp := mem[x + 1].int; + curtype := 16; + freenode(x, 2) + end + end else begin + mem[x].hh.b0 := 17; + depfinal := finalnode; + newdep(x, p); + if curexp = x then + if curtype = 19 then + curtype := 17 + end {:615}; + if fixneeded then + fixdependencies + end; {:610} {619:} + + function newringentry(p: halfword): halfword; + var + q: halfword; + begin + q := getnode(2); + mem[q].hh.b1 := 11; + mem[q].hh.b0 := mem[p].hh.b0; + if mem[p + 1].int = (-30000) then + mem[q + 1].int := p + else + mem[q + 1].int := mem[p + 1].int; + mem[p + 1].int := q; + newringentry := q + end; {:619} {621:} + + procedure nonlineareq(v: integer; p: halfword; flushp: boolean); + var + t: smallnumber; + q, r: halfword; + begin + t := mem[p].hh.b0 - 1; + q := mem[p + 1].int; + if flushp then + mem[p].hh.b0 := 1 + else + p := q; + repeat + r := mem[q + 1].int; + mem[q].hh.b0 := t; + case t of + 2: + mem[q + 1].int := v; + 4: + begin + mem[q + 1].int := v; + begin + if strref[v] < 127 then + strref[v] := strref[v] + 1 + end + end; + 6: + begin + mem[q + 1].int := v; + mem[v].hh.lh := mem[v].hh.lh + 1 + end; + 9: + mem[q + 1].int := copypath(v); + 11: + mem[q + 1].int := copyedges(v) + end; + q := r + until q = p + end; {:621} {622:} + + procedure ringmerge(p, q: halfword); + label + 10; + var + r: halfword; + begin + r := mem[p + 1].int; + while r <> p do begin + if r = q then begin {623:} + begin + begin + if interaction = 3 then + ; + printnl(133); + print(465) + end; + begin + helpptr := 2; + helpline[1] := 466; + helpline[0] := 467 + end; + putgeterror + end {:623}; + goto 10 + end; + r := mem[r + 1].int + end; + r := mem[p + 1].int; + mem[p + 1].int := mem[q + 1].int; + mem[q + 1].int := r; + 10: + + end; {:622} {626:} + + procedure showcmdmod(c, m: integer); + begin + begindiagnostic; + printnl(123); + printcmdmod(c, m); + printchar(125); + enddiagnostic(false) + end; {:626} {635:} + + procedure showcontext; + label + 30; + var + oldsetting: 0..5; {641:} + i: 0..bufsize; + l: integer; + m: integer; + n: 0..errorline; + p: integer; + q: integer; {:641} + begin + fileptr := inputptr; + inputstack[fileptr] := curinput; + while true do begin + curinput := inputstack[fileptr]; {636:} + if (((fileptr = inputptr) or (curinput.indexfield <= 6)) or (curinput.indexfield <> 10)) or (curinput.locfield <> (-30000)) then begin + tally := 0; + oldsetting := selector; + if curinput.indexfield <= 6 then begin {637:} + if curinput.namefield <= 1 then + if (curinput.namefield = 0) and (fileptr = 0) then + printnl(469) + else + printnl(470) + else if curinput.namefield = 2 then + printnl(471) + else begin + printnl(472); + printint(line) + end; + printchar(32) {:637}; +{644:} + begin + l := tally; + tally := 0; + selector := 4; + trickcount := 1000000 + end; + if curinput.limitfield > 0 then + for i := curinput.startfield to curinput.limitfield - 1 do begin + if i = curinput.locfield then begin + firstcount := tally; + trickcount := ((tally + 1) + errorline) - halferrorline; + if trickcount < errorline then + trickcount := errorline + end; + print(buffer[i]) + end {:644} + end else begin {638:} + if curinput.indexfield in + [7, 8, 9, 10, 11, 12] then + case curinput.indexfield of + 7: + printnl(473); + 8: + begin {639:} + printnl(478); + p := paramstack[curinput.limitfield]; + if p <> (-30000) then + if mem[p].hh.rh = (-29999) then + printexp(p, 0) + else + showtokenlist(p, -30000, 20, tally); + print(479) + end; {:639} + 9: + printnl(474); + 10: + if curinput.locfield = (-30000) then + printnl(475) + else + printnl(476); + 11: + printnl(477); + 12: + begin + println; + if curinput.namefield <> (-30000) then + print(hash[curinput.namefield].rh) {640:} + else begin + p := paramstack[curinput.limitfield]; + if p = (-30000) then + showtokenlist(paramstack[curinput.limitfield + 1], -30000, 20, tally) + else begin + q := p; + while mem[q].hh.rh <> (-30000) do + q := mem[q].hh.rh; + mem[q].hh.rh := paramstack[curinput.limitfield + 1]; + showtokenlist(p, -30000, 20, tally); + mem[q].hh.rh := -30000 + end + end {:640}; + print(368) + end + end + else + printnl(63) {:638}; {645:} + begin + l := tally; + tally := 0; + selector := 4; + trickcount := 1000000 + end; + if curinput.indexfield <> 12 then + showtokenlist(curinput.startfield, curinput.locfield, 100000, 0) + else + showmacro(curinput.startfield, curinput.locfield, 100000) {:645} + end; + selector := oldsetting; {643:} + if trickcount = 1000000 then begin + firstcount := tally; + trickcount := ((tally + 1) + errorline) - halferrorline; + if trickcount < errorline then + trickcount := errorline + end; + if tally < trickcount then + m := tally - firstcount + else + m := trickcount - firstcount; + if (l + firstcount) <= halferrorline then begin + p := 0; + n := l + firstcount + end else begin + print(146); + p := ((l + firstcount) - halferrorline) + 3; + n := halferrorline + end; + for q := p to firstcount - 1 do + printchar(trickbuf[q mod errorline]); + println; + for q := 1 to n do + printchar(32); + if (m + n) <= errorline then + p := firstcount + m + else + p := firstcount + ((errorline - n) - 3); + for q := firstcount to p - 1 do + printchar(trickbuf[q mod errorline]); + if (m + n) > errorline then + print(146) {:643} + end {:636}; + if curinput.indexfield <= 6 then + if (curinput.namefield > 2) or (fileptr = 0) then + goto 30; + fileptr := fileptr - 1 + end; + 30: + curinput := inputstack[inputptr] + end; { showcontext } +{:635} + {649:} + + procedure begintokenlist(p: halfword; t: quarterword); + begin + begin + if inputptr > maxinstack then begin + maxinstack := inputptr; + if inputptr = stacksize then + overflow(480, stacksize) + end; + inputstack[inputptr] := curinput; + inputptr := inputptr + 1 + end; + curinput.startfield := p; + curinput.indexfield := t; + curinput.limitfield := paramptr; + curinput.locfield := p + end; {:649} {650:} + + procedure endtokenlist; + label + 30; + var + p: halfword; + begin + if curinput.indexfield >= 10 then + if curinput.indexfield <= 11 then begin + flushtokenlist(curinput.startfield); + goto 30 + end else + deletemacref(curinput.startfield); + while paramptr > curinput.limitfield do begin + paramptr := paramptr - 1; + p := paramstack[paramptr]; + if p <> (-30000) then + if mem[p].hh.rh = (-29999) then begin + recyclevalue(p); + freenode(p, 2) + end else + flushtokenlist(p) + end; + 30: + begin + inputptr := inputptr - 1; + curinput := inputstack[inputptr] + end; + begin + if interrupt <> 0 then + pauseforinstructions + end + end; {:650} {651:} +{855:} + {856:} + + procedure encapsulate(p: halfword); + begin + curexp := getnode(2); + mem[curexp].hh.b0 := curtype; + mem[curexp].hh.b1 := 11; + newdep(curexp, p) + end; { encapsulate } +{:856} + {858:} + + procedure install(r, q: halfword); + var + p: halfword; + begin + if mem[q].hh.b0 = 16 then begin + mem[r + 1].int := mem[q + 1].int; + mem[r].hh.b0 := 16 + end else if mem[q].hh.b0 = 19 then begin + p := singledependency(q); + if p = depfinal then begin + mem[r].hh.b0 := 16; + mem[r + 1].int := 0; + freenode(p, 2) + end else begin + mem[r].hh.b0 := 17; + newdep(r, p) + end + end else begin + mem[r].hh.b0 := mem[q].hh.b0; + newdep(r, copydeplist(mem[q + 1].hh.rh)) + end + end; {:858} + + procedure makeexpcopy(p: halfword); + label + 20; + var + q, r, t: halfword; + begin + 20: + curtype := mem[p].hh.b0; + if curtype in + [1, 2, 16, 3, 5, 7, 12, 10, + 4, 6, 11, 9, 8, 13, 14, 17, + 18, 15, 19] then + case curtype of + 1, 2, 16: + curexp := mem[p + 1].int; + 3, 5, 7, 12, 10: + curexp := newringentry(p); + 4: + begin + curexp := mem[p + 1].int; + begin + if strref[curexp] < 127 then + strref[curexp] := strref[curexp] + 1 + end + end; + 6: + begin + curexp := mem[p + 1].int; + mem[curexp].hh.lh := mem[curexp].hh.lh + 1 + end; + 11: + curexp := copyedges(mem[p + 1].int); + 9, 8: + curexp := copypath(mem[p + 1].int); + 13, 14: + begin {857:} + if mem[p + 1].int = (-30000) then + initbignode(p); + t := getnode(2); + mem[t].hh.b1 := 11; + mem[t].hh.b0 := curtype; + initbignode(t); + q := mem[p + 1].int + bignodesize[curtype]; + r := mem[t + 1].int + bignodesize[curtype]; + repeat + q := q - 2; + r := r - 2; + install(r, q) + until q = mem[p + 1].int; + curexp := t + end; {:857} + 17, 18: + encapsulate(copydeplist(mem[p + 1].hh.rh)); + 15: + begin + begin + mem[p].hh.b0 := 19; + serialno := serialno + 64; + mem[p + 1].int := serialno + end; + goto 20 + end; + 19: + begin + q := singledependency(p); + if q = depfinal then begin + curtype := 16; + curexp := 0; + freenode(q, 2) + end else begin + curtype := 17; + encapsulate(q) + end + end + end + else + confusion(664) + end; {:855} + + function curtok: halfword; + var + p: halfword; + savetype: smallnumber; + saveexp: integer; + begin + if cursym = 0 then + if curcmd = 38 then begin + savetype := curtype; + saveexp := curexp; + makeexpcopy(curmod); + p := stashcurexp; + mem[p].hh.rh := -30000; + curtype := savetype; + curexp := saveexp + end else begin + p := getnode(2); + mem[p + 1].int := curmod; + mem[p].hh.b1 := 12; + if curcmd = 42 then + mem[p].hh.b0 := 16 + else + mem[p].hh.b0 := 4 + end + else begin + begin + p := avail; + if p = (-30000) then + p := getavail + else begin + avail := mem[p].hh.rh; + mem[p].hh.rh := -30000 + end {dynused:=dynused+1;} + end; + mem[p].hh.lh := cursym + end; + curtok := p + end; {:651} {652:} + + procedure backinput; + var + p: halfword; + s: 0..150; + begin + p := curtok; + while (curinput.indexfield > 6) and (curinput.locfield = (-30000)) do + endtokenlist; + begintokenlist(p, 10) + end; {:652} {653:} + + procedure backerror; + begin + OKtointerrupt := false; + backinput; + OKtointerrupt := true; + error + end; { backerror } + + procedure inserror; + begin + OKtointerrupt := false; + backinput; + curinput.indexfield := 11; + OKtointerrupt := true; + error + end; {:653} {654:} + + procedure beginfilereading; + begin + if inopen = 6 then + overflow(481, 6); + if first = bufsize then + overflow(128, bufsize); + inopen := inopen + 1; + begin + if inputptr > maxinstack then begin + maxinstack := inputptr; + if inputptr = stacksize then + overflow(480, stacksize) + end; + inputstack[inputptr] := curinput; + inputptr := inputptr + 1 + end; + curinput.indexfield := inopen; + linestack[curinput.indexfield] := line; + curinput.startfield := first; + curinput.namefield := 0 + end; {:654} {655:} + + procedure endfilereading; + begin + first := curinput.startfield; + line := linestack[curinput.indexfield]; + if curinput.indexfield <> inopen then + confusion(482); + if curinput.namefield > 2 then + aclose(inputfile[curinput.indexfield]); + begin + inputptr := inputptr - 1; + curinput := inputstack[inputptr] + end; + inopen := inopen - 1 + end; {:655} {656:} + + procedure clearforerrorprompt; + begin + while (((curinput.indexfield <= 6) and (curinput.namefield = 0)) and (inputptr > 0)) and (curinput.locfield = curinput.limitfield) do + endfilereading; + println + end; {:656} {661:} + + function checkoutervalidity: boolean; + var + p: halfword; + begin + if scannerstatus = 0 then + checkoutervalidity := true + else begin + deletionsallowed := false; {662:} + if cursym <> 0 then begin + p := getavail; + mem[p].hh.lh := cursym; + begintokenlist(p, 10) + end {:662}; + if scannerstatus > 1 then begin {663:} + runaway; + if cursym = 0 then begin + if interaction = 3 then + ; + printnl(133); + print(488) + end else begin + begin + if interaction = 3 then + ; + printnl(133); + print(489) + end + end; + print(490); + begin + helpptr := 4; + helpline[3] := 491; + helpline[2] := 492; + helpline[1] := 493; + helpline[0] := 494 + end; + case scannerstatus of {664:} + 2: + begin + print(495); + helpline[3] := 496; + cursym := 2235 + end; + 3: + begin + print(497); + helpline[3] := 498; + if warninginfo = 0 then + cursym := 2239 + else begin + cursym := 2231; + eqtb[2231].rh := warninginfo + end + end; + 4, 5: + begin + print(499); + if scannerstatus = 5 then + print(hash[warninginfo].rh) + else + printvariablename(warninginfo); + cursym := 2237 + end; + 6: + begin + print(500); + print(hash[warninginfo].rh); + print(501); + helpline[3] := 502; + cursym := 2236 + end + end {:664}; + inserror + end else begin {:663} + begin + if interaction = 3 then + ; + printnl(133); + print(483) + end; + printint(warninginfo); + begin + helpptr := 3; + helpline[2] := 484; + helpline[1] := 485; + helpline[0] := 486 + end; + if cursym = 0 then + helpline[2] := 487; + cursym := 2238; + inserror + end; + deletionsallowed := true; + checkoutervalidity := false + end + end; {:661} {666:} + + procedure firmuptheline; + forward; {:666} {667:} + + procedure getnext; + label + 20, 10, 40, 25, 85, 86, 87, 30; + var + k: 0..bufsize; + c: ASCIIcode; + class: ASCIIcode; + n, f: integer; + begin + 20: + cursym := 0; + if curinput.indexfield <= 6 then begin {669:} + 25: + c := buffer[curinput.locfield]; + curinput.locfield := curinput.locfield + 1; + class := charclass[c]; + if class in + [0, 1, 2, 3, 4, 5, 6, 7, + 8, 20] then + case class of + 0: + goto 85; + 1: + begin + class := charclass[buffer[curinput.locfield]]; + if class > 1 then + goto 25 + else if class < 1 then begin + n := 0; + goto 86 + end + end; + 2: + goto 25; + 3: + begin {679:} + if curinput.namefield > 2 then begin {681:} + line := line + 1; + first := curinput.startfield; + if not forceeof then begin + if inputln(inputfile[curinput.indexfield], true) then + firmuptheline + else + forceeof := true + end; + if forceeof then begin + printchar(41); + forceeof := false; + flush(output); + endfilereading; + if checkoutervalidity then + goto 20 + else + goto 20 + end; + buffer[curinput.limitfield] := 37; + first := curinput.limitfield + 1; + curinput.locfield := curinput.startfield + end else begin {:681} + if inputptr > 0 then begin + endfilereading; + goto 20 + end; + if selector < 2 then + openlogfile; + if interaction > 1 then begin + if curinput.limitfield = curinput.startfield then + printnl(517); + println; + first := curinput.startfield; + begin + print(42); + terminput + end; + curinput.limitfield := last; + buffer[curinput.limitfield] := 37; + first := curinput.limitfield + 1; + curinput.locfield := curinput.startfield + end else + fatalerror(518) + end {:679}; + begin + if interrupt <> 0 then + pauseforinstructions + end; + goto 25 + end; + 4: + begin {671:} + if buffer[curinput.locfield] = 34 then + curmod := 155 + else begin + k := curinput.locfield; + buffer[curinput.limitfield + 1] := 34; + repeat + curinput.locfield := curinput.locfield + 1 + until buffer[curinput.locfield] = 34; + if curinput.locfield > curinput.limitfield then begin {672:} + curinput.locfield := curinput.limitfield; + begin + if interaction = 3 then + ; + printnl(133); + print(510) + end; + begin + helpptr := 3; + helpline[2] := 511; + helpline[1] := 512; + helpline[0] := 513 + end; + deletionsallowed := false; + error; + deletionsallowed := true; + goto 20 + end {:672}; + if curinput.locfield = (k + 1) then + curmod := buffer[k] + else begin + begin + if ((poolptr + curinput.locfield) - k) > maxpoolptr then begin + if ((poolptr + curinput.locfield) - k) > poolsize then + overflow(129, poolsize - initpoolptr); + maxpoolptr := (poolptr + curinput.locfield) - k + end + end; + repeat + begin + strpool[poolptr] := buffer[k]; + poolptr := poolptr + 1 + end; + k := k + 1 + until k = curinput.locfield; + curmod := makestring + end + end; + curinput.locfield := curinput.locfield + 1; + curcmd := 39; + goto 10 + end; {:671} + 5, 6, 7, 8: + begin + k := curinput.locfield - 1; + goto 40 + end; + 20: + begin {670:} + begin + if interaction = 3 then + ; + printnl(133); + print(507) + end; + begin + helpptr := 2; + helpline[1] := 508; + helpline[0] := 509 + end; + deletionsallowed := false; + error; + deletionsallowed := true; + goto 20 + end + end + else + {:670}; + k := curinput.locfield - 1; + while charclass[buffer[curinput.locfield]] = class do + curinput.locfield := curinput.locfield + 1; + goto 40; + 85: {673:} + n := c - 48; + while charclass[buffer[curinput.locfield]] = 0 do begin + if n < 4096 then + n := ((10 * n) + buffer[curinput.locfield]) - 48; + curinput.locfield := curinput.locfield + 1 + end; + if buffer[curinput.locfield] = 46 then + if charclass[buffer[curinput.locfield + 1]] = 0 then + goto 30; + f := 0; + goto 87; + 30: + curinput.locfield := curinput.locfield + 1 {:673}; + 86: {674:} + k := 0; + repeat + if k < 17 then begin + dig[k] := buffer[curinput.locfield] - 48; + k := k + 1 + end; + curinput.locfield := curinput.locfield + 1 + until charclass[buffer[curinput.locfield]] <> 0; + f := rounddecimals(k); + if f = 65536 then begin + n := n + 1; + f := 0 + end {:674}; + 87: {675:} + if n < 4096 then + curmod := (n * 65536) + f + else begin + begin + if interaction = 3 then + ; + printnl(133); + print(514) + end; + begin + helpptr := 2; + helpline[1] := 515; + helpline[0] := 516 + end; + deletionsallowed := false; + error; + deletionsallowed := true; + curmod := 268435455 + end; + curcmd := 42; + goto 10 {:675}; + 40: + cursym := idlookup(k, curinput.locfield - k) + end else if curinput.locfield >= himemmin then begin {:669} {676:} + cursym := mem[curinput.locfield].hh.lh; + curinput.locfield := mem[curinput.locfield].hh.rh; + if cursym >= 2242 then + if cursym >= 2392 then begin {677:} + if cursym >= 2542 then + cursym := cursym - 150; + begintokenlist(paramstack[(curinput.limitfield + cursym) - 2392], 9); + goto 20 + end else begin {:677} + curcmd := 38; + curmod := paramstack[(curinput.limitfield + cursym) - 2242]; + cursym := 0; + goto 10 + end + end else if curinput.locfield > (-30000) then begin {678:} + if mem[curinput.locfield].hh.b1 = 12 then begin + curmod := mem[curinput.locfield + 1].int; + if mem[curinput.locfield].hh.b0 = 16 then + curcmd := 42 + else begin + curcmd := 39; + begin + if strref[curmod] < 127 then + strref[curmod] := strref[curmod] + 1 + end + end + end else begin + curmod := curinput.locfield; + curcmd := 38 + end; + curinput.locfield := mem[curinput.locfield].hh.rh; + goto 10 + end else begin {:678} + endtokenlist; + goto 20 + end {:676}; {668:} + curcmd := eqtb[cursym].lh; + curmod := eqtb[cursym].rh; + if curcmd >= 83 then + if checkoutervalidity then + curcmd := curcmd - 83 + else + goto 20 {:668}; + 10: + + end; {:667} {682:} + + procedure firmuptheline; + var + k: 0..bufsize; + begin + curinput.limitfield := last; + if internal[31] > 0 then + if interaction > 1 then begin + println; + if curinput.startfield < curinput.limitfield then + for k := curinput.startfield to curinput.limitfield - 1 do + print(buffer[k]); + first := curinput.limitfield; + begin + print(519); + terminput + end; + if last > first then begin + for k := first to last - 1 do + buffer[(k + curinput.startfield) - first] := buffer[k]; + curinput.limitfield := (curinput.startfield + last) - first + end + end + end; {:682} +{685:} + + function scantoks(terminator: commandcode; substlist, tailend: halfword; suffixcount: smallnumber): halfword; + label + 30, 40; + var + p: halfword; + q: halfword; + balance: integer; + begin + p := 29998; + balance := 1; + mem[29998].hh.rh := -30000; + while true do begin + getnext; + if cursym > 0 then begin {686:} + begin + q := substlist; + while q <> (-30000) do begin + if mem[q].hh.lh = cursym then begin + cursym := mem[q + 1].int; + curcmd := 7; + goto 40 + end; + q := mem[q].hh.rh + end; + 40: {:686} + + end; + if curcmd = terminator then {687:} + if curmod > 0 then + balance := balance + 1 + else begin + balance := balance - 1; + if balance = 0 then + goto 30 + end {:687} + else if curcmd = 61 then begin {690:} + if curmod = 0 then + getnext + else if curmod <= suffixcount then + cursym := 2391 + curmod + end {:690} + end; + mem[p].hh.rh := curtok; + p := mem[p].hh.rh + end; + 30: + mem[p].hh.rh := tailend; + flushnodelist(substlist); + scantoks := mem[29998].hh.rh + end; {:685} {691:} + + procedure getsymbol; + label + 20; + begin + 20: + getnext; + if (cursym = 0) or (cursym > 2229) then begin + begin + if interaction = 3 then + ; + printnl(133); + print(531) + end; + begin + helpptr := 3; + helpline[2] := 532; + helpline[1] := 533; + helpline[0] := 534 + end; + if cursym > 0 then + helpline[2] := 535 + else if curcmd = 39 then begin + if strref[curmod] < 127 then + if strref[curmod] > 1 then + strref[curmod] := strref[curmod] - 1 + else + flushstring(curmod) + end; + cursym := 2229; + inserror; + goto 20 + end + end; { getsymbol } +{:691} + {692:} + + procedure getclearsymbol; + begin + getsymbol; + clearsymbol(cursym, false) + end; {:692} {693:} + + procedure checkequals; + begin + if curcmd <> 51 then + if curcmd <> 77 then begin + missingerr(61); + begin + helpptr := 5; + helpline[4] := 536; + helpline[3] := 537; + helpline[2] := 538; + helpline[1] := 539; + helpline[0] := 540 + end; + backerror + end + end; {:693} {694:} + + procedure makeopdef; + var + m: commandcode; + p, q, r: halfword; + begin + m := curmod; + getsymbol; + q := getnode(2); + mem[q].hh.lh := cursym; + mem[q + 1].int := 2242; + getclearsymbol; + warninginfo := cursym; + getsymbol; + p := getnode(2); + mem[p].hh.lh := cursym; + mem[p + 1].int := 2243; + mem[p].hh.rh := q; + getnext; + checkequals; + scannerstatus := 5; + q := getavail; + mem[q].hh.lh := -30000; + r := getavail; + mem[q].hh.rh := r; + mem[r].hh.lh := 0; + mem[r].hh.rh := scantoks(16, p, -30000, 0); + scannerstatus := 0; + eqtb[warninginfo].lh := m; + eqtb[warninginfo].rh := q; + getxnext + end; {:694} +{697:} + {1032:} + + procedure checkdelimiter(ldelim, rdelim: halfword); + label + 10; + begin + if curcmd = 62 then + if curmod = ldelim then + goto 10; + if cursym <> rdelim then begin + missingerr(hash[rdelim].rh); + begin + helpptr := 2; + helpline[1] := 786; + helpline[0] := 787 + end; + backerror + end else begin + begin + if interaction = 3 then + ; + printnl(133); + print(788) + end; + print(hash[rdelim].rh); + print(789); + begin + helpptr := 3; + helpline[2] := 790; + helpline[1] := 791; + helpline[0] := 792 + end; + error + end; + 10: + + end; {:1032} {1011:} + + function scandeclaredvariable: halfword; + label + 30; + var + x: halfword; + h, t: halfword; + l: halfword; + begin + getsymbol; + x := cursym; + if curcmd <> 41 then + clearsymbol(x, false); + if eqtb[x].rh = (-30000) then + newroot(x); + h := getavail; + mem[h].hh.lh := x; + t := h; + while true do begin + getxnext; + if cursym = 0 then + goto 30; + if curcmd <> 41 then + if curcmd <> 40 then + if curcmd = 63 then begin {1012:} + l := cursym; + getxnext; + if curcmd <> 64 then begin + backinput; + cursym := l; + curcmd := 63; + goto 30 + end else + cursym := 0 + end else {:1012} + goto 30; + mem[t].hh.rh := getavail; + t := mem[t].hh.rh; + mem[t].hh.lh := cursym + end; + 30: + scandeclaredvariable := h + end; {:1011} + + procedure scandef; + var + m: 1..2; + n: 0..3; + k: 0..150; + c: 0..7; + r: halfword; + q: halfword; + p: halfword; + base: halfword; + ldelim, rdelim: halfword; + begin + m := curmod; + c := 0; + mem[29998].hh.rh := -30000; + q := getavail; + mem[q].hh.lh := -30000; + r := -30000; {700:} + if m = 1 then begin + getclearsymbol; + warninginfo := cursym; + getnext; + scannerstatus := 5; + n := 0; + eqtb[warninginfo].lh := 10; + eqtb[warninginfo].rh := q + end else begin + p := scandeclaredvariable; + flushvariable(eqtb[mem[p].hh.lh].rh, mem[p].hh.rh, true); + warninginfo := findvariable(p); + flushlist(p); + if warninginfo = (-30000) then begin {701:} + begin + if interaction = 3 then + ; + printnl(133); + print(547) + end; + begin + helpptr := 2; + helpline[1] := 548; + helpline[0] := 549 + end; + error; + warninginfo := -29979 + end {:701}; + scannerstatus := 4; + n := 2; + if curcmd = 61 then + if curmod = 3 then begin + n := 3; + getnext + end; + mem[warninginfo].hh.b0 := 20 + n; + mem[warninginfo + 1].int := q + end {:700}; + k := n; + if curcmd = 31 then {703:} + repeat + ldelim := cursym; + rdelim := curmod; + getnext; + if (curcmd = 56) and (curmod >= 2242) then + base := curmod + else begin + begin + if interaction = 3 then + ; + printnl(133); + print(550) + end; + begin + helpptr := 1; + helpline[0] := 551 + end; + backerror; + base := 2242 + end; {704:} + repeat + mem[q].hh.rh := getavail; + q := mem[q].hh.rh; + mem[q].hh.lh := base + k; + getsymbol; + p := getnode(2); + mem[p + 1].int := base + k; + mem[p].hh.lh := cursym; + if k = 150 then + overflow(552, 150); + k := k + 1; + mem[p].hh.rh := r; + r := p; + getnext + until curcmd <> 79 {:704}; + checkdelimiter(ldelim, rdelim); + getnext + until curcmd <> 31 {:703}; + if curcmd = 56 then begin {705:} + p := getnode(2); + if curmod < 2242 then begin + c := curmod; + mem[p + 1].int := 2242 + k + end else begin + mem[p + 1].int := curmod + k; + if curmod = 2242 then + c := 4 + else if curmod = 2392 then + c := 6 + else + c := 7 + end; + if k = 150 then + overflow(552, 150); + k := k + 1; + getsymbol; + mem[p].hh.lh := cursym; + mem[p].hh.rh := r; + r := p; + getnext; + if c = 4 then + if curcmd = 69 then begin + c := 5; + p := getnode(2); + if k = 150 then + overflow(552, 150); + mem[p + 1].int := 2242 + k; + getsymbol; + mem[p].hh.lh := cursym; + mem[p].hh.rh := r; + r := p; + getnext + end + end {:705}; + checkequals; + p := getavail; + mem[p].hh.lh := c; + mem[q].hh.rh := p; {698:} + if m = 1 then + mem[p].hh.rh := scantoks(16, r, -30000, n) + else begin + q := getavail; + mem[q].hh.lh := bgloc; + mem[p].hh.rh := q; + p := getavail; + mem[p].hh.lh := egloc; + mem[q].hh.rh := scantoks(16, r, p, n) + end; + if warninginfo = (-29979) then + flushtokenlist(mem[-29978].int) {:698}; + scannerstatus := 0; + getxnext + end; {:697} {706:} + + procedure scanprimary; + forward; + + procedure scansecondary; + forward; + + procedure scantertiary; + forward; + + procedure scanexpression; + forward; + + procedure scansuffix; + forward; {720:} +{722:} + + procedure printmacroname(a, n: halfword); + var + p, q: halfword; + begin + if n <> (-30000) then + print(hash[n].rh) + else begin + p := mem[a].hh.lh; + if p = (-30000) then + print(hash[mem[mem[mem[a].hh.rh].hh.lh].hh.lh].rh) + else begin + q := p; + while mem[q].hh.rh <> (-30000) do + q := mem[q].hh.rh; + mem[q].hh.rh := mem[mem[a].hh.rh].hh.lh; + showtokenlist(p, -30000, 1000, 0); + mem[q].hh.rh := -30000 + end + end + end; {:722} {723:} + + procedure printarg(q: halfword; n: integer; b: halfword); + begin + if mem[q].hh.rh = (-29999) then + printnl(365) + else if (b < 2542) and (b <> 7) then + printnl(366) + else + printnl(367); + printint(n); + print(568); + if mem[q].hh.rh = (-29999) then + printexp(q, 1) + else + showtokenlist(q, -30000, 1000, 0) + end; {:723} {730:} + + procedure scantextarg(ldelim, rdelim: halfword); + label + 30; + var + balance: integer; + p: halfword; + begin + warninginfo := ldelim; + scannerstatus := 3; + p := 29998; + balance := 1; + mem[29998].hh.rh := -30000; + while true do begin + getnext; + if ldelim = 0 then begin {732:} + if curcmd > 79 then begin + if balance = 1 then + goto 30 + else if curcmd = 81 then + balance := balance - 1 + end else if curcmd = 32 then + balance := balance + 1 + end else begin {:732} {731:} + if curcmd = 62 then begin + if curmod = ldelim then begin + balance := balance - 1; + if balance = 0 then + goto 30 + end + end else if curcmd = 31 then + if curmod = rdelim then + balance := balance + 1 + end {:731}; + mem[p].hh.rh := curtok; + p := mem[p].hh.rh + end; + 30: + curexp := mem[29998].hh.rh; + curtype := 20; + scannerstatus := 0 + end; {:730} + + procedure macrocall(defref, arglist, macroname: halfword); + label + 40; + var + r: halfword; + p, q: halfword; + n: integer; + ldelim, rdelim: halfword; + tail: halfword; + begin + r := mem[defref].hh.rh; + mem[defref].hh.lh := mem[defref].hh.lh + 1; + if arglist = (-30000) then + n := 0 {724:} + else begin + n := 1; + tail := arglist; + while mem[tail].hh.rh <> (-30000) do begin + n := n + 1; + tail := mem[tail].hh.rh + end + end {:724}; + if internal[9] > 0 then begin {721:} + begindiagnostic; + println; + printmacroname(arglist, macroname); + if n = 3 then + print(530); + showmacro(defref, -30000, 100000); + if arglist <> (-30000) then begin + n := 0; + p := arglist; + repeat + q := mem[p].hh.lh; + printarg(q, n, 0); + n := n + 1; + p := mem[p].hh.rh + until p = (-30000) + end; + enddiagnostic(false) + end {:721}; {725:} + curcmd := 80; + while mem[r].hh.lh >= 2242 do begin {726:} + if curcmd <> 79 then begin + getxnext; + if curcmd <> 31 then begin + begin + if interaction = 3 then + ; + printnl(133); + print(574) + end; + printmacroname(arglist, macroname); + begin + helpptr := 3; + helpline[2] := 575; + helpline[1] := 576; + helpline[0] := 577 + end; + if mem[r].hh.lh >= 2392 then begin + curexp := -30000; + curtype := 20 + end else begin + curexp := 0; + curtype := 16 + end; + backerror; + curcmd := 62; + goto 40 + end; + ldelim := cursym; + rdelim := curmod + end; {729:} + if mem[r].hh.lh >= 2542 then + scantextarg(ldelim, rdelim) + else begin + getxnext; + if mem[r].hh.lh >= 2392 then + scansuffix + else + scanexpression + end {:729}; + if curcmd <> 79 then {727:} + if (curcmd <> 62) or (curmod <> ldelim) then + if mem[mem[r].hh.rh].hh.lh >= 2242 then begin + missingerr(44); + begin + helpptr := 3; + helpline[2] := 578; + helpline[1] := 579; + helpline[0] := 573 + end; + backerror; + curcmd := 79 + end else begin + missingerr(hash[rdelim].rh); + begin + helpptr := 2; + helpline[1] := 580; + helpline[0] := 573 + end; + backerror + end {:727}; + 40: {728:} + begin + p := getavail; + if curtype = 20 then + mem[p].hh.lh := curexp + else + mem[p].hh.lh := stashcurexp; + if internal[9] > 0 then begin + begindiagnostic; + printarg(mem[p].hh.lh, n, mem[r].hh.lh); + enddiagnostic(false) + end; + if arglist = (-30000) then + arglist := p + else + mem[tail].hh.rh := p; + tail := p; + n := n + 1 + end {:728} {:726}; + r := mem[r].hh.rh + end; + if curcmd = 79 then begin + begin + if interaction = 3 then + ; + printnl(133); + print(569) + end; + printmacroname(arglist, macroname); + printchar(59); + printnl(570); + print(hash[rdelim].rh); + print(170); + begin + helpptr := 3; + helpline[2] := 571; + helpline[1] := 572; + helpline[0] := 573 + end; + error + end; + if mem[r].hh.lh <> 0 then begin {733:} + if mem[r].hh.lh < 7 then begin + getxnext; + if mem[r].hh.lh <> 6 then + if (curcmd = 51) or (curcmd = 77) then + getxnext + end; + case mem[r].hh.lh of + 1: + scanprimary; + 2: + scansecondary; + 3: + scantertiary; + 4: + scanexpression; + 5: + begin {734:} + scanexpression; + p := getavail; + mem[p].hh.lh := stashcurexp; + if internal[9] > 0 then begin + begindiagnostic; + printarg(mem[p].hh.lh, n, 0); + enddiagnostic(false) + end; + if arglist = (-30000) then + arglist := p + else + mem[tail].hh.rh := p; + tail := p; + n := n + 1; + if curcmd <> 69 then begin + missingerr(347); + print(581); + printmacroname(arglist, macroname); + begin + helpptr := 1; + helpline[0] := 582 + end; + backerror + end; + getxnext; + scanprimary + end; {:734} + 6: + begin {735:} + if curcmd <> 31 then + ldelim := -30000 + else begin + ldelim := cursym; + rdelim := curmod; + getxnext + end; + scansuffix; + if ldelim <> (-30000) then begin + if (curcmd <> 62) or (curmod <> ldelim) then begin + missingerr(hash[rdelim].rh); + begin + helpptr := 2; + helpline[1] := 580; + helpline[0] := 573 + end; + backerror + end; + getxnext + end + end; {:735} + 7: + scantextarg(0, 0) + end; + backinput; {728:} + begin + p := getavail; + if curtype = 20 then + mem[p].hh.lh := curexp + else + mem[p].hh.lh := stashcurexp; + if internal[9] > 0 then begin + begindiagnostic; + printarg(mem[p].hh.lh, n, mem[r].hh.lh); + enddiagnostic(false) + end; + if arglist = (-30000) then + arglist := p + else + mem[tail].hh.rh := p; + tail := p; + n := n + 1 + end {:728} + end {:733}; + r := mem[r].hh.rh {:725}; {736:} + while (curinput.indexfield > 6) and (curinput.locfield = (-30000)) do + endtokenlist; + if (paramptr + n) > maxparamstack then begin + maxparamstack := paramptr + n; + if maxparamstack > 150 then + overflow(552, 150) + end; + begintokenlist(defref, 12); + curinput.namefield := macroname; + curinput.locfield := r; + if n > 0 then begin + p := arglist; + repeat + paramstack[paramptr] := mem[p].hh.lh; + paramptr := paramptr + 1; + p := mem[p].hh.rh + until p = (-30000); + flushlist(arglist) + end {:736} + end; {:720} + + procedure getboolean; + forward; + + procedure passtext; + forward; + + procedure conditional; + forward; + + procedure startinput; + forward; + + procedure beginiteration; + forward; + + procedure resumeiteration; + forward; + + procedure stopiteration; + forward; {:706} {707:} + + procedure expand; + var + p: halfword; + k: integer; + j: poolpointer; + begin + if internal[7] > 65536 then + if curcmd <> 10 then + showcmdmod(curcmd, curmod); + case curcmd of + 1: + conditional; + 2: {751:} + if curmod > iflimit then + if iflimit = 1 then begin + missingerr(58); + backinput; + cursym := 2234; + inserror + end else begin + begin + if interaction = 3 then + ; + printnl(133); + print(589) + end; + printcmdmod(2, curmod); + begin + helpptr := 1; + helpline[0] := 590 + end; + error + end + else begin + while curmod <> 2 do + passtext; +{745:} + begin + p := condptr; + ifline := mem[p + 1].int; + curif := mem[p].hh.b1; + iflimit := mem[p].hh.b0; + condptr := mem[p].hh.rh; + freenode(p, 2) + end {:745} + end {:751}; + 3: {711:} + if curmod > 0 then + forceeof := true + else {:711} + startinput; + 4: + if curmod = 0 then begin {708:} + begin + if interaction = 3 then + ; + printnl(133); + print(553) + end; + begin + helpptr := 2; + helpline[1] := 554; + helpline[0] := 555 + end; + error + end else {:708} + beginiteration; + 5: + begin {712:} + while (curinput.indexfield > 6) and (curinput.locfield = (-30000)) do + endtokenlist; + if loopptr = (-30000) then begin + begin + if interaction = 3 then + ; + printnl(133); + print(557) + end; + begin + helpptr := 2; + helpline[1] := 558; + helpline[0] := 559 + end; + error + end else + resumeiteration + end; {:712} + 6: + begin {713:} + getboolean; + if internal[7] > 65536 then + showcmdmod(33, curexp); + if curexp = 30 then + if loopptr = (-30000) then begin + begin + if interaction = 3 then + ; + printnl(133); + print(560) + end; + begin + helpptr := 1; + helpline[0] := 561 + end; + if curcmd = 80 then + error + else + backerror + end else begin {714:} + p := -30000; + repeat + if curinput.indexfield <= 6 then + endfilereading + else begin + if curinput.indexfield <= 8 then + p := curinput.startfield; + endtokenlist + end + until p <> (-30000); + if p <> mem[loopptr].hh.lh then + fatalerror(564); + stopiteration + end {:714} + else if curcmd <> 80 then begin + missingerr(59); + begin + helpptr := 2; + helpline[1] := 562; + helpline[0] := 563 + end; + backerror + end + end; {:713} + 7: + ; + 9: + begin {715:} + getnext; + p := curtok; + getnext; + if curcmd < 11 then + expand + else + backinput; + begintokenlist(p, 10) + end; {:715} + 8: + begin {716:} + getxnext; + scanprimary; + if curtype <> 4 then begin + disperr(-30000, 565); + begin + helpptr := 2; + helpline[1] := 566; + helpline[0] := 567 + end; + putgetflusherror(0) + end else begin + backinput; + if (strstart[curexp + 1] - strstart[curexp]) > 0 then begin {717:} + beginfilereading; + curinput.namefield := 2; + k := first + (strstart[curexp + 1] - strstart[curexp]); + if k >= maxbufstack then begin + if k >= bufsize then begin + maxbufstack := bufsize; + overflow(128, bufsize) + end; + maxbufstack := k + 1 + end; + j := strstart[curexp]; + curinput.limitfield := k; + while first < curinput.limitfield do begin + buffer[first] := strpool[j]; + j := j + 1; + first := first + 1 + end; + buffer[curinput.limitfield] := 37; + first := curinput.limitfield + 1; + curinput.locfield := curinput.startfield; + flushcurexp(0) + end {:717} + end + end; {:716} + 10: + macrocall(curmod, -30000, cursym) + end + end; {:707} {718:} + + procedure getxnext; + var + saveexp: halfword; + begin + getnext; + if curcmd < 11 then begin + saveexp := stashcurexp; + repeat + if curcmd = 10 then + macrocall(curmod, -30000, cursym) + else + expand; + getnext + until curcmd >= 11; + unstashcurexp(saveexp) + end + end; {:718} {737:} + + procedure stackargument(p: halfword); + begin + if paramptr = maxparamstack then begin + maxparamstack := maxparamstack + 1; + if maxparamstack > 150 then + overflow(552, 150) + end; + paramstack[paramptr] := p; + paramptr := paramptr + 1 + end; {:737} {742:} + + procedure passtext; + label + 30; + var + l: integer; + begin + scannerstatus := 1; + l := 0; + warninginfo := line; + while true do begin + getnext; + if curcmd <= 2 then + if curcmd < 2 then + l := l + 1 + else begin + if l = 0 then + goto 30; + if curmod = 2 then + l := l - 1 + end {743:} + else if curcmd = 39 then begin + if strref[curmod] < 127 then + if strref[curmod] > 1 then + strref[curmod] := strref[curmod] - 1 + else + flushstring(curmod) + end {:743} + end; + 30: + scannerstatus := 0 + end; {:742} {746:} + + procedure changeiflimit(l: smallnumber; p: halfword); + label + 10; + var + q: halfword; + begin + if p = condptr then + iflimit := l + else begin + q := condptr; + while true do begin + if q = (-30000) then + confusion(583); + if mem[q].hh.rh = p then begin + mem[q].hh.b0 := l; + goto 10 + end; + q := mem[q].hh.rh + end + end; + 10: + + end; {:746} {747:} + + procedure checkcolon; + begin + if curcmd <> 78 then begin + missingerr(58); + begin + helpptr := 2; + helpline[1] := 586; + helpline[0] := 563 + end; + backerror + end + end; {:747} {748:} + + procedure conditional; + label + 10, 30, 21, 40; + var + savecondptr: halfword; + newiflimit: 2..4; + p: halfword; {744:} + begin + begin + p := getnode(2); + mem[p].hh.rh := condptr; + mem[p].hh.b0 := iflimit; + mem[p].hh.b1 := curif; + mem[p + 1].int := ifline; + condptr := p; + iflimit := 1; + ifline := line; + curif := 1 + end {:744}; + savecondptr := condptr; + 21: + getboolean; + newiflimit := 4; + if internal[7] > 65536 then begin {750:} + begindiagnostic; + if curexp = 30 then + print(587) + else + print(588); + enddiagnostic(false) + end {:750}; + 40: + checkcolon; + if curexp = 30 then begin + changeiflimit(newiflimit, savecondptr); + goto 10 + end; {749:} + while true do begin + passtext; + if condptr = savecondptr then + goto 30 + else if curmod = 2 then begin {745:} + p := condptr; + ifline := mem[p + 1].int; + curif := mem[p].hh.b1; + iflimit := mem[p].hh.b0; + condptr := mem[p].hh.rh; + freenode(p, 2) + end {:745} + end {:749}; + 30: + curif := curmod; + ifline := line; + if curmod = 2 then begin {745:} + p := condptr; + ifline := mem[p + 1].int; + curif := mem[p].hh.b1; + iflimit := mem[p].hh.b0; + condptr := mem[p].hh.rh; + freenode(p, 2) + end else if curmod = 4 then {:745} + goto 21 + else begin + curexp := 30; + newiflimit := 2; + getxnext; + goto 40 + end; + 10: + + end; {:748} {754:} + + procedure badfor(s: strnumber); + begin + disperr(-30000, 591); + print(s); + print(177); + begin + helpptr := 4; + helpline[3] := 592; + helpline[2] := 593; + helpline[1] := 594; + helpline[0] := 179 + end; + putgetflusherror(0) + end; {:754} {755:} + + procedure beginiteration; + label + 22, 30, 40; + var + m: halfword; + n: halfword; + p, q, s, pp: halfword; + begin + m := curmod; + n := cursym; + s := getnode(2); + if m = 1 then begin + mem[s + 1].hh.lh := -29999; + p := -30000; + getxnext; + goto 40 + end; + getsymbol; + p := getnode(2); + mem[p].hh.lh := cursym; + mem[p + 1].int := m; + getxnext; + if (curcmd <> 51) and (curcmd <> 77) then begin + missingerr(61); + begin + helpptr := 3; + helpline[2] := 595; + helpline[1] := 538; + helpline[0] := 596 + end; + backerror + end; +{764:} + mem[s + 1].hh.lh := -30000; + q := s + 1; + mem[q].hh.rh := -30000; + repeat + getxnext; + if m <> 2242 then + scansuffix + else begin + if curcmd >= 78 then + if curcmd <= 79 then + goto 22; + scanexpression; + if curcmd = 74 then + if q = (s + 1) then begin {765:} + if curtype <> 16 then + badfor(602); + pp := getnode(4); + mem[pp + 1].int := curexp; + getxnext; + scanexpression; + if curtype <> 16 then + badfor(603); + mem[pp + 2].int := curexp; + if curcmd <> 75 then begin + missingerr(357); + begin + helpptr := 2; + helpline[1] := 604; + helpline[0] := 605 + end; + backerror + end; + getxnext; + scanexpression; + if curtype <> 16 then + badfor(606); + mem[pp + 3].int := curexp; + mem[s + 1].hh.lh := pp; + goto 30 + end {:765}; + curexp := stashcurexp + end; + mem[q].hh.rh := getavail; + q := mem[q].hh.rh; + mem[q].hh.lh := curexp; + curtype := 1; + 22: + + until curcmd <> 79; + 30: {:764} + ; + 40: {756:} + if curcmd <> 78 then begin + missingerr(58); + begin + helpptr := 3; + helpline[2] := 597; + helpline[1] := 598; + helpline[0] := 599 + end; + backerror + end {:756}; {758:} + q := getavail; + mem[q].hh.lh := 2230; + scannerstatus := 6; + warninginfo := n; + mem[s].hh.lh := scantoks(4, p, q, 0); + scannerstatus := 0; + mem[s].hh.rh := loopptr; + loopptr := s {:758}; + resumeiteration + end; {:755} {760:} + + procedure resumeiteration; + label + 45, 10; + var + p, q: halfword; + begin + p := mem[loopptr + 1].hh.lh; + if p > (-29999) then begin + curexp := mem[p + 1].int; {761:} + if ((mem[p + 2].int > 0) and (curexp > mem[p + 3].int)) or ((mem[p + 2].int < 0) and (curexp < mem[p + 3].int)) then {:761} + goto 45; + curtype := 16; + q := stashcurexp; + mem[p + 1].int := curexp + mem[p + 2].int + end else if p < (-29999) then begin + p := mem[loopptr + 1].hh.rh; + if p = (-30000) then + goto 45; + mem[loopptr + 1].hh.rh := mem[p].hh.rh; + q := mem[p].hh.lh; + begin + mem[p].hh.rh := avail; + avail := p + end {dynused:=dynused-1;} + end else begin + begintokenlist(mem[loopptr].hh.lh, 7); + goto 10 + end; + begintokenlist(mem[loopptr].hh.lh, 8); + stackargument(q); + if internal[7] > 65536 then begin {762:} + begindiagnostic; + printnl(601); + if (q <> (-30000)) and (mem[q].hh.rh = (-29999)) then + printexp(q, 1) + else + showtokenlist(q, -30000, 50, 0); + printchar(125); + enddiagnostic(false) + end {:762}; + goto 10; + 45: + stopiteration; + 10: + + end; {:760} {763:} + + procedure stopiteration; + var + p, q: halfword; + begin + p := mem[loopptr + 1].hh.lh; + if p > (-29999) then + freenode(p, 4) + else if p < (-29999) then begin + q := mem[loopptr + 1].hh.rh; + while q <> (-30000) do begin + p := mem[q].hh.lh; + if p <> (-30000) then + if mem[p].hh.rh = (-29999) then begin + recyclevalue(p); + freenode(p, 2) + end else + flushtokenlist(p); + p := q; + q := mem[q].hh.rh; + begin + mem[p].hh.rh := avail; + avail := p + end {dynused:=dynused-1;} + end + end; + p := loopptr; + loopptr := mem[p].hh.rh; + flushtokenlist(mem[p].hh.lh); + freenode(p, 2) + end; {:763} {770:} + + procedure beginname; + begin + areadelimiter := 0; + extdelimiter := 0 + end; {:770} {771:} + + function morename(c: ASCIIcode): boolean; + begin + if (c = 32) or (c = 9) then + morename := false + else begin + if c = 47 then begin + areadelimiter := poolptr; + extdelimiter := 0 + end else if (c = 46) and (extdelimiter = 0) then + extdelimiter := poolptr; + begin + if (poolptr + 1) > maxpoolptr then begin + if (poolptr + 1) > poolsize then + overflow(129, poolsize - initpoolptr); + maxpoolptr := poolptr + 1 + end + end; + begin + strpool[poolptr] := c; + poolptr := poolptr + 1 + end; + morename := true + end + end; { morename } +{:771} + {772:} + + procedure endname; + begin + if (strptr + 3) > maxstrptr then begin + if (strptr + 3) > maxstrings then + overflow(130, maxstrings - initstrptr); + maxstrptr := strptr + 3 + end; + if areadelimiter = 0 then + curarea := 155 + else begin + curarea := strptr; + strptr := strptr + 1; + strstart[strptr] := areadelimiter + 1 + end; + if extdelimiter = 0 then begin + curext := 155; + curname := makestring + end else begin + curname := strptr; + strptr := strptr + 1; + strstart[strptr] := extdelimiter; + curext := makestring + end + end; {:772} {774:} + + procedure packfilename(n, a, e: strnumber); + var + k: integer; + c: ASCIIcode; + j: poolpointer; + begin + k := 0; + for j := strstart[a] to strstart[a + 1] - 1 do begin + c := strpool[j]; + k := k + 1; + if k <= filenamesize then + nameoffile[k] := xchr[c] + end; + for j := strstart[n] to strstart[n + 1] - 1 do begin + c := strpool[j]; + k := k + 1; + if k <= filenamesize then + nameoffile[k] := xchr[c] + end; + for j := strstart[e] to strstart[e + 1] - 1 do begin + c := strpool[j]; + k := k + 1; + if k <= filenamesize then + nameoffile[k] := xchr[c] + end; + if k <= filenamesize then + namelength := k + else + namelength := filenamesize; + for k := namelength + 1 to filenamesize do + nameoffile[k] := ' ' + end; {:774} +{778:} + + procedure packbufferedname(n: smallnumber; a, b: integer); + var + k: integer; + c: ASCIIcode; + j: integer; + begin + if (((n + b) - a) + 6) > filenamesize then + b := ((a + filenamesize) - n) - 6; + k := 0; + for j := 1 to n do begin + c := xord[MFbasedefault[j]]; + k := k + 1; + if k <= filenamesize then + nameoffile[k] := xchr[c] + end; + for j := a to b do begin + c := buffer[j]; + k := k + 1; + if k <= filenamesize then + nameoffile[k] := xchr[c] + end; + for j := 6 to 10 do begin + c := xord[MFbasedefault[j]]; + k := k + 1; + if k <= filenamesize then + nameoffile[k] := xchr[c] + end; + if k <= filenamesize then + namelength := k + else + namelength := filenamesize; + for k := namelength + 1 to filenamesize do + nameoffile[k] := ' ' + end; {:778} +{780:} + + function makenamestring: strnumber; + var + k, kstart: 1..filenamesize; + begin + k := 1; + while (k < filenamesize) and (xord[realnameoffile[k]] <> 32) do + k := k + 1; + namelength := k - 1; + if ((poolptr + namelength) > poolsize) or (strptr = maxstrings) then + makenamestring := 63 + else begin + if (xord[realnameoffile[1]] = 46) and (xord[realnameoffile[2]] = 47) then + kstart := 3 + else + kstart := 1; + for k := kstart to namelength do begin + strpool[poolptr] := xord[realnameoffile[k]]; + poolptr := poolptr + 1 + end; + makenamestring := makestring + end + end; + + function amakenamestring(var f: alphafile): strnumber; + begin + amakenamestring := makenamestring + end; { amakenamestring } + + function bmakenamestring(var f: bytefile): strnumber; + begin + bgetname(f, realnameoffile); + bmakenamestring := makenamestring + end; { bmakenamestring } + + function wmakenamestring(var f: wordfile): strnumber; + begin + wmakenamestring := makenamestring + end; {:780} {781:} + + procedure scanfilename; + label + 30; + begin + beginname; + while (buffer[curinput.locfield] = 32) or (buffer[curinput.locfield] = 9) do + curinput.locfield := curinput.locfield + 1; + while true do begin + if (buffer[curinput.locfield] = 59) or (buffer[curinput.locfield] = 37) then + goto 30; + if not morename(buffer[curinput.locfield]) then + goto 30; + curinput.locfield := curinput.locfield + 1 + end; + 30: + endname + end; {:781} {784:} + + procedure packjobname(s: strnumber); + begin + curarea := 155; + curext := s; + curname := jobname; + packfilename(curname, curarea, curext) + end; {:784} {786:} + + procedure promptfilename(s, e: strnumber); + label + 30; + var + k: 0..bufsize; + begin + if interaction = 2 then + ; + if s = 607 then begin + if interaction = 3 then + ; + printnl(133); + print(608) + end else begin + if interaction = 3 then + ; + printnl(133); + print(609) + end; + printfilename(curname, curarea, curext); + print(610); + if e = 611 then + showcontext; + printnl(612); + print(s); + if interaction < 2 then + fatalerror(613); + begin + print(614); + terminput + end; +{787:} + begin + beginname; + k := first; + while ((buffer[k] = 32) or (buffer[k] = 9)) and (k < last) do + k := k + 1; + while true do begin + if k = last then + goto 30; + if not morename(buffer[k]) then + goto 30; + k := k + 1 + end; + 30: + endname + end {:787}; + if curext = 155 then + curext := e; + packfilename(curname, curarea, curext) + end; { promptfilename } +{:786} + {788:} + + procedure openlogfile; + var + oldsetting: 0..5; + k: 0..bufsize; + l: 0..bufsize; + m: integer; + months: packed array [1..36] of char; + begin + oldsetting := selector; + if jobname = 0 then + jobname := 615; + packjobname(616); + while not aopenout(logfile) do begin {789:} + if interaction < 2 then begin + begin + if interaction = 3 then + ; + printnl(133); + print(609) + end; + printfilename(curname, curarea, curext); + print(610); + jobname := 0; + history := 3; + jumpout + end; + promptfilename(618, 616) + end {:789}; + logname := amakenamestring(logfile); + selector := 2; {790:} + begin + write(logfile, 'This is METAFONT, Version 1.0 for Berkeley UNIX'); + print(baseident); + print(619); + printint(roundunscaled(internal[16])); + printchar(32); + months := 'JANFEBMARAPRMAYJUNJULAUGSEPOCTNOVDEC'; + m := roundunscaled(internal[15]); + for k := (3 * m) - 2 to 3 * m do + write(logfile, months[k]); + printchar(32); + printint(roundunscaled(internal[14])); + printchar(32); + m := roundunscaled(internal[17]); + printdd(m div 60); + printchar(58); + printdd(m mod 60) + end {:790}; + inputstack[inputptr] := curinput; + printnl(617); + l := inputstack[0].limitfield - 1; + for k := 1 to l do + print(buffer[k]); + println; + selector := oldsetting + 2 + end; {:788} {793:} + + procedure startinput; + label + 30; {795:} + begin + while (curinput.indexfield > 6) and (curinput.locfield = (-30000)) do + endtokenlist; + if curinput.indexfield > 6 then begin + begin + if interaction = 3 then + ; + printnl(133); + print(621) + end; + begin + helpptr := 3; + helpline[2] := 622; + helpline[1] := 623; + helpline[0] := 624 + end; + error + end; + if curinput.indexfield <= 6 then + scanfilename + else begin + curname := 155; + curext := 155; + curarea := 155 + end {:795}; + if curext = 155 then + curext := 611; + packfilename(curname, curarea, curext); + while true do begin + beginfilereading; + if aopenin(inputfile[curinput.indexfield], 6) then + goto 30; + endfilereading; + promptfilename(607, 611) + end; + 30: + curinput.namefield := amakenamestring(inputfile[curinput.indexfield]); + strref[curname] := 127; + if jobname = 0 then begin + jobname := curname; + openlogfile + end; + if (termoffset + (strstart[curinput.namefield + 1] - strstart[curinput.namefield])) > (maxprintline - 2) then + println + else if (termoffset > 0) or (fileoffset > 0) then + printchar(32); + printchar(40); + print(curinput.namefield); + flush(output); {794:} + begin + if not inputln(inputfile[curinput.indexfield], false) then + ; + firmuptheline; + buffer[curinput.limitfield] := 37; + first := curinput.limitfield + 1; + curinput.locfield := curinput.startfield; + line := 1 + end {:794} + end; {:793} {824:} + + procedure badexp(s: strnumber); + var + saveflag: 0..82; + begin + begin + if interaction = 3 then + ; + printnl(133); + print(s) + end; + print(634); + printcmdmod(curcmd, curmod); + printchar(39); + begin + helpptr := 4; + helpline[3] := 635; + helpline[2] := 636; + helpline[1] := 637; + helpline[0] := 638 + end; + backinput; + cursym := 0; + curcmd := 42; + curmod := 0; + inserror; + saveflag := varflag; + varflag := 0; + getxnext; + varflag := saveflag + end; {:824} {827:} + + procedure stashin(p: halfword); + var + q: halfword; + begin + mem[p].hh.b0 := curtype; + { + 829:} + if curtype = 16 then + mem[p + 1].int := curexp + else begin + if curtype = 19 then begin + q := singledependency(curexp); + if q = depfinal then begin + mem[p].hh.b0 := 16; + mem[p + 1].int := 0; + freenode(q, 2) + end else begin + mem[p].hh.b0 := 17; + newdep(p, q) + end; + recyclevalue(curexp) + end else begin {:829} + mem[p + 1] := mem[curexp + 1]; + mem[mem[p + 1].hh.lh].hh.rh := p + end; + freenode(curexp, 2) + end; + curtype := 1 + end; { stashin } +{:827} + {848:} + + procedure backexpr; + var + p: halfword; + begin + p := stashcurexp; + mem[p].hh.rh := -30000; + begintokenlist(p, 10) + end; {:848} {849:} + + procedure badsubscript; + begin + disperr(-30000, 650); + begin + helpptr := 3; + helpline[2] := 651; + helpline[1] := 652; + helpline[0] := 653 + end; + flusherror(0) + end; {:849} {851:} + + procedure obliterated(q: halfword); + begin + begin + if interaction = 3 then + ; + printnl(133); + print(654) + end; + showtokenlist(q, -30000, 1000, 0); + print(655); + begin + helpptr := 5; + helpline[4] := 656; + helpline[3] := 657; + helpline[2] := 658; + helpline[1] := 659; + helpline[0] := 660 + end + end; {:851} {863:} + + procedure binarymac(p, c, n: halfword); + var + q, r: halfword; + begin + q := getavail; + r := getavail; + mem[q].hh.rh := r; + mem[q].hh.lh := p; + mem[r].hh.lh := stashcurexp; + macrocall(c, q, n) + end; {:863} {865:} + + procedure materializepen; + label + 50; + var + aminusb, aplusb, majoraxis, minoraxis: scaled; + theta: angle; + p: halfword; + q: halfword; + begin + q := curexp; + if mem[q].hh.b0 = 0 then begin + begin + if interaction = 3 then + ; + printnl(133); + print(670) + end; + begin + helpptr := 2; + helpline[1] := 671; + helpline[0] := 442 + end; + putgeterror; + curexp := -29997; + goto 50 + end else if mem[q].hh.b0 = 4 then begin {866:} + tx := mem[q + 1].int; + ty := mem[q + 2].int; + txx := mem[q + 3].int - tx; + tyx := mem[q + 4].int - ty; + txy := mem[q + 5].int - tx; + tyy := mem[q + 6].int - ty; + aminusb := pythadd(txx - tyy, tyx + txy); + aplusb := pythadd(txx + tyy, tyx - txy); + majoraxis := (aminusb + aplusb) div 2; + minoraxis := abs(aplusb - aminusb) div 2; + if majoraxis = minoraxis then + theta := 0 + else + theta := (narg(txx - tyy, tyx + txy) + narg(txx + tyy, tyx - txy)) div 2; + freenode(q, 7); + q := makeellipse(majoraxis, minoraxis, theta); + if (tx <> 0) or (ty <> 0) then begin {867:} + p := q; + repeat + mem[p + 1].int := mem[p + 1].int + tx; + mem[p + 2].int := mem[p + 2].int + ty; + p := mem[p].hh.rh + until p = q + end {:867} + end {:866}; + curexp := makepen(q); + 50: + tossknotlist(q); + curtype := 6 + end; {:865} +{871:} + {872:} + + procedure knownpair; + var + p: halfword; + begin + if curtype <> 14 then begin + disperr(-30000, 673); + begin + helpptr := 5; + helpline[4] := 674; + helpline[3] := 675; + helpline[2] := 676; + helpline[1] := 677; + helpline[0] := 678 + end; + putgetflusherror(0); + curx := 0; + cury := 0 + end else begin + p := mem[curexp + 1].int; {873:} + if mem[p].hh.b0 = 16 then + curx := mem[p + 1].int + else begin + disperr(p, 679); + begin + helpptr := 5; + helpline[4] := 680; + helpline[3] := 675; + helpline[2] := 676; + helpline[1] := 677; + helpline[0] := 678 + end; + putgeterror; + recyclevalue(p); + curx := 0 + end; + if mem[p + 2].hh.b0 = 16 then + cury := mem[p + 3].int + else begin + disperr(p + 2, 681); + begin + helpptr := 5; + helpline[4] := 682; + helpline[3] := 675; + helpline[2] := 676; + helpline[1] := 677; + helpline[0] := 678 + end; + putgeterror; + recyclevalue(p + 2); + cury := 0 + end {:873}; + flushcurexp(0) + end + end; {:872} + + function newknot: halfword; + var + q: halfword; + begin + q := getnode(7); + mem[q].hh.b0 := 0; + mem[q].hh.b1 := 0; + mem[q].hh.rh := q; + knownpair; + mem[q + 1].int := curx; + mem[q + 2].int := cury; + newknot := q + end; {:871} {875:} + + function scandirection: smallnumber; + var + t: 2..4; + x: scaled; + begin + getxnext; + if curcmd = 60 then begin {876:} + getxnext; + scanexpression; + if (curtype <> 16) or (curexp < 0) then begin + disperr(-30000, 685); + begin + helpptr := 1; + helpline[0] := 686 + end; + putgetflusherror(65536) + end; + t := 3 + end else begin {:876} {877:} + scanexpression; + if curtype > 14 then begin {878:} + if curtype <> 16 then begin + disperr(-30000, 679); + begin + helpptr := 5; + helpline[4] := 680; + helpline[3] := 675; + helpline[2] := 676; + helpline[1] := 677; + helpline[0] := 678 + end; + putgetflusherror(0) + end; + x := curexp; + if curcmd <> 79 then begin + missingerr(44); + begin + helpptr := 2; + helpline[1] := 687; + helpline[0] := 688 + end; + backerror + end; + getxnext; + scanexpression; + if curtype <> 16 then begin + disperr(-30000, 681); + begin + helpptr := 5; + helpline[4] := 682; + helpline[3] := 675; + helpline[2] := 676; + helpline[1] := 677; + helpline[0] := 678 + end; + putgetflusherror(0) + end; + cury := curexp; + curx := x + end else {:878} + knownpair; + if (curx = 0) and (cury = 0) then + t := 4 + else begin + t := 2; + curexp := narg(curx, cury) + end + end {:877}; + if curcmd <> 65 then begin + missingerr(125); + begin + helpptr := 3; + helpline[2] := 683; + helpline[1] := 684; + helpline[0] := 563 + end; + backerror + end; + getxnext; + scandirection := t + end; {:875} {895:} + + procedure donullary(c: quarterword); + var + k: integer; + begin + begin + if aritherror then + cleararith + end; + if internal[7] > 131072 then + showcmdmod(33, c); + case c of + 30, 31: + begin + curtype := 2; + curexp := c + end; + 32: + begin + curtype := 11; + curexp := getnode(6); + initedges(curexp) + end; + 33: + begin + curtype := 6; + curexp := -29997 + end; + 37: + begin + curtype := 16; + curexp := normrand + end; + 36: + begin {896:} + curtype := 8; + curexp := getnode(7); + mem[curexp].hh.b0 := 4; + mem[curexp].hh.b1 := 4; + mem[curexp].hh.rh := curexp; + mem[curexp + 1].int := 0; + mem[curexp + 2].int := 0; + mem[curexp + 3].int := 65536; + mem[curexp + 4].int := 0; + mem[curexp + 5].int := 0; + mem[curexp + 6].int := 65536 + end; {:896} + 34: + begin + if jobname = 0 then + openlogfile; + curtype := 4; + curexp := jobname + end; + 35: + begin {897:} + if interaction <= 1 then + fatalerror(699); + beginfilereading; + curinput.namefield := 1; + begin + print(155); + terminput + end; + begin + if ((poolptr + last) - curinput.startfield) > maxpoolptr then begin + if ((poolptr + last) - curinput.startfield) > poolsize then + overflow(129, poolsize - initpoolptr); + maxpoolptr := (poolptr + last) - curinput.startfield + end + end; + for k := curinput.startfield to last - 1 do begin + strpool[poolptr] := buffer[k]; + poolptr := poolptr + 1 + end; + endfilereading; + curtype := 4; + curexp := makestring + end + end {:897}; + begin + if aritherror then + cleararith + end + end; {:895} {898:} +{899:} + + function nicepair(p: integer; t: quarterword): boolean; + label + 10; + begin + if t = 14 then begin + p := mem[p + 1].int; + if mem[p].hh.b0 = 16 then + if mem[p + 2].hh.b0 = 16 then begin + nicepair := true; + goto 10 + end + end; + nicepair := false; + 10: + + end; {:899} {900:} + + procedure printknownorunknownt(t: smallnumber; v: integer); + begin + printchar(40); + if t < 17 then + if t <> 14 then + printtype(t) + else if nicepair(v, 14) then + print(207) + else + print(700) + else + print(701); + printchar(41) + end; {:900} {901:} + + procedure badunary(c: quarterword); + begin + disperr(-30000, 702); + printop(c); + printknownorunknownt(curtype, curexp); + begin + helpptr := 3; + helpline[2] := 703; + helpline[1] := 704; + helpline[0] := 705 + end; + putgeterror + end; {:901} {904:} + + procedure negatedeplist(p: halfword); + label + 10; + begin + while true do begin + mem[p + 1].int := -mem[p + 1].int; + if mem[p].hh.lh = (-30000) then + goto 10; + p := mem[p].hh.rh + end; + 10: + + end; {:904} +{908:} + + procedure pairtopath; + begin + curexp := newknot; + curtype := 9 + end; {:908} +{910:} + + procedure takepart(c: quarterword); + var + p: halfword; + begin + p := mem[curexp + 1].int; + mem[-29982].int := p; + mem[-29983].hh.b0 := curtype; + mem[p].hh.rh := -29983; + freenode(curexp, 2); + makeexpcopy(p + (2 * (c - 53))); + recyclevalue(-29983) + end; {:910} {913:} + + procedure strtonum(c: quarterword); + var + n: integer; + m: ASCIIcode; + k: poolpointer; + b: 8..16; + badchar: boolean; + begin + if c = 49 then + if (strstart[curexp + 1] - strstart[curexp]) = 0 then + n := -1 + else + n := strpool[strstart[curexp]] + else begin + if c = 47 then + b := 8 + else + b := 16; + n := 0; + badchar := false; + for k := strstart[curexp] to strstart[curexp + 1] - 1 do begin + m := strpool[k]; + if (m >= 48) and (m <= 57) then + m := m - 48 + else if (m >= 65) and (m <= 70) then + m := m - 55 + else if (m >= 97) and (m <= 102) then + m := m - 87 + else begin + badchar := true; + m := 0 + end; + if m >= b then begin + badchar := true; + m := 0 + end; + if n < (32768 div b) then + n := (n * b) + m + else + n := 32767 + end; {914:} + if badchar then begin + disperr(-30000, 707); + if c = 47 then begin + helpptr := 1; + helpline[0] := 708 + end else begin + helpptr := 1; + helpline[0] := 709 + end; + putgeterror + end; + if n > 4095 then begin + begin + if interaction = 3 then + ; + printnl(133); + print(710) + end; + printint(n); + printchar(41); + begin + helpptr := 1; + helpline[0] := 711 + end; + putgeterror + end {:914} + end; + flushcurexp(n * 65536) + end; { strtonum } +{:913} + {916:} + + function pathlength: scaled; + var + n: scaled; + p: halfword; + begin + p := curexp; + if mem[p].hh.b0 = 0 then + n := -65536 + else + n := 0; + repeat + p := mem[p].hh.rh; + n := n + 65536 + until p = curexp; + pathlength := n + end; { pathlength } +{:916} + {919:} + + procedure testknown(c: quarterword); + label + 30; + var + b: 30..31; + p, q: halfword; + begin + b := 31; + if curtype in + [1, 2, 4, 6, 8, 9, 11, 16, + 13, 14] then + case curtype of + 1, 2, 4, 6, 8, 9, 11, + 16: + b := 30; + 13, 14: + begin + p := mem[curexp + 1].int; + q := p + bignodesize[curtype]; + repeat + q := q - 2; + if mem[q].hh.b0 <> 16 then + goto 30 + until q = p; + b := 30; + 30: + + end + end + else + ; + if c = 39 then + flushcurexp(b) + else + flushcurexp(61 - b); + curtype := 2 + end; {:919} + + procedure dounary(c: quarterword); + var + p, q: halfword; + x: integer; + begin + begin + if aritherror then + cleararith + end; + if internal[7] > 131072 then begin {902:} + begindiagnostic; + printnl(123); + printop(c); + printchar(40); + printexp(-30000, 0); + print(706); + enddiagnostic(false) + end {:902}; + case c of + 69: + if curtype < 14 then + if curtype <> 11 then + badunary(69); + 70: {903:} + if curtype in + [14, 19, 17, 18, 16, 11] then + case curtype of + 14, 19: + begin + q := curexp; + makeexpcopy(q); + if curtype = 17 then + negatedeplist(mem[curexp + 1].hh.rh) + else if curtype = 14 then begin + p := mem[curexp + 1].int; + if mem[p].hh.b0 = 16 then + mem[p + 1].int := -mem[p + 1].int + else + negatedeplist(mem[p + 1].hh.rh); + if mem[p + 2].hh.b0 = 16 then + mem[p + 3].int := -mem[p + 3].int + else + negatedeplist(mem[p + 3].hh.rh) + end; + recyclevalue(q); + freenode(q, 2) + end; + 17, 18: + negatedeplist(mem[curexp + 1].hh.rh); + 16: + curexp := -curexp; + 11: + negateedges(curexp) + end + else + badunary(70) {:903}; {905:} + 41: + if curtype <> 2 then + badunary(41) + else + curexp := 61 - curexp; {:905} {906:} + 59, 60, 61, 62, 63, 64, 65, + 38, 66: + if curtype <> 16 then + badunary(c) + else + case c of + 59: + curexp := squarert(curexp); + 60: + curexp := mexp(curexp); + 61: + curexp := mlog(curexp); + 62, 63: + begin + nsincos((curexp mod 23592960) * 16); + if c = 62 then + curexp := roundfraction(nsin) + else + curexp := roundfraction(ncos) + end; + 64: + curexp := floorscaled(curexp); + 65: + curexp := unifrand(curexp); + 38: + begin + if odd(roundunscaled(curexp)) then + curexp := 30 + else + curexp := 31; + curtype := 2 + end; + 66: + begin {1181:} + curexp := roundunscaled(curexp) mod 256; + if curexp < 0 then + curexp := curexp + 256; + if charexists[curexp] then + curexp := 30 + else + curexp := 31; + curtype := 2 + end + end {:1181}; {:906} {907:} + 67: + if nicepair(curexp, curtype) then begin + p := mem[curexp + 1].int; + x := narg(mem[p + 1].int, mem[p + 3].int); + if x >= 0 then + flushcurexp((x + 8) div 16) + else + flushcurexp(-(((-x) + 8) div 16)) + end else + badunary(67); {:907} {909:} + 53, 54: + if (curtype <= 14) and (curtype >= 13) then + takepart(c) + else + badunary(c); + 55, 56, 57, 58: + if curtype = 13 then + takepart(c) + else + badunary(c); {:909} {912:} + 50: + if curtype <> 16 then + badunary(50) + else begin + curexp := roundunscaled(curexp) mod 128; + curtype := 4; + if curexp < 0 then + curexp := curexp + 128; + if (strstart[curexp + 1] - strstart[curexp]) <> 1 then begin + begin + if (poolptr + 1) > maxpoolptr then begin + if (poolptr + 1) > poolsize then + overflow(129, poolsize - initpoolptr); + maxpoolptr := poolptr + 1 + end + end; + begin + strpool[poolptr] := curexp; + poolptr := poolptr + 1 + end; + curexp := makestring + end + end; + 42: + if curtype <> 16 then + badunary(42) + else begin + oldsetting := selector; + selector := 5; + printscaled(curexp); + curexp := makestring; + selector := oldsetting; + curtype := 4 + end; + 47, 48, 49: + if curtype <> 4 then + badunary(c) + else + strtonum(c); +{:912} + {915:} + 51: + if curtype = 4 then + flushcurexp((strstart[curexp + 1] - strstart[curexp]) * 65536) + else if curtype = 9 then + flushcurexp(pathlength) + else if curtype = 16 then + curexp := abs(curexp) + else if nicepair(curexp, curtype) then + flushcurexp(pythadd(mem[mem[curexp + 1].int + 1].int, mem[mem[curexp + 1].int + 3].int)) + else + badunary(c); {:915} {917:} + 52: + if curtype = 14 then + flushcurexp(0) + else if curtype <> 9 then + badunary(52) + else if mem[curexp].hh.b0 = 0 then + flushcurexp(0) + else begin + curpen := -29997; + curpathtype := 1; + curexp := makespec(curexp, -1879080960, 0); + flushcurexp(turningnumber * 65536) + end; {:917} {918:} + 2: + begin + if (curtype >= 2) and (curtype <= 3) then + flushcurexp(30) + else + flushcurexp(31); + curtype := 2 + end; + 4: + begin + if (curtype >= 4) and (curtype <= 5) then + flushcurexp(30) + else + flushcurexp(31); + curtype := 2 + end; + 6: + begin + if (curtype >= 6) and (curtype <= 8) then + flushcurexp(30) + else + flushcurexp(31); + curtype := 2 + end; + 9: + begin + if (curtype >= 9) and (curtype <= 10) then + flushcurexp(30) + else + flushcurexp(31); + curtype := 2 + end; + 11: + begin + if (curtype >= 11) and (curtype <= 12) then + flushcurexp(30) + else + flushcurexp(31); + curtype := 2 + end; + 13, 14: + begin + if curtype = c then + flushcurexp(30) + else + flushcurexp(31); + curtype := 2 + end; + 15: + begin + if (curtype >= 16) and (curtype <= 19) then + flushcurexp(30) + else + flushcurexp(31); + curtype := 2 + end; + 39, 40: + testknown(c); {:918} {920:} + 68: + begin + if curtype <> 9 then + flushcurexp(31) + else if mem[curexp].hh.b0 <> 0 then + flushcurexp(30) + else + flushcurexp(31); + curtype := 2 + end; {:920} {921:} + 45: + begin + if curtype = 14 then + pairtopath; + if curtype = 9 then + curtype := 8 + else + badunary(45) + end; + 44: + begin + if curtype = 8 then + materializepen; + if curtype <> 6 then + badunary(44) + else begin + flushcurexp(makepath(curexp)); + curtype := 9 + end + end; + 46: + if curtype <> 11 then + badunary(46) + else + flushcurexp(totalweight(curexp)); + 43: + if curtype = 9 then begin + p := htapypoc(curexp); + if mem[p].hh.b1 = 0 then + p := mem[p].hh.rh; + tossknotlist(curexp); + curexp := p + end else if curtype = 14 then + pairtopath + else + badunary(43) + end {:921}; + begin + if aritherror then + cleararith + end + end; {:898} {922:} {923:} + + procedure badbinary(p: halfword; c: quarterword); + begin + disperr(p, 155); + disperr(-30000, 702); + if c >= 94 then + printop(c); + printknownorunknownt(mem[p].hh.b0, p); + if c >= 94 then + print(347) + else + printop(c); + printknownorunknownt(curtype, curexp); + begin + helpptr := 3; + helpline[2] := 703; + helpline[1] := 712; + helpline[0] := 713 + end; + putgeterror + end; {:923} {928:} + + function tarnished(p: halfword): halfword; + label + 10; + var + q: halfword; + r: halfword; + begin + q := mem[p + 1].int; + r := q + bignodesize[mem[p].hh.b0]; + repeat + r := r - 2; + if mem[r].hh.b0 = 19 then begin + tarnished := -29999; + goto 10 + end + until r = q; + tarnished := -30000; + 10: + + end; {:928} {930:} {935:} + + procedure depfinish(v, q: halfword; t: smallnumber); + var + p: halfword; + vv: scaled; + begin + if q = (-30000) then + p := curexp + else + p := q; + mem[p + 1].hh.rh := v; + mem[p].hh.b0 := t; + if mem[v].hh.lh = (-30000) then begin + vv := mem[v + 1].int; + if q = (-30000) then + flushcurexp(vv) + else begin + recyclevalue(p); + mem[q].hh.b0 := 16; + mem[q + 1].int := vv + end + end else if q = (-30000) then + curtype := t; + if fixneeded then + fixdependencies + end; {:935} + + procedure addorsubtract(p, q: halfword; c: quarterword); + label + 30, 10; + var + s, t: smallnumber; + r: halfword; + v: integer; + begin + if q = (-30000) then begin + t := curtype; + if t < 17 then + v := curexp + else + v := mem[curexp + 1].hh.rh + end else begin + t := mem[q].hh.b0; + if t < 17 then + v := mem[q + 1].int + else + v := mem[q + 1].hh.rh + end; + if t = 16 then begin + if c = 70 then + v := -v; + if mem[p].hh.b0 = 16 then begin + v := slowadd(mem[p + 1].int, v); + if q = (-30000) then + curexp := v + else + mem[q + 1].int := v; + goto 10 + end; {931:} + r := mem[p + 1].hh.rh; + while mem[r].hh.lh <> (-30000) do + r := mem[r].hh.rh; + mem[r + 1].int := slowadd(mem[r + 1].int, v); + if q = (-30000) then begin + q := getnode(2); + curexp := q; + curtype := mem[p].hh.b0; + mem[q].hh.b1 := 11 + end; + mem[q + 1].hh.rh := mem[p + 1].hh.rh; + mem[q].hh.b0 := mem[p].hh.b0; + mem[q + 1].hh.lh := mem[p + 1].hh.lh; + mem[mem[p + 1].hh.lh].hh.rh := q; + mem[p].hh.b0 := 16 + end else begin {:931} + if c = 70 then + negatedeplist(v); {932:} + if mem[p].hh.b0 = 16 then begin {933:} + while mem[v].hh.lh <> (-30000) do + v := mem[v].hh.rh; + mem[v + 1].int := slowadd(mem[p + 1].int, mem[v + 1].int) + end else begin {:933} + s := mem[p].hh.b0; + r := mem[p + 1].hh.rh; + if t = 17 then begin + if s = 17 then + if (maxcoef(r) + maxcoef(v)) < 626349397 then begin + v := pplusq(v, r, 17); + goto 30 + end; + t := 18; + v := poverv(v, 65536, 17, 18) + end; + if s = 18 then + v := pplusq(v, r, 18) + else + v := pplusfq(v, 65536, r, 18, 17); + 30: {934:} + if q <> (-30000) then + depfinish(v, q, t) + else begin + curtype := t; + depfinish(v, -30000, t) + end {:934} + end {:932} + end; + 10: + + end; {:930} {943:} + + procedure depmult(p: halfword; v: integer; visscaled: boolean); + label + 10; + var + q: halfword; + s, t: smallnumber; + begin + if p = (-30000) then + q := curexp + else if mem[p].hh.b0 <> 16 then + q := p + else begin + if visscaled then + mem[p + 1].int := takescaled(mem[p + 1].int, v) + else + mem[p + 1].int := takefraction(mem[p + 1].int, v); + goto 10 + end; + t := mem[q].hh.b0; + q := mem[q + 1].hh.rh; + s := t; + if t = 17 then + if visscaled then + if abvscd(maxcoef(q), abs(v), 626349396, 65536) >= 0 then + t := 18; + q := ptimesv(q, v, s, t, visscaled); + depfinish(q, p, t); + 10: + + end; {:943} {946:} + + procedure hardtimes(p: halfword); + var + q: halfword; + r: halfword; + u, v: scaled; + begin + if mem[p].hh.b0 = 14 then begin + q := stashcurexp; + unstashcurexp(p); + p := q + end; + r := mem[curexp + 1].int; + u := mem[r + 1].int; + v := mem[r + 3].int; {947:} + mem[r + 2].hh.b0 := mem[p].hh.b0; + newdep(r + 2, copydeplist(mem[p + 1].hh.rh)); + mem[r].hh.b0 := mem[p].hh.b0; + mem[r + 1] := mem[p + 1]; + mem[mem[p + 1].hh.lh].hh.rh := r; + freenode(p, 2) {:947}; + depmult(r, u, true); + depmult(r + 2, v, true) + end; {:946} {949:} + + procedure depdiv(p: halfword; v: scaled); + label + 10; + var + q: halfword; + s, t: smallnumber; + begin + if p = (-30000) then + q := curexp + else if mem[p].hh.b0 <> 16 then + q := p + else begin + mem[p + 1].int := makescaled(mem[p + 1].int, v); + goto 10 + end; + t := mem[q].hh.b0; + q := mem[q + 1].hh.rh; + s := t; + if t = 17 then + if abvscd(maxcoef(q), 65536, 626349396, abs(v)) >= 0 then + t := 18; + q := poverv(q, v, s, t); + depfinish(q, p, t); + 10: + + end; {:949} {953:} + + procedure setuptrans(c: quarterword); + label + 30, 10; + var + p, q, r: halfword; + begin + if (c <> 88) or (curtype <> 13) then begin {955:} + p := stashcurexp; + curexp := idtransform; + curtype := 13; + q := mem[curexp + 1].int; + case c of {957:} + 84: + if mem[p].hh.b0 = 16 then begin {958:} + nsincos((mem[p + 1].int mod 23592960) * 16); + mem[q + 5].int := roundfraction(ncos); + mem[q + 9].int := roundfraction(nsin); + mem[q + 7].int := -mem[q + 9].int; + mem[q + 11].int := mem[q + 5].int; + goto 30 + end {:958}; + 85: + if mem[p].hh.b0 > 14 then begin + install(q + 6, p); + goto 30 + end; + 86: + if mem[p].hh.b0 > 14 then begin + install(q + 4, p); + install(q + 10, p); + goto 30 + end; + 87: + if mem[p].hh.b0 = 14 then begin + r := mem[p + 1].int; + install(q, r); + install(q + 2, r + 2); + goto 30 + end; + 89: + if mem[p].hh.b0 > 14 then begin + install(q + 4, p); + goto 30 + end; + 90: + if mem[p].hh.b0 > 14 then begin + install(q + 10, p); + goto 30 + end; + 91: + if mem[p].hh.b0 = 14 then begin {959:} + r := mem[p + 1].int; + install(q + 4, r); + install(q + 10, r); + install(q + 8, r + 2); + if mem[r + 2].hh.b0 = 16 then + mem[r + 3].int := -mem[r + 3].int + else + negatedeplist(mem[r + 3].hh.rh); + install(q + 6, r + 2); + goto 30 + end {:959}; + 88: + + end {:957}; + disperr(p, 722); + begin + helpptr := 3; + helpline[2] := 723; + helpline[1] := 724; + helpline[0] := 405 + end; + putgeterror; + 30: + recyclevalue(p); + freenode(p, 2) + end {:955}; {956:} + q := mem[curexp + 1].int; + r := q + 12; + repeat + r := r - 2; + if mem[r].hh.b0 <> 16 then + goto 10 + until r = q; + txx := mem[q + 5].int; + txy := mem[q + 7].int; + tyx := mem[q + 9].int; + tyy := mem[q + 11].int; + tx := mem[q + 1].int; + ty := mem[q + 3].int; + flushcurexp(0) {:956}; + 10: + + end; {:953} {960:} + + procedure setupknowntrans(c: quarterword); + begin + setuptrans(c); + if curtype <> 16 then begin + disperr(-30000, 725); + begin + helpptr := 3; + helpline[2] := 726; + helpline[1] := 727; + helpline[0] := 405 + end; + putgetflusherror(0); + txx := 65536; + txy := 0; + tyx := 0; + tyy := 65536; + tx := 0; + ty := 0 + end + end; {:960} {961:} + + procedure trans(p, q: halfword); + var + v: scaled; + begin + v := (takescaled(mem[p].int, txx) + takescaled(mem[q].int, txy)) + tx; + mem[q].int := (takescaled(mem[p].int, tyx) + takescaled(mem[q].int, tyy)) + ty; + mem[p].int := v + end; {:961} {962:} + + procedure pathtrans(p: halfword; c: quarterword); + label + 10; + var + q: halfword; + begin + setupknowntrans(c); + unstashcurexp(p); + if curtype = 6 then begin + if mem[curexp + 9].int = 0 then + if tx = 0 then + if ty = 0 then + goto 10; + flushcurexp(makepath(curexp)); + curtype := 8 + end; + q := curexp; + repeat + if mem[q].hh.b0 <> 0 then + trans(q + 3, q + 4); + trans(q + 1, q + 2); + if mem[q].hh.b1 <> 0 then + trans(q + 5, q + 6); + q := mem[q].hh.rh + until q = curexp; + 10: + + end; {:962} {963:} + + procedure edgestrans(p: halfword; c: quarterword); + label + 10; + begin + setupknowntrans(c); + unstashcurexp(p); + curedges := curexp; + if mem[curedges].hh.rh = curedges then + goto 10; + if txx = 0 then + if tyy = 0 then + if (txy mod 65536) = 0 then + if (tyx mod 65536) = 0 then begin + xyswapedges; + txx := txy; + tyy := tyx; + txy := 0; + tyx := 0; + if mem[curedges].hh.rh = curedges then + goto 10 + end; + if txy = 0 then + if tyx = 0 then + if (txy mod 65536) = 0 then + if (tyy mod 65536) = 0 then begin {964:} + if (txx = 0) or (tyy = 0) then begin + tossedges(curedges); + curexp := getnode(6); + initedges(curexp) + end else begin + if txx < 0 then begin + xreflectedges; + txx := -txx + end; + if tyy < 0 then begin + yreflectedges; + tyy := -tyy + end; + if txx <> 65536 then + xscaleedges(txx div 65536); + if tyy <> 65536 then + yscaleedges(tyy div 65536); {965:} + tx := roundunscaled(tx); + ty := roundunscaled(ty); + if ((((((mem[curedges + 2].hh.lh + tx) <= 0) or ((mem[curedges + 2].hh.rh + tx) >= 8192)) or ((mem[curedges + 1].hh.lh + ty) <= 0)) or ((mem[curedges + 1].hh.rh + ty) >= 8191)) or (abs(tx) >= 4096)) or (abs(ty) >= 4096) then begin + begin + if interaction = 3 then + ; + printnl(133); + print(731) + end; + begin + helpptr := 3; + helpline[2] := 732; + helpline[1] := 404; + helpline[0] := 405 + end; + putgeterror + end else begin + if tx <> 0 then begin + if not (abs((mem[curedges + 3].hh.lh - tx) - 4096) < 4096) then + fixoffset; + mem[curedges + 2].hh.lh := mem[curedges + 2].hh.lh + tx; + mem[curedges + 2].hh.rh := mem[curedges + 2].hh.rh + tx; + mem[curedges + 3].hh.lh := mem[curedges + 3].hh.lh - tx; + mem[curedges + 4].int := 0 + end; + if ty <> 0 then begin + mem[curedges + 1].hh.lh := mem[curedges + 1].hh.lh + ty; + mem[curedges + 1].hh.rh := mem[curedges + 1].hh.rh + ty; + mem[curedges + 5].hh.lh := mem[curedges + 5].hh.lh + ty; + mem[curedges + 4].int := 0 + end + end {:965} + end; + goto 10 + end {:964}; + begin + if interaction = 3 then + ; + printnl(133); + print(728) + end; + begin + helpptr := 3; + helpline[2] := 729; + helpline[1] := 730; + helpline[0] := 405 + end; + putgeterror; + 10: + + end; {:963} {966:} +{968:} + + procedure bilin1(p: halfword; t: scaled; q: halfword; u, delta: scaled); + var + r: halfword; + begin + if t <> 65536 then + depmult(p, t, true); + if u <> 0 then + if mem[q].hh.b0 = 16 then + delta := delta + takescaled(mem[q + 1].int, u) + else begin {969:} + if mem[p].hh.b0 <> 18 then begin + if mem[p].hh.b0 = 16 then + newdep(p, constdependency(mem[p + 1].int)) + else + mem[p + 1].hh.rh := ptimesv(mem[p + 1].hh.rh, 65536, 17, 18, true); + mem[p].hh.b0 := 18 + end {:969}; + mem[p + 1].hh.rh := pplusfq(mem[p + 1].hh.rh, u, mem[q + 1].hh.rh, 18, mem[q].hh.b0) + end; + if mem[p].hh.b0 = 16 then + mem[p + 1].int := mem[p + 1].int + delta + else begin + r := mem[p + 1].hh.rh; + while mem[r].hh.lh <> (-30000) do + r := mem[r].hh.rh; + delta := mem[r + 1].int + delta; + if r <> mem[p + 1].hh.rh then + mem[r + 1].int := delta + else begin + recyclevalue(p); + mem[p].hh.b0 := 16; + mem[p + 1].int := delta + end + end; + if fixneeded then + fixdependencies + end; {:968} {971:} + + procedure addmultdep(p: halfword; v: scaled; r: halfword); + begin + if mem[r].hh.b0 = 16 then + mem[depfinal + 1].int := mem[depfinal + 1].int + takescaled(mem[r + 1].int, v) + else begin + mem[p + 1].hh.rh := pplusfq(mem[p + 1].hh.rh, v, mem[r + 1].hh.rh, 18, mem[r].hh.b0); + if fixneeded then + fixdependencies + end + end; {:971} {972:} + + procedure bilin2(p, t: halfword; v: scaled; u, q: halfword); + var + vv: scaled; + begin + vv := mem[p + 1].int; + mem[p].hh.b0 := 18; + newdep(p, constdependency(0)); + if vv <> 0 then + addmultdep(p, vv, t); + if v <> 0 then + addmultdep(p, v, u); + if q <> (-30000) then + addmultdep(p, 65536, q); + if mem[p + 1].hh.rh = depfinal then begin + vv := mem[depfinal + 1].int; + recyclevalue(p); + mem[p].hh.b0 := 16; + mem[p + 1].int := vv + end + end; {:972} {974:} + + procedure bilin3(p: halfword; t, v, u, delta: scaled); + begin + if t <> 65536 then + delta := delta + takescaled(mem[p + 1].int, t) + else + delta := delta + mem[p + 1].int; + if u <> 0 then + mem[p + 1].int := delta + takescaled(v, u) + else + mem[p + 1].int := delta + end; {:974} + + procedure bigtrans(p: halfword; c: quarterword); + label + 10; + var + q, r, pp, qq: halfword; + s: smallnumber; + begin + s := bignodesize[mem[p].hh.b0]; + q := mem[p + 1].int; + r := q + s; + repeat + r := r - 2; + if mem[r].hh.b0 <> 16 then begin {967:} + setupknowntrans(c); + makeexpcopy(p); + r := mem[curexp + 1].int; + if curtype = 13 then begin + bilin1(r + 10, tyy, q + 6, tyx, 0); + bilin1(r + 8, tyy, q + 4, tyx, 0); + bilin1(r + 6, txx, q + 10, txy, 0); + bilin1(r + 4, txx, q + 8, txy, 0) + end; + bilin1(r + 2, tyy, q, tyx, ty); + bilin1(r, txx, q + 2, txy, tx); + goto 10 + end {:967} + until r = q; {970:} + setuptrans(c); + if curtype = 16 then begin {973:} + makeexpcopy(p); + r := mem[curexp + 1].int; + if curtype = 13 then begin + bilin3(r + 10, tyy, mem[q + 7].int, tyx, 0); + bilin3(r + 8, tyy, mem[q + 5].int, tyx, 0); + bilin3(r + 6, txx, mem[q + 11].int, txy, 0); + bilin3(r + 4, txx, mem[q + 9].int, txy, 0) + end; + bilin3(r + 2, tyy, mem[q + 1].int, tyx, ty); + bilin3(r, txx, mem[q + 3].int, txy, tx) + end else begin {:973} + pp := stashcurexp; + qq := mem[pp + 1].int; + makeexpcopy(p); + r := mem[curexp + 1].int; + if curtype = 13 then begin + bilin2(r + 10, qq + 10, mem[q + 7].int, qq + 8, -30000); + bilin2(r + 8, qq + 10, mem[q + 5].int, qq + 8, -30000); + bilin2(r + 6, qq + 4, mem[q + 11].int, qq + 6, -30000); + bilin2(r + 4, qq + 4, mem[q + 9].int, qq + 6, -30000) + end; + bilin2(r + 2, qq + 10, mem[q + 1].int, qq + 8, qq + 2); + bilin2(r, qq + 4, mem[q + 3].int, qq + 6, qq); + recyclevalue(pp); + freenode(pp, 2) + end; +{:970} + 10: + + end; {:966} {976:} + + procedure cat(p: halfword); + var + a, b: strnumber; + k: poolpointer; + begin + a := mem[p + 1].int; + b := curexp; + begin + if ((poolptr + (strstart[a + 1] - strstart[a])) + (strstart[b + 1] - strstart[b])) > maxpoolptr then begin + if ((poolptr + (strstart[a + 1] - strstart[a])) + (strstart[b + 1] - strstart[b])) > poolsize then + overflow(129, poolsize - initpoolptr); + maxpoolptr := (poolptr + (strstart[a + 1] - strstart[a])) + (strstart[b + 1] - strstart[b]) + end + end; + for k := strstart[a] to strstart[a + 1] - 1 do begin + strpool[poolptr] := strpool[k]; + poolptr := poolptr + 1 + end; + for k := strstart[b] to strstart[b + 1] - 1 do begin + strpool[poolptr] := strpool[k]; + poolptr := poolptr + 1 + end; + curexp := makestring; + begin + if strref[b] < 127 then + if strref[b] > 1 then + strref[b] := strref[b] - 1 + else + flushstring(b) + end + end; {:976} {977:} + + procedure chopstring(p: halfword); + var + a, b: integer; + l: integer; + k: integer; + s: strnumber; + reversed: boolean; + begin + a := roundunscaled(mem[p + 1].int); + b := roundunscaled(mem[p + 3].int); + if a <= b then + reversed := false + else begin + reversed := true; + k := a; + a := b; + b := k + end; + s := curexp; + l := strstart[s + 1] - strstart[s]; + if a < 0 then begin + a := 0; + if b < 0 then + b := 0 + end; + if b > l then begin + b := l; + if a > l then + a := l + end; + begin + if ((poolptr + b) - a) > maxpoolptr then begin + if ((poolptr + b) - a) > poolsize then + overflow(129, poolsize - initpoolptr); + maxpoolptr := (poolptr + b) - a + end + end; + if reversed then + for k := (strstart[s] + b) - 1 downto strstart[s] + a do begin + strpool[poolptr] := strpool[k]; + poolptr := poolptr + 1 + end + else + for k := strstart[s] + a to (strstart[s] + b) - 1 do begin + strpool[poolptr] := strpool[k]; + poolptr := poolptr + 1 + end; + curexp := makestring; + begin + if strref[s] < 127 then + if strref[s] > 1 then + strref[s] := strref[s] - 1 + else + flushstring(s) + end + end; {:977} {978:} + + procedure choppath(p: halfword); + var + q: halfword; + pp, qq, rr, ss: halfword; + a, b, k, l: scaled; + reversed: boolean; + begin + l := pathlength; + a := mem[p + 1].int; + b := mem[p + 3].int; + if a <= b then + reversed := false + else begin + reversed := true; + k := a; + a := b; + b := k + end; {979:} + if a < 0 then + if mem[curexp].hh.b0 = 0 then begin + a := 0; + if b < 0 then + b := 0 + end else + repeat + a := a + l; + b := b + l + until a >= 0; + if b > l then + if mem[curexp].hh.b0 = 0 then begin + b := l; + if a > l then + a := l + end else + while a >= l do begin + a := a - l; + b := b - l + end {:979}; + q := curexp; + while a >= 65536 do begin + q := mem[q].hh.rh; + a := a - 65536; + b := b - 65536 + end; + if b = a then begin {981:} + if a > 0 then begin + qq := mem[q].hh.rh; + splitcubic(q, a * 4096, mem[qq + 1].int, mem[qq + 2].int); + q := mem[q].hh.rh + end; + pp := copyknot(q); + qq := pp + end else begin {:981} {980:} + pp := copyknot(q); + qq := pp; + repeat + q := mem[q].hh.rh; + rr := qq; + qq := copyknot(q); + mem[rr].hh.rh := qq; + b := b - 65536 + until b <= 0; + if a > 0 then begin + ss := pp; + pp := mem[pp].hh.rh; + splitcubic(ss, a * 4096, mem[pp + 1].int, mem[pp + 2].int); + pp := mem[ss].hh.rh; + freenode(ss, 7); + if rr = ss then begin + b := makescaled(b, 65536 - a); + rr := pp + end + end; + if b < 0 then begin + splitcubic(rr, (b + 65536) * 4096, mem[qq + 1].int, mem[qq + 2].int); + freenode(qq, 7); + qq := mem[rr].hh.rh + end + end {:980}; + mem[pp].hh.b0 := 0; + mem[qq].hh.b1 := 0; + mem[qq].hh.rh := pp; + tossknotlist(curexp); + if reversed then begin + curexp := mem[htapypoc(pp)].hh.rh; + tossknotlist(pp) + end else + curexp := pp + end; {:978} {982:} + + procedure pairvalue(x, y: scaled); + var + p: halfword; + begin + p := getnode(2); + flushcurexp(p); + curtype := 14; + mem[p].hh.b0 := 14; + mem[p].hh.b1 := 11; + initbignode(p); + p := mem[p + 1].int; + mem[p].hh.b0 := 16; + mem[p + 1].int := x; + mem[p + 2].hh.b0 := 16; + mem[p + 3].int := y + end; { pairvalue } +{:982} + {984:} + + procedure setupoffset(p: halfword); + begin + findoffset(mem[p + 1].int, mem[p + 3].int, curexp); + pairvalue(curx, cury) + end; + + procedure setupdirectiontime(p: halfword); + begin + flushcurexp(finddirectiontime(mem[p + 1].int, mem[p + 3].int, curexp)) + end; {:984} {985:} + + procedure findpoint(v: scaled; c: quarterword); + var + p: halfword; + n: scaled; + vv: scaled; + q: halfword; + begin + vv := v; + p := curexp; + if mem[p].hh.b0 = 0 then + n := -65536 + else + n := 0; + repeat + p := mem[p].hh.rh; + n := n + 65536 + until p = curexp; + if n = 0 then + v := 0 + else if v < 0 then + if mem[p].hh.b0 = 0 then + v := 0 + else + v := (n - 1) - (((-v) - 1) mod n) + else if v > n then + if mem[p].hh.b0 = 0 then + v := n + else + v := v mod n; + p := curexp; + while v >= 65536 do begin + p := mem[p].hh.rh; + v := v - 65536 + end; + if v <> 0 then begin {986:} + q := mem[p].hh.rh; + splitcubic(p, v * 4096, mem[q + 1].int, mem[q + 2].int); + p := mem[p].hh.rh + end {:986}; {987:} + case c of + 97: + pairvalue(mem[p + 1].int, mem[p + 2].int); + 98: + if mem[p].hh.b0 = 0 then + pairvalue(mem[p + 1].int, mem[p + 2].int) + else + pairvalue(mem[p + 3].int, mem[p + 4].int); + 99: + if mem[p].hh.b1 = 0 then + pairvalue(mem[p + 1].int, mem[p + 2].int) + else + pairvalue(mem[p + 5].int, mem[p + 6].int) + end {:987} + end; {:985} + + procedure dobinary(p: halfword; c: quarterword); + label + 30, 31, 10; + var + q, r, rr: halfword; + oldp, oldexp: halfword; + v: integer; + begin + begin + if aritherror then + cleararith + end; + if internal[7] > 131072 then begin {924:} + begindiagnostic; + printnl(714); + printexp(p, 0); + printchar(41); + printop(c); + printchar(40); + printexp(-30000, 0); + print(706); + enddiagnostic(false) + end {:924}; {926:} + if mem[p].hh.b0 in + [13, 14, 19] then + case mem[p].hh.b0 of + 13, 14: + oldp := tarnished(p); + 19: + oldp := -29999 + end + else + oldp := -30000; + if oldp <> (-30000) then begin + q := stashcurexp; + oldp := p; + makeexpcopy(oldp); + p := stashcurexp; + unstashcurexp(q) + end; {:926} +{927:} + if curtype in + [13, 14, 19] then + case curtype of + 13, 14: + oldexp := tarnished(curexp); + 19: + oldexp := -29999 + end + else + oldexp := -30000; + if oldexp <> (-30000) then begin + oldexp := curexp; + makeexpcopy(oldexp) + end {:927}; + case c of + 69, 70: {929:} + if (curtype < 14) or (mem[p].hh.b0 < 14) then + if (curtype = 11) and (mem[p].hh.b0 = 11) then begin + if c = 70 then + negateedges(curexp); + curedges := curexp; + mergeedges(mem[p + 1].int) + end else + badbinary(p, c) + else if curtype = 14 then + if mem[p].hh.b0 <> 14 then + badbinary(p, c) + else begin + q := mem[p + 1].int; + r := mem[curexp + 1].int; + addorsubtract(q, r, c); + addorsubtract(q + 2, r + 2, c) + end + else if mem[p].hh.b0 = 14 then + badbinary(p, c) + else + addorsubtract(p, -30000, c) {:929}; {936:} + 77, 78, 79, 80, 81, 82: + begin + if (curtype > 14) and (mem[p].hh.b0 > 14) then + addorsubtract(p, -30000, 70) + else if curtype <> mem[p].hh.b0 then begin + badbinary(p, c); + goto 30 + end else if curtype = 4 then + flushcurexp(strvsstr(mem[p + 1].int, curexp)) + else if (curtype = 5) or (curtype = 3) then begin {938:} + q := mem[curexp + 1].int; + while (q <> curexp) and (q <> p) do + q := mem[q + 1].int; + if q = p then + flushcurexp(0) + end else if (curtype = 14) or (curtype = 13) then begin {:938} {939:} + q := mem[p + 1].int; + r := mem[curexp + 1].int; + rr := (r + bignodesize[curtype]) - 2; + while true do begin + addorsubtract(q, r, 70); + if mem[r].hh.b0 <> 16 then + goto 31; + if mem[r + 1].int <> 0 then + goto 31; + if r = rr then + goto 31; + q := q + 2; + r := r + 2 + end; + 31: + takepart(53 + ((r - mem[curexp + 1].int) div 2)) + end else if curtype = 2 then {:939} + flushcurexp(curexp - mem[p + 1].int) + else begin + badbinary(p, c); + goto 30 + end; {937:} + if curtype <> 16 then begin + if curtype < 16 then begin + disperr(p, 155); + begin + helpptr := 1; + helpline[0] := 715 + end + end else begin + helpptr := 2; + helpline[1] := 716; + helpline[0] := 717 + end; + disperr(-30000, 718); + putgetflusherror(31) + end else + case c of + 77: + if curexp < 0 then + curexp := 30 + else + curexp := 31; + 78: + if curexp <= 0 then + curexp := 30 + else + curexp := 31; + 79: + if curexp > 0 then + curexp := 30 + else + curexp := 31; + 80: + if curexp >= 0 then + curexp := 30 + else + curexp := 31; + 81: + if curexp = 0 then + curexp := 30 + else + curexp := 31; + 82: + if curexp <> 0 then + curexp := 30 + else + curexp := 31 + end; + curtype := 2 {:937}; + 30: + + end; {:936} {940:} + 76, 75: + if (mem[p].hh.b0 <> 2) or (curtype <> 2) then + badbinary(p, c) + else if mem[p + 1].int = (c - 45) then + curexp := mem[p + 1].int; {:940} {941:} + 71: + if (curtype < 14) or (mem[p].hh.b0 < 14) then + badbinary(p, 71) + else if (curtype = 16) or (mem[p].hh.b0 = 16) then begin {942:} + if mem[p].hh.b0 = 16 then begin + v := mem[p + 1].int; + freenode(p, 2) + end else begin + v := curexp; + unstashcurexp(p) + end; + if curtype = 16 then + curexp := takescaled(curexp, v) + else if curtype = 14 then begin + p := mem[curexp + 1].int; + depmult(p, v, true); + depmult(p + 2, v, true) + end else + depmult(-30000, v, true); + goto 10 + end else if (nicepair(p, mem[p].hh.b0) and (curtype > 14)) or (nicepair(curexp, curtype) and (mem[p].hh.b0 > 14)) then begin {:942} + hardtimes(p); + goto 10 + end else + badbinary(p, 71); {:941} {948:} + 72: + if (curtype <> 16) or (mem[p].hh.b0 < 14) then + badbinary(p, 72) + else begin + v := curexp; + unstashcurexp(p); + if v = 0 then begin {950:} + disperr(-30000, 648); + begin + helpptr := 2; + helpline[1] := 720; + helpline[0] := 721 + end; + putgeterror + end else begin {:950} + if curtype = 16 then + curexp := makescaled(curexp, v) + else if curtype = 14 then begin + p := mem[curexp + 1].int; + depdiv(p, v); + depdiv(p + 2, v) + end else + depdiv(-30000, v) + end; + goto 10 + end; {:948} {951:} + 73, 74: + if (curtype = 16) and (mem[p].hh.b0 = 16) then + if c = 73 then + curexp := pythadd(mem[p + 1].int, curexp) + else + curexp := pythsub(mem[p + 1].int, curexp) + else + badbinary(p, c); {:951} {952:} + 84, 85, 86, 87, 88, 89, 90, + 91: + if ((mem[p].hh.b0 = 9) or (mem[p].hh.b0 = 8)) or (mem[p].hh.b0 = 6) then begin + pathtrans(p, c); + goto 10 + end else if (mem[p].hh.b0 = 14) or (mem[p].hh.b0 = 13) then + bigtrans(p, c) + else if mem[p].hh.b0 = 11 then begin + edgestrans(p, c); + goto 10 + end else + badbinary(p, c); {:952} {975:} + 83: + if (curtype = 4) and (mem[p].hh.b0 = 4) then + cat(p) + else + badbinary(p, 83); + 94: + if nicepair(p, mem[p].hh.b0) and (curtype = 4) then + chopstring(mem[p + 1].int) + else + badbinary(p, 94); + 95: + begin + if curtype = 14 then + pairtopath; + if nicepair(p, mem[p].hh.b0) and (curtype = 9) then + choppath(mem[p + 1].int) + else + badbinary(p, 95) + end; {:975} {983:} + 97, 98, 99: + begin + if curtype = 14 then + pairtopath; + if (curtype = 9) and (mem[p].hh.b0 = 16) then + findpoint(mem[p + 1].int, c) + else + badbinary(p, c) + end; + 100: + begin + if curtype = 8 then + materializepen; + if (curtype = 6) and nicepair(p, mem[p].hh.b0) then + setupoffset(mem[p + 1].int) + else + badbinary(p, 100) + end; + 96: + begin + if curtype = 14 then + pairtopath; + if (curtype = 9) and nicepair(p, mem[p].hh.b0) then + setupdirectiontime(mem[p + 1].int) + else + badbinary(p, 96) + end; {:983} {988:} + 92: + begin + if mem[p].hh.b0 = 14 then begin + q := stashcurexp; + unstashcurexp(p); + pairtopath; + p := stashcurexp; + unstashcurexp(q) + end; + if curtype = 14 then + pairtopath; + if (curtype = 9) and (mem[p].hh.b0 = 9) then begin + pathintersection(mem[p + 1].int, curexp); + pairvalue(curt, curtt) + end else + badbinary(p, 92) + end + end {:988}; + recyclevalue(p); + freenode(p, 2); + 10: + begin + if aritherror then + cleararith + end; {925:} + if oldp <> (-30000) then begin + recyclevalue(oldp); + freenode(oldp, 2) + end; + if oldexp <> (-30000) then begin + recyclevalue(oldexp); + freenode(oldexp, 2) + end {:925} + end; {:922} {944:} + + procedure fracmult(n, d: scaled); + var + p: halfword; + oldexp: halfword; + v: fraction; + begin + if internal[7] > 131072 then begin {945:} + begindiagnostic; + printnl(714); + printscaled(n); + printchar(47); + printscaled(d); + print(719); + printexp(-30000, 0); + print(706); + enddiagnostic(false) + end {:945}; + if curtype in + [13, 14, 19] then + case curtype of + 13, 14: + oldexp := tarnished(curexp); + 19: + oldexp := -29999 + end + else + oldexp := -30000; + if oldexp <> (-30000) then begin + oldexp := curexp; + makeexpcopy(oldexp) + end; + v := makefraction(n, d); + if curtype = 16 then + curexp := takefraction(curexp, v) + else if curtype = 14 then begin + p := mem[curexp + 1].int; + depmult(p, v, false); + depmult(p + 2, v, false) + end else + depmult(-30000, v, false); + if oldexp <> (-30000) then begin + recyclevalue(oldexp); + freenode(oldexp, 2) + end + end; {:944} {989:} {1155:} + + procedure gfswap; + begin + if gflimit = gfbufsize then begin + bwritebuf(gffile, gfbuf, 0, halfbuf - 1); + gflimit := halfbuf; + gfoffset := gfoffset + gfbufsize; + gfptr := 0 + end else begin + bwritebuf(gffile, gfbuf, halfbuf, gfbufsize - 1); + gflimit := gfbufsize + end + end; {:1155} {1157:} + + procedure gffour(x: integer); + begin + if x >= 0 then begin + gfbuf[gfptr] := x div 16777216; + gfptr := gfptr + 1; + if gfptr = gflimit then + gfswap + end else begin + x := x + 1073741824; + x := x + 1073741824; + begin + gfbuf[gfptr] := (x div 16777216) + 128; + gfptr := gfptr + 1; + if gfptr = gflimit then + gfswap + end + end; + x := x mod 16777216; + begin + gfbuf[gfptr] := x div 65536; + gfptr := gfptr + 1; + if gfptr = gflimit then + gfswap + end; + x := x mod 65536; + begin + gfbuf[gfptr] := x div 256; + gfptr := gfptr + 1; + if gfptr = gflimit then + gfswap + end; + begin + gfbuf[gfptr] := x mod 256; + gfptr := gfptr + 1; + if gfptr = gflimit then + gfswap + end + end; {:1157} {1158:} + + procedure gftwo(x: integer); + begin + begin + gfbuf[gfptr] := x div 256; + gfptr := gfptr + 1; + if gfptr = gflimit then + gfswap + end; + begin + gfbuf[gfptr] := x mod 256; + gfptr := gfptr + 1; + if gfptr = gflimit then + gfswap + end + end; + + procedure gfthree(x: integer); + begin + begin + gfbuf[gfptr] := x div 65536; + gfptr := gfptr + 1; + if gfptr = gflimit then + gfswap + end; + begin + gfbuf[gfptr] := (x mod 65536) div 256; + gfptr := gfptr + 1; + if gfptr = gflimit then + gfswap + end; + begin + gfbuf[gfptr] := x mod 256; + gfptr := gfptr + 1; + if gfptr = gflimit then + gfswap + end + end; {:1158} {1159:} + + procedure gfpaint(d: integer); + begin + if d < 64 then begin + gfbuf[gfptr] := 0 + d; + gfptr := gfptr + 1; + if gfptr = gflimit then + gfswap + end else if d < 256 then begin + begin + gfbuf[gfptr] := 64; + gfptr := gfptr + 1; + if gfptr = gflimit then + gfswap + end; + begin + gfbuf[gfptr] := d; + gfptr := gfptr + 1; + if gfptr = gflimit then + gfswap + end + end else begin + begin + gfbuf[gfptr] := 65; + gfptr := gfptr + 1; + if gfptr = gflimit then + gfswap + end; + gftwo(d) + end + end; {:1159} +{1160:} + + procedure gfstring(s, t: strnumber); + var + k: poolpointer; + l: integer; + begin + if s <> 0 then begin + l := strstart[s + 1] - strstart[s]; + if t <> 0 then + l := l + (strstart[t + 1] - strstart[t]); + if l <= 255 then begin + begin + gfbuf[gfptr] := 239; + gfptr := gfptr + 1; + if gfptr = gflimit then + gfswap + end; + begin + gfbuf[gfptr] := l; + gfptr := gfptr + 1; + if gfptr = gflimit then + gfswap + end + end else begin + begin + gfbuf[gfptr] := 241; + gfptr := gfptr + 1; + if gfptr = gflimit then + gfswap + end; + gfthree(l) + end; + for k := strstart[s] to strstart[s + 1] - 1 do begin + gfbuf[gfptr] := strpool[k]; + gfptr := gfptr + 1; + if gfptr = gflimit then + gfswap + end + end; + if t <> 0 then + for k := strstart[t] to strstart[t + 1] - 1 do begin + gfbuf[gfptr] := strpool[k]; + gfptr := gfptr + 1; + if gfptr = gflimit then + gfswap + end + end; {:1160} +{1161:} + + procedure gfboc(minm, maxm, minn, maxn: integer); + label + 10; + begin + if minm < gfminm then + gfminm := minm; + if maxn > gfmaxn then + gfmaxn := maxn; + if bocp = (-1) then + if bocc >= 0 then + if bocc < 256 then + if (maxm - minm) >= 0 then + if (maxm - minm) < 256 then + if maxm >= 0 then + if maxm < 256 then + if (maxn - minn) >= 0 then + if (maxn - minn) < 256 then + if maxn >= 0 then + if maxn < 256 then begin + begin + gfbuf[gfptr] := 68; + gfptr := gfptr + 1; + if gfptr = gflimit then + gfswap + end; + begin + gfbuf[gfptr] := bocc; + gfptr := gfptr + 1; + if gfptr = gflimit then + gfswap + end; + begin + gfbuf[gfptr] := maxm - minm; + gfptr := gfptr + 1; + if gfptr = gflimit then + gfswap + end; + begin + gfbuf[gfptr] := maxm; + gfptr := gfptr + 1; + if gfptr = gflimit then + gfswap + end; + begin + gfbuf[gfptr] := maxn - minn; + gfptr := gfptr + 1; + if gfptr = gflimit then + gfswap + end; + begin + gfbuf[gfptr] := maxn; + gfptr := gfptr + 1; + if gfptr = gflimit then + gfswap + end; + goto 10 + end; + begin + gfbuf[gfptr] := 67; + gfptr := gfptr + 1; + if gfptr = gflimit then + gfswap + end; + gffour(bocc); + gffour(bocp); + gffour(minm); + gffour(maxm); + gffour(minn); + gffour(maxn); + 10: + + end; {:1161} {1163:} + + procedure initgf; + var + k: eightbits; + t: integer; + begin + gfminm := 4096; + gfmaxm := -4096; + gfminn := 4096; + gfmaxn := -4096; + for k := 0 to 255 do + charptr[k] := -1; {1164:} + if internal[27] <= 0 then + gfext := 908 + else begin + oldsetting := selector; + selector := 5; + printchar(46); + printint(makescaled(internal[27], 59429463)); + print(909); + gfext := makestring; + selector := oldsetting + end {:1164}; + begin + if jobname = 0 then + openlogfile; + packjobname(gfext); + while not bopenout(gffile, nameoffile) do + promptfilename(620, gfext); + outputfilename := bmakenamestring(gffile) + end; + begin + gfbuf[gfptr] := 247; + gfptr := gfptr + 1; + if gfptr = gflimit then + gfswap + end; + begin + gfbuf[gfptr] := 131; + gfptr := gfptr + 1; + if gfptr = gflimit then + gfswap + end; + oldsetting := selector; + selector := 5; + print(907); + printint(roundunscaled(internal[14])); + printchar(46); + printdd(roundunscaled(internal[15])); + printchar(46); + printdd(roundunscaled(internal[16])); + printchar(58); + t := roundunscaled(internal[17]); + printdd(t div 60); + printdd(t mod 60); + selector := oldsetting; + begin + gfbuf[gfptr] := poolptr - strstart[strptr]; + gfptr := gfptr + 1; + if gfptr = gflimit then + gfswap + end; + strstart[strptr + 1] := poolptr; + gfstring(0, strptr); + poolptr := strstart[strptr]; + gfprevptr := gfoffset + gfptr + end; {:1163} {1165:} + + procedure shipout(c: eightbits); + label + 30; + var + f: integer; + prevm, m, mm: integer; + prevn, n: integer; + p, q: halfword; + prevw, w, ww: integer; + d: integer; + delta: integer; + curminm: integer; + xoff, yoff: integer; + begin + if outputfilename = 0 then + initgf; + f := roundunscaled(internal[19]); + xoff := roundunscaled(internal[29]); + yoff := roundunscaled(internal[30]); + if termoffset > (maxprintline - 9) then + println + else if (termoffset > 0) or (fileoffset > 0) then + printchar(32); + printchar(91); + printint(c); + if f <> 0 then begin + printchar(46); + printint(f) + end; + flush(output); + bocc := (256 * f) + c; + bocp := charptr[c]; + charptr[c] := gfprevptr; + if internal[34] > 0 then begin {1166:} + if xoff <> 0 then begin + gfstring(308, 0); + begin + gfbuf[gfptr] := 243; + gfptr := gfptr + 1; + if gfptr = gflimit then + gfswap + end; + gffour(xoff * 65536) + end; + if yoff <> 0 then begin + gfstring(309, 0); + begin + gfbuf[gfptr] := 243; + gfptr := gfptr + 1; + if gfptr = gflimit then + gfswap + end; + gffour(yoff * 65536) + end + end {:1166}; {1167:} + prevn := 4096; + p := mem[curedges].hh.lh; + n := mem[curedges + 1].hh.rh - 4096; + while p <> curedges do begin {1169:} + if mem[p + 1].hh.lh > (-29999) then + sortedges(p); + q := mem[p + 1].hh.rh; + w := 0; + prevm := -268435456; + ww := 0; + prevw := 0; + m := prevm; + repeat + if q = 30000 then + mm := 268435456 + else begin + d := mem[q].hh.lh + 32768; + mm := d div 8; + ww := (ww + (d mod 8)) - 4 + end; + if mm <> m then begin + if prevw <= 0 then begin + if w > 0 then begin {1170:} + if prevm = (-268435456) then begin {1172:} + if prevn = 4096 then begin + gfboc((mem[curedges + 2].hh.lh + xoff) - 4096, (mem[curedges + 2].hh.rh + xoff) - 4096, (mem[curedges + 1].hh.lh + yoff) - 4096, n + yoff); + curminm := (mem[curedges + 2].hh.lh - 4096) + mem[curedges + 3].hh.lh + end else if prevn > (n + 1) then begin {1174:} + delta := (prevn - n) - 1; + if delta < 256 then + if delta = 0 then begin + gfbuf[gfptr] := 70; + gfptr := gfptr + 1; + if gfptr = gflimit then + gfswap + end else begin + begin + gfbuf[gfptr] := 71; + gfptr := gfptr + 1; + if gfptr = gflimit then + gfswap + end; + begin + gfbuf[gfptr] := delta; + gfptr := gfptr + 1; + if gfptr = gflimit then + gfswap + end + end + else begin + begin + gfbuf[gfptr] := 72; + gfptr := gfptr + 1; + if gfptr = gflimit then + gfswap + end; + gftwo(delta) + end + end else begin {:1174} {1173:} + delta := m - curminm; + if delta > 164 then begin + gfbuf[gfptr] := 70; + gfptr := gfptr + 1; + if gfptr = gflimit then + gfswap + end else begin + begin + gfbuf[gfptr] := 74 + delta; + gfptr := gfptr + 1; + if gfptr = gflimit then + gfswap + end; + goto 30 + end + end {:1173}; + gfpaint(m - curminm); + 30: + prevn := n + end else {:1172} + gfpaint(m - prevm); + prevm := m; + prevw := w + end {:1170} + end else if w <= 0 then begin {1171:} + gfpaint(m - prevm); + prevm := m; + prevw := w + end {:1171}; + m := mm + end; + w := ww; + q := mem[q].hh.rh + until mm = 268435456; + if w <> 0 then + printnl(911); + if ((prevm - mem[curedges + 3].hh.lh) + xoff) > gfmaxm then + gfmaxm := (prevm - mem[curedges + 3].hh.lh) + xoff {:1169}; + p := mem[p].hh.lh; + n := n - 1 + end; + if prevn = 4096 then begin {1168:} + gfboc(0, 0, 0, 0); + if gfmaxm < 0 then + gfmaxm := 0; + if gfminn > 0 then + gfminn := 0 + end else if (prevn + yoff) < gfminn then {:1168} + gfminn := prevn + yoff {:1167}; + begin + gfbuf[gfptr] := 69; + gfptr := gfptr + 1; + if gfptr = gflimit then + gfswap + end; + gfprevptr := gfoffset + gfptr; + totalchars := totalchars + 1; + printchar(93); + flush(output); + if internal[11] > 0 then + printedges(910, true, xoff, yoff) + end; { shipout } +{:1165} + {995:} + {1006:} + + procedure tryeq(l, r: halfword); + label + 30, 31; + var + p: halfword; + t: 16..19; + q: halfword; + pp: halfword; + tt: 17..19; + copied: boolean; {1007:} + begin + t := mem[l].hh.b0; + if t = 16 then begin + t := 17; + p := constdependency(-mem[l + 1].int); + q := p + end else if t = 19 then begin + t := 17; + p := singledependency(l); + mem[p + 1].int := -mem[p + 1].int; + q := depfinal + end else begin + p := mem[l + 1].hh.rh; + q := p; + while true do begin + mem[q + 1].int := -mem[q + 1].int; + if mem[q].hh.lh = (-30000) then + goto 30; + q := mem[q].hh.rh + end; + 30: + mem[mem[l + 1].hh.lh].hh.rh := mem[q].hh.rh; + mem[mem[q].hh.rh + 1].hh.lh := mem[l + 1].hh.lh; + mem[l].hh.b0 := 16 + end {:1007}; +{1009:} + if r = (-30000) then + if curtype = 16 then begin + mem[q + 1].int := mem[q + 1].int + curexp; + goto 31 + end else begin + tt := curtype; + if tt = 19 then + pp := singledependency(curexp) + else + pp := mem[curexp + 1].hh.rh + end + else if mem[r].hh.b0 = 16 then begin + mem[q + 1].int := mem[q + 1].int + mem[r + 1].int; + goto 31 + end else begin + tt := mem[r].hh.b0; + if tt = 19 then + pp := singledependency(r) + else + pp := mem[r + 1].hh.rh + end; + if tt <> 19 then + copied := false + else begin + copied := true; + tt := 17 + end; {1010:} + watchcoefs := false; + if t = tt then + p := pplusq(p, pp, t) + else if t = 18 then + p := pplusfq(p, 65536, pp, 18, 17) + else begin + q := p; + while mem[q].hh.lh <> (-30000) do begin + mem[q + 1].int := roundfraction(mem[q + 1].int); + q := mem[q].hh.rh + end; + t := 18; + p := pplusq(p, pp, t) + end; + watchcoefs := true; +{:1010} + if copied then + flushnodelist(pp); + 31: {:1009} + ; + if mem[p].hh.lh = (-30000) then begin {1008:} + if abs(mem[p + 1].int) > 64 then begin + begin + if interaction = 3 then + ; + printnl(133); + print(761) + end; + print(763); + printscaled(mem[p + 1].int); + printchar(41); + begin + helpptr := 2; + helpline[1] := 762; + helpline[0] := 760 + end; + putgeterror + end else if r = (-30000) then begin {623:} + begin + if interaction = 3 then + ; + printnl(133); + print(465) + end; + begin + helpptr := 2; + helpline[1] := 466; + helpline[0] := 467 + end; + putgeterror + end {:623}; + freenode(p, 2) + end else begin {:1008} + lineareq(p, t); + if r = (-30000) then + if curtype <> 16 then + if mem[curexp].hh.b0 = 16 then begin + pp := curexp; + curexp := mem[curexp + 1].int; + curtype := 16; + freenode(pp, 2) + end + end + end; {:1006} {1001:} + + procedure makeeq(lhs: halfword); + label + 20, 30, 45; + var + t: smallnumber; + v: integer; + p, q: halfword; + begin + 20: + t := mem[lhs].hh.b0; + if t <= 14 then + v := mem[lhs + 1].int; + case t of {1003:} + 2, 4, 6, 9, 11: + if curtype = (t + 1) then begin + nonlineareq(v, curexp, false); + goto 30 + end else if curtype = t then begin {1004:} + if curtype <= 4 then begin + if curtype = 4 then begin + if strvsstr(v, curexp) <> 0 then + goto 45 + end else if v <> curexp then + goto 45; {623:} + begin + begin + if interaction = 3 then + ; + printnl(133); + print(465) + end; + begin + helpptr := 2; + helpline[1] := 466; + helpline[0] := 467 + end; + putgeterror + end {:623}; + goto 30 + end; + begin + if interaction = 3 then + ; + printnl(133); + print(758) + end; + begin + helpptr := 2; + helpline[1] := 759; + helpline[0] := 760 + end; + putgeterror; + goto 30; + 45: + begin + if interaction = 3 then + ; + printnl(133); + print(761) + end; + begin + helpptr := 2; + helpline[1] := 762; + helpline[0] := 760 + end; + putgeterror; + goto 30 + end {:1004}; + 3, 5, 7, 12, 10: + if curtype = (t - 1) then begin + nonlineareq(curexp, lhs, true); + goto 30 + end else if curtype = t then begin + ringmerge(lhs, curexp); + goto 30 + end else if curtype = 14 then + if t = 10 then begin + pairtopath; + goto 20 + end; + 13, 14: + if curtype = t then begin {1005:} + p := v + bignodesize[t]; + q := mem[curexp + 1].int + bignodesize[t]; + repeat + p := p - 2; + q := q - 2; + tryeq(p, q) + until p = v; + goto 30 + end {:1005}; + 16, 17, 18, 19: + if curtype >= 16 then begin + tryeq(lhs, -30000); + goto 30 + end; + 1: + + end +{:1003}; {1002:} + disperr(lhs, 155); + disperr(-30000, 755); + if mem[lhs].hh.b0 <= 14 then + printtype(mem[lhs].hh.b0) + else + print(211); + printchar(61); + if curtype <= 14 then + printtype(curtype) + else + print(211); + printchar(41); + begin + helpptr := 2; + helpline[1] := 756; + helpline[0] := 757 + end; {:1002} + putgeterror; + 30: + begin + if aritherror then + cleararith + end; + recyclevalue(lhs); + freenode(lhs, 2) + end; {:1001} + + procedure doassignment; + forward; + + procedure doequation; + var + lhs: halfword; + p: halfword; + begin + lhs := stashcurexp; + getxnext; + varflag := 77; + scanexpression; + if curcmd = 51 then + doequation + else if curcmd = 77 then + doassignment; + if internal[7] > 131072 then begin {997:} + begindiagnostic; + printnl(714); + printexp(lhs, 0); + print(750); + printexp(-30000, 0); + print(706); + enddiagnostic(false) + end {:997}; + if curtype = 10 then + if mem[lhs].hh.b0 = 14 then begin + p := stashcurexp; + unstashcurexp(lhs); + lhs := p + end; + makeeq(lhs) + end; {:995} {996:} + + procedure doassignment; + var + lhs: halfword; + p: halfword; + q: halfword; + begin + if curtype <> 20 then begin + disperr(-30000, 747); + begin + helpptr := 2; + helpline[1] := 748; + helpline[0] := 749 + end; + error; + doequation + end else begin + lhs := curexp; + curtype := 1; + getxnext; + varflag := 77; + scanexpression; + if curcmd = 51 then + doequation + else if curcmd = 77 then + doassignment; + if internal[7] > 131072 then begin {998:} + begindiagnostic; + printnl(123); + if mem[lhs].hh.lh > 2241 then + print(intname[mem[lhs].hh.lh - 2241]) + else + showtokenlist(lhs, -30000, 1000, 0); + print(329); + printexp(-30000, 0); + printchar(125); + enddiagnostic(false) + end {:998}; + if mem[lhs].hh.lh > 2241 then {999:} + if curtype = 16 then + internal[mem[lhs].hh.lh - 2241] := curexp + else begin + disperr(-30000, 751); + print(intname[mem[lhs].hh.lh - 2241]); + print(752); + begin + helpptr := 2; + helpline[1] := 753; + helpline[0] := 754 + end; + putgeterror + end {:999} {1000:} + else begin + p := findvariable(lhs); + if p <> (-30000) then begin + q := stashcurexp; + curtype := undtype(p); + recyclevalue(p); + mem[p].hh.b0 := curtype; + mem[p + 1].int := -30000; + makeexpcopy(p); + p := stashcurexp; + unstashcurexp(q); + makeeq(p) + end else begin + obliterated(lhs); + putgeterror + end + end {:1000}; + flushnodelist(lhs) + end + end; {:996} {1015:} + + procedure dotypedeclaration; + var + t: smallnumber; + p: halfword; + q: halfword; + begin + if curmod >= 13 then + t := curmod + else + t := curmod + 1; + repeat + p := scandeclaredvariable; + flushvariable(eqtb[mem[p].hh.lh].rh, mem[p].hh.rh, false); + q := findvariable(p); + if q <> (-30000) then begin + mem[q].hh.b0 := t; + mem[q + 1].int := -30000 + end else begin + begin + if interaction = 3 then + ; + printnl(133); + print(764) + end; + begin + helpptr := 2; + helpline[1] := 765; + helpline[0] := 766 + end; + putgeterror + end; + flushlist(p); + if curcmd < 79 then begin {1016:} + begin + if interaction = 3 then + ; + printnl(133); + print(767) + end; + begin + helpptr := 5; + helpline[4] := 768; + helpline[3] := 769; + helpline[2] := 770; + helpline[1] := 771; + helpline[0] := 772 + end; + if curcmd = 42 then + helpline[2] := 773; + putgeterror; + scannerstatus := 2; + repeat + getnext; {743:} + if curcmd = 39 then begin + if strref[curmod] < 127 then + if strref[curmod] > 1 then + strref[curmod] := strref[curmod] - 1 + else + flushstring(curmod) + end {:743} + until curcmd >= 79; + scannerstatus := 0 + end {:1016} + until curcmd > 79 + end; { dotypedeclaration } +{:1015} + {1021:} + + procedure dorandomseed; + begin + getxnext; + if curcmd <> 77 then begin + missingerr(329); + begin + helpptr := 1; + helpline[0] := 778 + end; + backerror + end; + getxnext; + scanexpression; + if curtype <> 16 then begin + disperr(-30000, 779); + begin + helpptr := 2; + helpline[1] := 780; + helpline[0] := 781 + end; + putgetflusherror(0) + end else begin {1022:} + initrandoms(curexp); + if selector >= 2 then begin + oldsetting := selector; + selector := 2; + printnl(782); + printscaled(curexp); + printchar(125); + printnl(155); + selector := oldsetting + end + end {:1022} + end; {:1021} {1029:} + + procedure doprotection; + var + m: 0..1; + t: halfword; + begin + m := curmod; + repeat + getsymbol; + t := eqtb[cursym].lh; + if m = 0 then begin + if t >= 83 then + eqtb[cursym].lh := t - 83 + end else if t < 83 then + eqtb[cursym].lh := t + 83; + getxnext + until curcmd <> 79 + end; {:1029} {1031:} + + procedure defdelims; + var + ldelim, rdelim: halfword; + begin + getclearsymbol; + ldelim := cursym; + getclearsymbol; + rdelim := cursym; + eqtb[ldelim].lh := 31; + eqtb[ldelim].rh := rdelim; + eqtb[rdelim].lh := 62; + eqtb[rdelim].rh := ldelim; + getxnext + end; {:1031} {1034:} + + procedure dostatement; + forward; + + procedure dointerim; + begin + getxnext; + if curcmd <> 40 then begin + begin + if interaction = 3 then + ; + printnl(133); + print(788) + end; + if cursym = 0 then + print(793) + else + print(hash[cursym].rh); + print(794); + begin + helpptr := 1; + helpline[0] := 795 + end; + backerror + end else begin + saveinternal(curmod); + backinput + end; + dostatement + end; { dointerim } +{:1034} + {1035:} + + procedure dolet; + var + l: halfword; + begin + getsymbol; + l := cursym; + getxnext; + if curcmd <> 51 then + if curcmd <> 77 then begin + missingerr(61); + begin + helpptr := 3; + helpline[2] := 796; + helpline[1] := 538; + helpline[0] := 797 + end; + backerror + end; + getsymbol; + if curcmd in + [10, 53, 44, 49] then + case curcmd of + 10, 53, 44, 49: + mem[curmod].hh.lh := mem[curmod].hh.lh + 1 + end + else + ; + clearsymbol(l, false); + eqtb[l].lh := curcmd; + if curcmd = 41 then + eqtb[l].rh := -30000 + else + eqtb[l].rh := curmod; + getxnext + end; {:1035} {1036:} + + procedure donewinternal; + begin + repeat + if intptr = maxinternal then + overflow(798, maxinternal); + getclearsymbol; + intptr := intptr + 1; + eqtb[cursym].lh := 40; + eqtb[cursym].rh := intptr; + intname[intptr] := hash[cursym].rh; + internal[intptr] := 0; + getxnext + until curcmd <> 79 + end; {:1036} {1040:} + + procedure doshow; + begin + repeat + getxnext; + scanexpression; + printnl(629); + printexp(-30000, 2); + flushcurexp(0) + until curcmd <> 79 + end; {:1040} {1041:} + + procedure disptoken; + begin + printnl(804); + if cursym = 0 then begin {1042:} + if curcmd = 42 then + printscaled(curmod) + else if curcmd = 38 then begin + gpointer := curmod; + printcapsule + end else begin + printchar(34); + print(curmod); + printchar(34); + begin + if strref[curmod] < 127 then + if strref[curmod] > 1 then + strref[curmod] := strref[curmod] - 1 + else + flushstring(curmod) + end + end + end else begin {:1042} + print(hash[cursym].rh); + printchar(61); + if eqtb[cursym].lh >= 83 then + print(805); + printcmdmod(curcmd, curmod); + if curcmd = 10 then begin + println; + showmacro(curmod, -30000, 100000) + end + end + end; {:1041} {1044:} + + procedure doshowtoken; + begin + repeat + getnext; + disptoken; + getxnext + until curcmd <> 79 + end; {:1044} {1045:} + + procedure doshowstats; + {printint(varused);printchar(38);printint(dynused); + if false then} + begin + printnl(814); + print(228); + print(425); + printint((himemmin - lomemmax) - 1); + print(815); + println; + printnl(816); + printint(strptr - initstrptr); + printchar(38); + printint(poolptr - initpoolptr); + print(425); + printint(maxstrings - maxstrptr); + printchar(38); + printint(poolsize - maxpoolptr); + print(815); + println; + getxnext + end; {:1045} +{1046:} + + procedure dispvar(p: halfword); + var + q: halfword; + n: 0..maxprintline; + begin + if mem[p].hh.b0 = 21 then begin {1047:} + q := mem[p + 1].hh.lh; + repeat + dispvar(q); + q := mem[q].hh.rh + until q = (-29983); + q := mem[p + 1].hh.rh; + while mem[q].hh.b1 = 3 do begin + dispvar(q); + q := mem[q].hh.rh + end + end else if mem[p].hh.b0 >= 22 then begin {:1047} {1048:} + printnl(155); + printvariablename(p); + if mem[p].hh.b0 > 22 then + print(530); + print(817); + if fileoffset >= (maxprintline - 20) then + n := 5 + else + n := (maxprintline - fileoffset) - 15; + showmacro(mem[p + 1].int, -30000, n) + end else if mem[p].hh.b0 <> 0 then begin {:1048} + printnl(155); + printvariablename(p); + printchar(61); + printexp(p, 0) + end + end; {:1046} {1049:} + + procedure doshowvar; + label + 30; + begin + repeat + getnext; + if cursym > 0 then + if cursym <= 2241 then + if curcmd = 41 then + if curmod <> (-30000) then begin + dispvar(curmod); + goto 30 + end; + disptoken; + 30: + getxnext + until curcmd <> 79 + end; {:1049} {1050:} + + procedure doshowdependencies; + var + p: halfword; + begin + p := mem[-29987].hh.rh; + while p <> (-29987) do begin + if interesting(p) then begin + printnl(155); + printvariablename(p); + if mem[p].hh.b0 = 17 then + printchar(61) + else + print(632); + printdependency(mem[p + 1].hh.rh, mem[p].hh.b0) + end; + p := mem[p + 1].hh.rh; + while mem[p].hh.lh <> (-30000) do + p := mem[p].hh.rh; + p := mem[p].hh.rh + end; + getxnext + end; {:1050} {1051:} + + procedure doshowwhatever; + begin + if interaction = 3 then + ; + case curmod of + 0: + doshowtoken; + 1: + doshowstats; + 2: + doshow; + 3: + doshowvar; + 4: + doshowdependencies + end; + if internal[32] > 0 then begin + begin + if interaction = 3 then + ; + printnl(133); + print(818) + end; + if interaction < 3 then begin + helpptr := 0; + errorcount := errorcount - 1 + end else begin + helpptr := 1; + helpline[0] := 819 + end; + if curcmd = 80 then + error + else + putgeterror + end + end; {:1051} {1054:} + + function scanwith: boolean; + var + t: smallnumber; + result: boolean; + begin + t := curmod; + curtype := 1; + getxnext; + scanexpression; + result := false; + if curtype <> t then begin {1055:} + disperr(-30000, 827); + begin + helpptr := 2; + helpline[1] := 828; + helpline[0] := 829 + end; + if t = 6 then + helpline[1] := 830; + putgetflusherror(0) + end else if curtype = 6 then {:1055} + result := true {1056:} + else begin + curexp := roundunscaled(curexp); + if (abs(curexp) < 4) and (curexp <> 0) then + result := true + else begin + begin + if interaction = 3 then + ; + printnl(133); + print(831) + end; + begin + helpptr := 1; + helpline[0] := 829 + end; + putgetflusherror(0) + end + end {:1056}; + scanwith := result + end; {:1054} {1057:} + + procedure findedgesvar(t: halfword); + var + p: halfword; + begin + p := findvariable(t); + curedges := -30000; + if p = (-30000) then begin + obliterated(t); + putgeterror + end else if mem[p].hh.b0 <> 11 then begin + begin + if interaction = 3 then + ; + printnl(133); + print(654) + end; + showtokenlist(t, -30000, 1000, 0); + print(832); + printtype(mem[p].hh.b0); + printchar(41); + begin + helpptr := 2; + helpline[1] := 833; + helpline[0] := 834 + end; + putgeterror + end else + curedges := mem[p + 1].int; + flushnodelist(t) + end; {:1057} {1059:} + + procedure doaddto; + label + 30, 45; + var + lhs, rhs: halfword; + t: smallnumber; + w: integer; + p: halfword; + q: halfword; + begin + getxnext; + varflag := 68; + scanprimary; + if curtype <> 20 then begin {1060:} + disperr(-30000, 835); + begin + helpptr := 4; + helpline[3] := 836; + helpline[2] := 837; + helpline[1] := 838; + helpline[0] := 834 + end; + putgetflusherror(0) + end else begin {:1060} + lhs := curexp; + curpathtype := curmod; + curtype := 1; + getxnext; + scanexpression; + if curpathtype = 2 then begin {1061:} + findedgesvar(lhs); + if curedges = (-30000) then + flushcurexp(0) + else if curtype <> 11 then begin + disperr(-30000, 839); + begin + helpptr := 2; + helpline[1] := 840; + helpline[0] := 834 + end; + putgetflusherror(0) + end else begin + mergeedges(curexp); + flushcurexp(0) + end + end else begin {:1061} {1062:} + if curtype = 14 then + pairtopath; + if curtype <> 9 then begin + disperr(-30000, 839); + begin + helpptr := 2; + helpline[1] := 841; + helpline[0] := 834 + end; + putgetflusherror(0); + flushtokenlist(lhs) + end else begin + rhs := curexp; + w := 1; + curpen := -29997; + { + 1063:} + while curcmd = 66 do + if scanwith then + if curtype = 16 then + w := curexp + else begin + if mem[curpen].hh.lh = (-30000) then + tosspen(curpen) + else + mem[curpen].hh.lh := mem[curpen].hh.lh - 1; + curpen := curexp + end {:1063}; {1064:} + findedgesvar(lhs); + if curedges = (-30000) then + tossknotlist(rhs) + else begin + lhs := -30000; + if mem[rhs].hh.b0 = 0 then + if curpathtype = 0 then {1065:} + if mem[rhs].hh.rh = rhs then begin {1066:} + mem[rhs + 5].int := mem[rhs + 1].int; + mem[rhs + 6].int := mem[rhs + 2].int; + mem[rhs + 3].int := mem[rhs + 1].int; + mem[rhs + 4].int := mem[rhs + 2].int; + mem[rhs].hh.b0 := 1; + mem[rhs].hh.b1 := 1 + end else begin {:1066} + p := htapypoc(rhs); + q := mem[p].hh.rh; + mem[pathtail + 5].int := mem[q + 5].int; + mem[pathtail + 6].int := mem[q + 6].int; + mem[pathtail].hh.b1 := mem[q].hh.b1; + mem[pathtail].hh.rh := mem[q].hh.rh; + freenode(q, 7); + mem[p + 5].int := mem[rhs + 5].int; + mem[p + 6].int := mem[rhs + 6].int; + mem[p].hh.b1 := mem[rhs].hh.b1; + mem[p].hh.rh := mem[rhs].hh.rh; + freenode(rhs, 7); + rhs := p + end {:1065} {1067:} + else begin + begin + if interaction = 3 then + ; + printnl(133); + print(842) + end; + begin + helpptr := 2; + helpline[1] := 843; + helpline[0] := 834 + end; + putgeterror; + tossknotlist(rhs); + goto 45 + end {:1067} + else if curpathtype = 0 then + lhs := htapypoc(rhs); + curwt := w; + rhs := makespec(rhs, mem[curpen + 9].int, internal[5]); {1068:} + if turningnumber <= 0 then + if curpathtype <> 0 then + if internal[39] > 0 then + if (turningnumber < 0) and (mem[curpen].hh.rh = (-30000)) then + curwt := -curwt + else begin + if turningnumber = 0 then + if (internal[39] <= 65536) and (mem[curpen].hh.rh = (-30000)) then + goto 30 + else + printstrange(844) + else + printstrange(845); + begin + helpptr := 3; + helpline[2] := 846; + helpline[1] := 847; + helpline[0] := 848 + end; + putgeterror + end; + 30: {:1068} + ; + if mem[curpen + 9].int = 0 then + fillspec(rhs) + else + fillenvelope(rhs); + if lhs <> (-30000) then begin + revturns := true; + lhs := makespec(lhs, mem[curpen + 9].int, internal[5]); + revturns := false; + if mem[curpen + 9].int = 0 then + fillspec(lhs) + else + fillenvelope(lhs) + end; + 45: {:1064} + + end; + if mem[curpen].hh.lh = (-30000) then + tosspen(curpen) + else + mem[curpen].hh.lh := mem[curpen].hh.lh - 1 + end + end {:1062} + end + end; {:1059} {1070:} {1098:} + + function tfmcheck(m: smallnumber): scaled; + begin + if abs(internal[m]) >= 134217728 then begin + begin + if interaction = 3 then + ; + printnl(133); + print(865) + end; + print(intname[m]); + print(866); + begin + helpptr := 1; + helpline[0] := 867 + end; + putgeterror; + if internal[m] > 0 then + tfmcheck := 134217727 + else + tfmcheck := -134217727 + end else + tfmcheck := internal[m] + end; {:1098} + + procedure doshipout; + label + 10; + var + c: integer; + begin + getxnext; + varflag := 80; + scanexpression; + {1060: + } + if curtype <> 20 then + if curtype = 11 then + curedges := curexp + else begin + begin + disperr(-30000, 835); + begin + helpptr := 4; + helpline[3] := 836; + helpline[2] := 837; + helpline[1] := 838; + helpline[0] := 834 + end; + putgetflusherror(0) + end {:1060}; + goto 10 + end + else begin + findedgesvar(curexp); + curtype := 1 + end; + if curedges <> (-30000) then begin + c := roundunscaled(internal[18]) mod 256; + if c < 0 then + c := c + 256; {1099:} + if c < bc then + bc := c; + if c > ec then + ec := c; + charexists[c] := true; + gfdx[c] := internal[24]; + gfdy[c] := internal[25]; + tfmwidth[c] := tfmcheck(20); + tfmheight[c] := tfmcheck(21); + tfmdepth[c] := tfmcheck(22); + tfmitalcorr[c] := tfmcheck(23) {:1099}; + if internal[34] >= 0 then + shipout(c) + end; + flushcurexp(0); + 10: + + end; {:1070} +{1071:} + + procedure dodisplay; + label + 45, 50, 10; + var + e: halfword; + begin + getxnext; + varflag := 73; + scanprimary; + if curtype <> 20 then begin {1060:} + disperr(-30000, 835); + begin + helpptr := 4; + helpline[3] := 836; + helpline[2] := 837; + helpline[1] := 838; + helpline[0] := 834 + end; + putgetflusherror(0) + end else begin {:1060} + e := curexp; + curtype := 1; + getxnext; + scanexpression; + if curtype <> 16 then + goto 50; + curexp := roundunscaled(curexp); + if curexp < 0 then + goto 45; + if curexp > 15 then + goto 45; + if not windowopen[curexp] then + goto 45; + findedgesvar(e); + if curedges <> (-30000) then + dispedges(curexp); + goto 10; + 45: + curexp := curexp * 65536; + 50: + disperr(-30000, 849); + begin + helpptr := 1; + helpline[0] := 850 + end; + putgetflusherror(0); + flushtokenlist(e) + end; + 10: + + end; { dodisplay } +{:1071} + {1072:} + + function getpair(c: commandcode): boolean; + var + p: halfword; + b: boolean; + begin + if curcmd <> c then + getpair := false + else begin + getxnext; + scanexpression; + if nicepair(curexp, curtype) then begin + p := mem[curexp + 1].int; + curx := mem[p + 1].int; + cury := mem[p + 3].int; + b := true + end else + b := false; + flushcurexp(0); + getpair := b + end + end; {:1072} {1073:} + + procedure doopenwindow; + label + 45, 10; + var + k: integer; + r0, c0, r1, c1: scaled; + begin + getxnext; + scanexpression; + if curtype <> 16 then + goto 45; + k := roundunscaled(curexp); + if k < 0 then + goto 45; + if k > 15 then + goto 45; + if not getpair(70) then + goto 45; + r0 := curx; + c0 := cury; + if not getpair(71) then + goto 45; + r1 := curx; + c1 := cury; + if not getpair(72) then + goto 45; + openawindow(k, r0, c0, r1, c1, curx, cury); + goto 10; + 45: + begin + if interaction = 3 then + ; + printnl(133); + print(851) + end; + begin + helpptr := 2; + helpline[1] := 852; + helpline[0] := 853 + end; + putgeterror; + 10: + + end; {:1073} {1074:} + + procedure docull; + label + 45, 10; + var + e: halfword; + keeping: 0..1; + w, win, wout: integer; + begin + w := 1; + getxnext; + varflag := 67; + scanprimary; + if curtype <> 20 then begin {1060:} + disperr(-30000, 835); + begin + helpptr := 4; + helpline[3] := 836; + helpline[2] := 837; + helpline[1] := 838; + helpline[0] := 834 + end; + putgetflusherror(0) + end else begin {:1060} + e := curexp; + curtype := 1; + keeping := curmod; + if not getpair(67) then + goto 45; + while (curcmd = 66) and (curmod = 16) do + if scanwith then + w := curexp; {1075:} + if curx > cury then + goto 45; + if keeping = 0 then begin + if (curx > 0) or (cury < 0) then + goto 45; + wout := w; + win := 0 + end else begin + if (curx <= 0) and (cury >= 0) then + goto 45; + wout := 0; + win := w + end {:1075}; + findedgesvar(e); + if curedges <> (-30000) then + culledges(floorunscaled(curx + 65535), floorunscaled(cury), wout, win); + goto 10; + 45: + begin + if interaction = 3 then + ; + printnl(133); + print(854) + end; + begin + helpptr := 1; + helpline[0] := 855 + end; + putgeterror; + flushtokenlist(e) + end; + 10: + + end; {:1074} {1082:} + + procedure domessage; + var + m: 0..2; + begin + m := curmod; + getxnext; + scanexpression; + if curtype <> 4 then begin + disperr(-30000, 565); + begin + helpptr := 1; + helpline[0] := 859 + end; + putgeterror + end else + case m of + 0: + begin + printnl(155); + slowprint(curexp) + end; + 1: + begin {1086:} + begin + if interaction = 3 then + ; + printnl(133); + print(155) + end; + slowprint(curexp); + if errhelp <> 0 then + useerrhelp := true + else if longhelpseen then begin + helpptr := 1; + helpline[0] := 860 + end else begin + if interaction < 3 then + longhelpseen := true; + begin + helpptr := 4; + helpline[3] := 861; + helpline[2] := 862; + helpline[1] := 863; + helpline[0] := 864 + end + end; + putgeterror; + useerrhelp := false + end; {:1086} + 2: + begin {1083:} + if errhelp <> 0 then begin + if strref[errhelp] < 127 then + if strref[errhelp] > 1 then + strref[errhelp] := strref[errhelp] - 1 + else + flushstring(errhelp) + end; + if (strstart[curexp + 1] - strstart[curexp]) = 0 then + errhelp := 0 + else begin + errhelp := curexp; + begin + if strref[errhelp] < 127 then + strref[errhelp] := strref[errhelp] + 1 + end + end + end + end {:1083}; + flushcurexp(0) + end; {:1082} {1103:} + + function getcode: eightbits; + label + 40; + var + c: integer; + begin + getxnext; + scanexpression; + if curtype = 16 then begin + c := roundunscaled(curexp); + if c >= 0 then + if c < 256 then + goto 40 + end else if curtype = 4 then + if (strstart[curexp + 1] - strstart[curexp]) = 1 then begin + c := strpool[strstart[curexp]]; + goto 40 + end; + disperr(-30000, 873); + begin + helpptr := 2; + helpline[1] := 874; + helpline[0] := 875 + end; + putgetflusherror(0); + c := 0; + 40: + getcode := c + end; {:1103} {1104:} + + procedure settag(c: eightbits; t: smallnumber; r: eightbits); + begin + if chartag[c] = 0 then begin + chartag[c] := t; + charremainder[c] := r + end else begin {1105:} + begin + if interaction = 3 then + ; + printnl(133); + print(876) + end; + if (c > 32) and (c < 128) then + print(c) + else begin + print(877); + printint(c) + end; + print(878); + case chartag[c] of + 1: + print(879); + 2: + print(880); + 3: + print(870) + end; + begin + helpptr := 2; + helpline[1] := 881; + helpline[0] := 834 + end; + putgeterror + end {:1105} + end; {:1104} {1106:} + + procedure dotfmcommand; + label + 22; + var + c, cc: eightbits; + k: 0..256; + j: integer; + begin + case curmod of + 0: + begin {1107:} + c := getcode; + while curcmd = 78 do begin + cc := getcode; + settag(c, 2, cc); + c := cc + end + end; {:1107} + 1: + begin {1108:} + 22: + c := getcode; + if curcmd = 78 then begin {1111:} + if nl < 256 then + settag(c, 1, nl) + else begin + begin + if interaction = 3 then + ; + printnl(133); + print(891) + end; + begin + helpptr := 1; + helpline[0] := 892 + end; + error + end; + goto 22 + end {:1111}; + if curcmd = 76 then begin {1112:} + ligkern[nl].b1 := c - 128; + ligkern[nl].b2 := curmod - 128; + ligkern[nl].b0 := -128; + if curmod = 0 then + ligkern[nl].b3 := getcode - 128 + else begin + getxnext; + scanexpression; + if curtype <> 16 then begin + disperr(-30000, 893); + begin + helpptr := 2; + helpline[1] := 894; + helpline[0] := 179 + end; + putgetflusherror(0) + end; + kern[nk] := curexp; + k := 0; + while kern[k] <> curexp do + k := k + 1; + if k = nk then begin + if nk = 256 then + overflow(890, 256); + nk := nk + 1 + end; + ligkern[nl].b3 := k - 128 + end {:1112}; + if nl = ligtablesize then + overflow(886, ligtablesize); + nl := nl + 1; + if curcmd = 79 then + goto 22 + end else begin + begin + if interaction = 3 then + ; + printnl(133); + print(887) + end; + begin + helpptr := 1; + helpline[0] := 888 + end; + backerror + end; + if nl > 0 then + ligkern[nl - 1].b0 := 0 + end; {:1108} + 2: + begin {1113:} + if ne = 256 then + overflow(870, 256); + c := getcode; + settag(c, 3, ne); + if curcmd <> 78 then begin + missingerr(58); + begin + helpptr := 1; + helpline[0] := 895 + end; + backerror + end; + exten[ne].b0 := getcode - 128; + if curcmd <> 79 then begin + missingerr(44); + begin + helpptr := 1; + helpline[0] := 895 + end; + backerror + end; + exten[ne].b1 := getcode - 128; + if curcmd <> 79 then begin + missingerr(44); + begin + helpptr := 1; + helpline[0] := 895 + end; + backerror + end; + exten[ne].b2 := getcode - 128; + if curcmd <> 79 then begin + missingerr(44); + begin + helpptr := 1; + helpline[0] := 895 + end; + backerror + end; + exten[ne].b3 := getcode - 128; + ne := ne + 1 + end; {:1113} + 3, 4: + begin + c := curmod; + getxnext; + scanexpression; + if (curtype <> 16) or (curexp < 32768) then begin + disperr(-30000, 882); + begin + helpptr := 2; + helpline[1] := 883; + helpline[0] := 884 + end; + putgeterror + end else begin + j := roundunscaled(curexp); + if curcmd <> 78 then begin + missingerr(58); + begin + helpptr := 1; + helpline[0] := 885 + end; + backerror + end; + if c = 3 then {1114:} + repeat + if j > headersize then + overflow(871, headersize); + headerbyte[j] := getcode; + j := j + 1 + until curcmd <> 79 {:1114} {1115:} + else + repeat + if j > maxfontdimen then + overflow(872, maxfontdimen); + while j > np do begin + np := np + 1; + param[np] := 0 + end; + getxnext; + scanexpression; + if curtype <> 16 then begin + disperr(-30000, 896); + begin + helpptr := 1; + helpline[0] := 179 + end; + putgetflusherror(0) + end; + param[j] := curexp; + j := j + 1 + until curcmd <> 79 {:1115} + end + end + end + end; {:1106} {1177:} + + procedure dospecial; + var + m: smallnumber; + begin + m := curmod; + getxnext; + scanexpression; + if internal[34] >= 0 then + if curtype <> m then begin {1178:} + disperr(-30000, 914); + begin + helpptr := 1; + helpline[0] := 915 + end; + putgeterror + end else begin {:1178} + if outputfilename = 0 then + initgf; + if m = 4 then + gfstring(curexp, 0) + else begin + begin + gfbuf[gfptr] := 243; + gfptr := gfptr + 1; + if gfptr = gflimit then + gfswap + end; + gffour(curexp) + end + end; + flushcurexp(0) + end; {:1177} {1186:} + {procedure storebasefile;var k:integer; + p,q:halfword;x:integer;w:fourquarters;begin[1200:]selector:=5; + print(925);print(jobname);printchar(32); + printint(roundunscaled(internal[14])mod 100);printchar(46); + printint(roundunscaled(internal[15]));printchar(46); + printint(roundunscaled(internal[16]));printchar(41); + if interaction=0 then selector:=2 else selector:=3; + begin if poolptr+1>maxpoolptr then begin if poolptr+1>poolsize then + overflow(129,poolsize-initpoolptr);maxpoolptr:=poolptr+1;end;end; + baseident:=makestring;strref[baseident]:=127;packjobname(926); + while not wopenout(basefile)do promptfilename(927,926);printnl(928); + print(wmakenamestring(basefile));flushstring(strptr-1); + printnl(baseident)[:1200];[1190:]begin basefile^.int:=503742536; + put(basefile);end;begin basefile^.int:=-30000;put(basefile);end; + begin basefile^.int:=30000;put(basefile);end;begin basefile^.int:=2100; + put(basefile);end;begin basefile^.int:=1777;put(basefile);end; + begin basefile^.int:=6;put(basefile);end[:1190]; + [1192:]begin basefile^.int:=poolptr;put(basefile);end; + begin basefile^.int:=strptr;put(basefile);end; + for k:=0 to strptr do begin basefile^.int:=strstart[k];put(basefile); + end;k:=0;while k+4<poolptr do begin w.b0:=strpool[k];w.b1:=strpool[k+1]; + w.b2:=strpool[k+2];w.b3:=strpool[k+3];begin basefile^.qqqq:=w; + put(basefile);end;k:=k+4;end;k:=poolptr-4;w.b0:=strpool[k]; + w.b1:=strpool[k+1];w.b2:=strpool[k+2];w.b3:=strpool[k+3]; + begin basefile^.qqqq:=w;put(basefile);end;println;printint(strptr); + print(922);printint(poolptr)[:1192];[1194:]sortavail;varused:=0; + begin basefile^.int:=lomemmax;put(basefile);end; + begin basefile^.int:=rover;put(basefile);end;p:=-30000;q:=rover;x:=0; + repeat for k:=p to q+1 do begin basefile^:=mem[k];put(basefile);end; + x:=x+q+2-p;varused:=varused+q-p;p:=q+mem[q].hh.lh;q:=mem[q+1].hh.rh; + until q=rover;varused:=varused+lomemmax-p;dynused:=memend+1-himemmin; + for k:=p to lomemmax do begin basefile^:=mem[k];put(basefile);end; + x:=x+lomemmax+1-p;begin basefile^.int:=himemmin;put(basefile);end; + begin basefile^.int:=avail;put(basefile);end; + for k:=himemmin to memend do begin basefile^:=mem[k];put(basefile);end; + x:=x+memend+1-himemmin;p:=avail; + while p<>-30000 do begin dynused:=dynused-1;p:=mem[p].hh.rh;end; + begin basefile^.int:=varused;put(basefile);end; + begin basefile^.int:=dynused;put(basefile);end;println;printint(x); + print(923);printint(varused);printchar(38);printint(dynused)[:1194]; + [1196:]begin basefile^.int:=hashused;put(basefile);end; + stcount:=2228-hashused; + for p:=1 to hashused do if hash[p].rh<>0 then begin begin basefile^.int + :=p;put(basefile);end;begin basefile^.hh:=hash[p];put(basefile);end; + begin basefile^.hh:=eqtb[p];put(basefile);end;stcount:=stcount+1;end; + for p:=hashused+1 to 2241 do begin begin basefile^.hh:=hash[p]; + put(basefile);end;begin basefile^.hh:=eqtb[p];put(basefile);end;end; + begin basefile^.int:=stcount;put(basefile);end;println; + printint(stcount);print(924)[:1196];[1198:]begin basefile^.int:=intptr; + put(basefile);end; + for k:=1 to intptr do begin begin basefile^.int:=internal[k]; + put(basefile);end;begin basefile^.int:=intname[k];put(basefile);end;end; + begin basefile^.int:=startsym;put(basefile);end; + begin basefile^.int:=interaction;put(basefile);end; + begin basefile^.int:=baseident;put(basefile);end; + begin basefile^.int:=bgloc;put(basefile);end;begin basefile^.int:=egloc; + put(basefile);end;begin basefile^.int:=serialno;put(basefile);end; + begin basefile^.int:=69069;put(basefile);end;internal[12]:=0[:1198]; + [1201:]wclose(basefile)[:1201];end;} + {:1186} + + procedure dostatement; + begin + curtype := 1; + getxnext; + if curcmd > 43 then begin {990:} + if curcmd < 80 then begin + begin + if interaction = 3 then + ; + printnl(133); + print(733) + end; + printcmdmod(curcmd, curmod); + printchar(39); + begin + helpptr := 5; + helpline[4] := 734; + helpline[3] := 735; + helpline[2] := 736; + helpline[1] := 737; + helpline[0] := 738 + end; + backerror; + getxnext + end + end else if curcmd > 30 then begin {:990} {993:} + varflag := 77; + scanexpression; + if curcmd < 81 then begin + if curcmd = 51 then + doequation + else if curcmd = 77 then + doassignment + else if curtype = 4 then begin {994:} + if internal[1] > 0 then begin + printnl(155); + slowprint(curexp); + {---------------------} + auxprintnl(155); + auxslowprint(curexp); + {---------------------} + flush(output) + end; + if internal[34] > 0 then begin {1179:} + if outputfilename = 0 then + initgf; + gfstring(916, curexp) + end {:1179} + end else if curtype <> 1 then begin {:994} + disperr(-30000, 743); + begin + helpptr := 3; + helpline[2] := 744; + helpline[1] := 745; + helpline[0] := 746 + end; + putgeterror + end; + flushcurexp(0); + curtype := 1 + end + end else begin {:993} {992:} + if internal[7] > 0 then + showcmdmod(curcmd, curmod); + case curcmd of + 30: + dotypedeclaration; + 16: + if curmod > 2 then + makeopdef + else if curmod > 0 then + scandef; {1020:} + 24: + dorandomseed; {:1020} {1023:} + 23: + begin + println; + interaction := curmod; {70:} + if interaction = 0 then + selector := 0 + else + selector := 1 {:70}; + if jobname <> 0 then + selector := selector + 2; + getxnext + end; {:1023} {1026:} + 21: + doprotection; {:1026} {1030:} + 27: + defdelims; {:1030} {1033:} + 12: + repeat + getsymbol; + savevariable(cursym); + getxnext + until curcmd <> 79; + 13: + dointerim; + 14: + dolet; + 15: + donewinternal; {:1033} {1039:} + 22: + doshowwhatever; +{:1039} + {1058:} + 18: + doaddto; {:1058} {1069:} + 17: + doshipout; + 11: + dodisplay; + 28: + doopenwindow; + 19: + docull; {:1069} {1076:} + 26: + begin + getsymbol; + startsym := cursym; + getxnext + end; {:1076} {1081:} + 25: + domessage; {:1081} {1100:} + 20: + dotfmcommand; {:1100} {1175:} + 29: + dospecial + end {:1175}; + curtype := 1 + end {:992}; + if curcmd < 80 then begin {991:} + begin + if interaction = 3 then + ; + printnl(133); + print(739) + end; + begin + helpptr := 6; + helpline[5] := 740; + helpline[4] := 741; + helpline[3] := 742; + helpline[2] := 736; + helpline[1] := 737; + helpline[0] := 738 + end; + backerror; + scannerstatus := 2; + repeat + getnext; {743:} + if curcmd = 39 then begin + if strref[curmod] < 127 then + if strref[curmod] > 1 then + strref[curmod] := strref[curmod] - 1 + else + flushstring(curmod) + end {:743} + until curcmd > 79; + scannerstatus := 0 + end {:991}; + errorcount := 0 + end; {:989} +{1017:} + + procedure maincontrol; + begin + repeat + dostatement; + if curcmd = 81 then begin + begin + if interaction = 3 then + ; + printnl(133); + print(774) + end; + begin + helpptr := 2; + helpline[1] := 775; + helpline[0] := 555 + end; + flusherror(0) + end + until curcmd = 82 + end; {:1017} {1117:} + + function sortin(v: scaled): halfword; + label + 40; + var + p, q, r: halfword; + begin + p := 29999; + while true do begin + q := mem[p].hh.rh; + if v <= mem[q + 1].int then + goto 40; + p := q + end; + 40: + if v < mem[q + 1].int then begin + r := getnode(2); + mem[r + 1].int := v; + mem[r].hh.rh := q; + mem[p].hh.rh := r + end; + sortin := mem[p].hh.rh + end; {:1117} +{1118:} + + function mincover(d: scaled): integer; + var + p: halfword; + l: scaled; + m: integer; + begin + m := 0; + p := mem[29999].hh.rh; + perturbation := 2147483647; + while p <> (-29981) do begin + m := m + 1; + l := mem[p + 1].int; + repeat + p := mem[p].hh.rh + until mem[p + 1].int > (l + d); + if (mem[p + 1].int - l) < perturbation then + perturbation := mem[p + 1].int - l + end; + mincover := m + end; {:1118} {1120:} + + function threshold(m: integer): scaled; + var + d: scaled; + begin + if mincover(0) <= m then + threshold := 0 + else begin + repeat + d := perturbation + until mincover(d + d) <= m; + while mincover(d) > m do + d := perturbation; + threshold := d + end + end; {:1120} +{1121:} + + function skimp(m: integer): integer; + var + d: scaled; + p, q, r: halfword; + l: scaled; + v: scaled; + begin + d := threshold(m); + perturbation := 0; + q := 29999; + m := 0; + p := mem[29999].hh.rh; + while p <> (-29981) do begin + m := m + 1; + l := mem[p + 1].int; + mem[p].hh.lh := m; + if mem[mem[p].hh.rh + 1].int <= (l + d) then begin {1122:} + repeat + p := mem[p].hh.rh; + mem[p].hh.lh := m + until mem[mem[p].hh.rh + 1].int > (l + d); + v := (l + mem[p + 1].int) div 2; + if (mem[p + 1].int - v) > perturbation then + perturbation := mem[p + 1].int - v; + r := q; + repeat + r := mem[r].hh.rh; + mem[r + 1].int := v + until r = p; + mem[q].hh.rh := p + end {:1122}; + q := p; + p := mem[p].hh.rh + end; + skimp := m + end; {:1121} {1123:} + + procedure tfmwarning(m: smallnumber); + begin + printnl(897); + print(intname[m]); + print(898); + printscaled(perturbation); + print(899) + end; { tfmwarning } +{:1123} + {1128:} + + procedure fixdesignsize; + var + d: scaled; + begin + d := internal[26]; + if (d < 65536) or (d >= 134217728) then begin + if d <> 0 then + printnl(900); + d := 8388608; + internal[26] := d + end; + if headerbyte[5] < 0 then + if headerbyte[6] < 0 then + if headerbyte[7] < 0 then + if headerbyte[8] < 0 then begin + headerbyte[5] := d div 1048576; + headerbyte[6] := (d div 4096) mod 256; + headerbyte[7] := (d div 16) mod 256; + headerbyte[8] := (d mod 16) * 16 + end; + maxtfmdimen := (16 * internal[26]) - (internal[26] div 2097152); + if maxtfmdimen >= 134217728 then + maxtfmdimen := 134217727 + end; {:1128} {1129:} + + function dimenout(x: scaled): integer; + begin + if abs(x) > maxtfmdimen then begin + tfmchanged := tfmchanged + 1; + if x > 0 then + x := 16777215 + else + x := -16777215 + end else + x := makescaled(x * 16, internal[26]); + dimenout := x + end; {:1129} {1131:} + + procedure fixchecksum; + label + 10; + var + k: eightbits; + b1, b2, b3, b4: eightbits; + x: integer; + begin + if headerbyte[1] < 0 then + if headerbyte[2] < 0 then + if headerbyte[3] < 0 then + if headerbyte[4] < 0 then begin {1132:} + b1 := bc; + b2 := ec; + b3 := bc; + b4 := ec; + tfmchanged := 0; + for k := bc to ec do + if charexists[k] then begin + x := dimenout(mem[tfmwidth[k] + 1].int) + ((k + 4) * 4194304); + b1 := ((b1 + b1) + x) mod 255; + b2 := ((b2 + b2) + x) mod 253; + b3 := ((b3 + b3) + x) mod 251; + b4 := ((b4 + b4) + x) mod 247 + end {:1132}; + headerbyte[1] := b1; + headerbyte[2] := b2; + headerbyte[3] := b3; + headerbyte[4] := b4; + goto 10 + end; + for k := 1 to 4 do + if headerbyte[k] < 0 then + headerbyte[k] := 0; + 10: + + end; {:1131} +{1133:} + + procedure tfmqqqq(x: fourquarters); + begin + bwritebyte(tfmfile, x.b0 + 128); + bwritebyte(tfmfile, x.b1 + 128); + bwritebyte(tfmfile, x.b2 + 128); + bwritebyte(tfmfile, x.b3 + 128) + end; {:1133} +{1187:} + {779:} + + function openbasefile: boolean; + label + 40, 10; + var + j: 0..bufsize; + begin + j := curinput.locfield; + if buffer[curinput.locfield] = 38 then begin + curinput.locfield := curinput.locfield + 1; + j := curinput.locfield; + buffer[last] := 32; + while buffer[j] <> 32 do + j := j + 1; + packbufferedname(0, curinput.locfield, j - 1); + if wopenin(basefile) then + goto 40; + writeln(output, 'Sorry, I can''t find that base;', ' will try PLAIN.'); + flush(output) + end; + packbufferedname(5, 1, 0); + if not wopenin(basefile) then begin + writeln(output, 'I can''t find the PLAIN base file!'); + openbasefile := false; + goto 10 + end; + 40: + curinput.locfield := j; + openbasefile := true; + 10: + + end; {:779} + + function loadbasefile: boolean; + label + 6666, 10; + var + k: integer; + p, q: halfword; + x: integer; + w: fourquarters; {1191:} + begin + x := basefile^.int; + if x <> 503742536 then + goto 6666; + begin + get(basefile); + x := basefile^.int + end; + if x <> (-30000) then + goto 6666; + begin + get(basefile); + x := basefile^.int + end; + if x <> 30000 then + goto 6666; + begin + get(basefile); + x := basefile^.int + end; + if x <> 2100 then + goto 6666; + begin + get(basefile); + x := basefile^.int + end; + if x <> 1777 then + goto 6666; + begin + get(basefile); + x := basefile^.int + end; + if x <> 6 then + goto 6666 {:1191}; +{1193:} + begin + begin + get(basefile); + x := basefile^.int + end; + if x < 0 then + goto 6666; + if x > poolsize then begin + writeln(output, '---! Must increase the ', 'string pool size'); + goto 6666 + end else + poolptr := x + end; + begin + begin + get(basefile); + x := basefile^.int + end; + if x < 0 then + goto 6666; + if x > maxstrings then begin + writeln(output, '---! Must increase the ', 'max strings'); + goto 6666 + end else + strptr := x + end; + for k := 0 to strptr do begin + begin + begin + get(basefile); + x := basefile^.int + end; + if (x < 0) or (x > poolptr) then + goto 6666 + else + strstart[k] := x + end; + strref[k] := 127 + end; + k := 0; + while (k + 4) < poolptr do begin + begin + get(basefile); + w := basefile^.qqqq + end; + strpool[k] := w.b0; + strpool[k + 1] := w.b1; + strpool[k + 2] := w.b2; + strpool[k + 3] := w.b3; + k := k + 4 + end; + k := poolptr - 4; + begin + get(basefile); + w := basefile^.qqqq + end; + strpool[k] := w.b0; + strpool[k + 1] := w.b1; + strpool[k + 2] := w.b2; + strpool[k + 3] := w.b3 {:1193}; {1195:} + begin + begin + get(basefile); + x := basefile^.int + end; + if (x < (-28978)) or (x > 29997) then + goto 6666 + else + lomemmax := x + end; + begin + begin + get(basefile); + x := basefile^.int + end; + if (x < (-29977)) or (x > lomemmax) then + goto 6666 + else + rover := x + end; + p := -30000; + q := rover; + x := 0; + repeat + for k := p to q + 1 do begin + get(basefile); + mem[k] := basefile^ + end; + p := q + mem[q].hh.lh; + if (p > lomemmax) or ((q >= mem[q + 1].hh.rh) and (mem[q + 1].hh.rh <> rover)) then + goto 6666; + q := mem[q + 1].hh.rh + until q = rover; + for k := p to lomemmax do begin + get(basefile); + mem[k] := basefile^ + end; + begin + begin + get(basefile); + x := basefile^.int + end; + if (x < (lomemmax + 1)) or (x > 29998) then + goto 6666 + else + himemmin := x + end; + begin + begin + get(basefile); + x := basefile^.int + end; + if (x < (-30000)) or (x > 30000) then + goto 6666 + else + avail := x + end; + memend := 30000; + for k := himemmin to memend do begin + get(basefile); + mem[k] := basefile^ + end; + begin + get(basefile); + varused := basefile^.int + end; + begin + get(basefile); + dynused := basefile^.int + end {:1195}; {1197:} + begin + begin + get(basefile); + x := basefile^.int + end; + if (x < 1) or (x > 2229) then + goto 6666 + else + hashused := x + end; + p := 0; + repeat + begin + begin + get(basefile); + x := basefile^.int + end; + if (x < (p + 1)) or (x > hashused) then + goto 6666 + else + p := x + end; + begin + get(basefile); + hash[p] := basefile^.hh + end; + begin + get(basefile); + eqtb[p] := basefile^.hh + end + until p = hashused; + for p := hashused + 1 to 2241 do begin + begin + get(basefile); + hash[p] := basefile^.hh + end; + begin + get(basefile); + eqtb[p] := basefile^.hh + end + end; + begin + get(basefile); + stcount := basefile^.int + end {:1197}; {1199:} + begin + begin + get(basefile); + x := basefile^.int + end; + if (x < 40) or (x > maxinternal) then + goto 6666 + else + intptr := x + end; + for k := 1 to intptr do begin + begin + get(basefile); + internal[k] := basefile^.int + end; + begin + begin + get(basefile); + x := basefile^.int + end; + if (x < 0) or (x > strptr) then + goto 6666 + else + intname[k] := x + end + end; + begin + begin + get(basefile); + x := basefile^.int + end; + if (x < 0) or (x > 2229) then + goto 6666 + else + startsym := x + end; + begin + begin + get(basefile); + x := basefile^.int + end; + if (x < 0) or (x > 3) then + goto 6666 + else + interaction := x + end; + begin + begin + get(basefile); + x := basefile^.int + end; + if (x < 0) or (x > strptr) then + goto 6666 + else + baseident := x + end; + begin + begin + get(basefile); + x := basefile^.int + end; + if (x < 1) or (x > 2241) then + goto 6666 + else + bgloc := x + end; + begin + begin + get(basefile); + x := basefile^.int + end; + if (x < 1) or (x > 2241) then + goto 6666 + else + egloc := x + end; + begin + get(basefile); + serialno := basefile^.int + end; + begin + get(basefile); + x := basefile^.int + end; + if (x <> 69069) or eof(basefile) then + goto 6666 {:1199}; + loadbasefile := true; + goto 10; + 6666: + ; + writeln(output, '(Fatal base file error; I''m stymied)'); + loadbasefile := false; + 10: + + end; {:1187} {1202:} {823:} + + procedure scanprimary; + label + 20, 30, 31, 32; + var + p, q, r: halfword; + c: quarterword; + myvarflag: 0..82; + ldelim, rdelim: halfword; {831:} + groupline: integer; {:831} {836:} + num, denom: scaled; {:836} {843:} + prehead, posthead, tail: halfword; + tt: smallnumber; + t: halfword; + macroref: halfword; {:843} + begin + myvarflag := varflag; + varflag := 0; + 20: + begin + if aritherror then + cleararith + end; {825:} +{if panicking then checkmem(false);} + if interrupt <> 0 then + if OKtointerrupt then begin + backinput; + begin + if interrupt <> 0 then + pauseforinstructions + end; + getxnext + end {:825}; + if curcmd in + [31, 32, 39, 42, 33, 34, 30, 36, + 43, 37, 35, 40, 38, 41] then + case curcmd of + 31: + begin {826:} + ldelim := cursym; + rdelim := curmod; + getxnext; + scanexpression; + if (curcmd = 79) and (curtype >= 16) then begin {830:} + p := getnode(2); + mem[p].hh.b0 := 14; + mem[p].hh.b1 := 11; + initbignode(p); + q := mem[p + 1].int; + stashin(q); + getxnext; + scanexpression; + if curtype < 16 then begin + disperr(-30000, 639); + begin + helpptr := 4; + helpline[3] := 640; + helpline[2] := 641; + helpline[1] := 642; + helpline[0] := 643 + end; + putgetflusherror(0) + end; + stashin(q + 2); + checkdelimiter(ldelim, rdelim); + curtype := 14; + curexp := p + end else {:830} + checkdelimiter(ldelim, rdelim) + end; {:826} + 32: + begin {832:} + groupline := line; + if internal[7] > 0 then + showcmdmod(curcmd, curmod); + begin + p := getavail; + mem[p].hh.lh := 0; + mem[p].hh.rh := saveptr; + saveptr := p + end; + repeat + dostatement + until curcmd <> 80; + if curcmd <> 81 then begin + begin + if interaction = 3 then + ; + printnl(133); + print(644) + end; + printint(groupline); + print(645); + begin + helpptr := 2; + helpline[1] := 646; + helpline[0] := 647 + end; + backerror; + curcmd := 81 + end; + unsave; + if internal[7] > 0 then + showcmdmod(curcmd, curmod) + end; {:832} + 39: + begin {833:} + curtype := 4; + curexp := curmod + end; {:833} + 42: + begin {837:} + curexp := curmod; + curtype := 16; + getxnext; + if curcmd <> 54 then begin + num := 0; + denom := 0 + end else begin + getxnext; + if curcmd <> 42 then begin + backinput; + curcmd := 54; + curmod := 72; + cursym := 2233; + goto 30 + end; + num := curexp; + denom := curmod; + if denom = 0 then begin {838:} + begin + if interaction = 3 then + ; + printnl(133); + print(648) + end; + begin + helpptr := 1; + helpline[0] := 649 + end; + error + end else {:838} + curexp := makescaled(num, denom); + begin + if aritherror then + cleararith + end; + getxnext + end; + if curcmd >= 30 then + if curcmd < 42 then begin + p := stashcurexp; + scanprimary; + if (abs(num) >= abs(denom)) or (curtype < 14) then + dobinary(p, 71) + else begin + fracmult(num, denom); + freenode(p, 2) + end + end; + goto 30 + end; {:837} + 33: {834:} + donullary(curmod) {:834}; + 34, 30, 36, 43: + begin {835:} + c := curmod; + getxnext; + scanprimary; + dounary(c); + goto 30 + end; {:835} + 37: + begin {839:} + c := curmod; + getxnext; + scanexpression; + if curcmd <> 69 then begin + missingerr(347); + print(581); + printcmdmod(37, c); + begin + helpptr := 1; + helpline[0] := 582 + end; + backerror + end; + p := stashcurexp; + getxnext; + scanprimary; + dobinary(p, c); + goto 30 + end; {:839} + 35: + begin {840:} + getxnext; + scansuffix; + oldsetting := selector; + selector := 5; + showtokenlist(curexp, -30000, 100000, 0); + flushtokenlist(curexp); + curexp := makestring; + selector := oldsetting; + curtype := 4; + goto 30 + end; {:840} + 40: + begin {841:} + q := curmod; + if myvarflag = 77 then begin + getxnext; + if curcmd = 77 then begin + curexp := getavail; + mem[curexp].hh.lh := q + 2241; + curtype := 20; + goto 30 + end; + backinput + end; + curtype := 16; + curexp := internal[q] + end; {:841} + 38: + makeexpcopy(curmod); + 41: + begin {844:} + begin + prehead := avail; + if prehead = (-30000) then + prehead := getavail + else begin + avail := mem[prehead].hh.rh; + mem[prehead].hh.rh := -30000 + end {dynused:=dynused+1;} + end; + tail := prehead; + posthead := -30000; + tt := 1; + while true do begin + t := curtok; + mem[tail].hh.rh := t; + if tt <> 0 then begin {850:} + begin + p := mem[prehead].hh.rh; + q := mem[p].hh.lh; + tt := 0; + if (eqtb[q].lh mod 83) = 41 then begin + q := eqtb[q].rh; + if q = (-30000) then + goto 32; + while true do begin + p := mem[p].hh.rh; + if p = (-30000) then begin + tt := mem[q].hh.b0; + goto 32 + end; + if mem[q].hh.b0 <> 21 then + goto 32; + q := mem[mem[q + 1].hh.lh].hh.rh; + if p >= himemmin then begin + repeat + q := mem[q].hh.rh + until mem[q + 2].hh.lh >= mem[p].hh.lh; + if mem[q + 2].hh.lh > mem[p].hh.lh then + goto 32 + end + end + end; + 32: {:850} + + end; + if tt >= 22 then begin {845:} + mem[tail].hh.rh := -30000; + if tt > 22 then begin + posthead := getavail; + tail := posthead; + mem[tail].hh.rh := t; + tt := 0; + macroref := mem[q + 1].int; + mem[macroref].hh.lh := mem[macroref].hh.lh + 1 + end else begin {853:} + p := getavail; + mem[prehead].hh.lh := mem[prehead].hh.rh; + mem[prehead].hh.rh := p; + mem[p].hh.lh := t; + macrocall(mem[q + 1].int, prehead, -30000); + getxnext; + goto 20 + end {:853} + end {:845} + end; + getxnext; + tail := t; + if curcmd = 63 then begin {846:} + getxnext; + scanexpression; + if curcmd <> 64 then begin {847:} + backinput; + backexpr; + curcmd := 63; + curmod := 0; + cursym := 2232 + end else begin {:847} + if curtype <> 16 then + badsubscript; + curcmd := 42; + curmod := curexp; + cursym := 0 + end + end {:846}; + if curcmd > 42 then + goto 31; + if curcmd < 40 then + goto 31 + end; + 31: {852:} + if posthead <> (-30000) then begin {854:} + backinput; + p := getavail; + q := mem[posthead].hh.rh; + mem[prehead].hh.lh := mem[prehead].hh.rh; + mem[prehead].hh.rh := posthead; + mem[posthead].hh.lh := q; + mem[posthead].hh.rh := p; + mem[p].hh.lh := mem[q].hh.rh; + mem[q].hh.rh := -30000; + macrocall(macroref, prehead, -30000); + mem[macroref].hh.lh := mem[macroref].hh.lh - 1; + getxnext; + goto 20 + end {:854}; + q := mem[prehead].hh.rh; + begin + mem[prehead].hh.rh := avail; + avail := prehead + end +{dynused:=dynused-1;}; + if curcmd = myvarflag then begin + curtype := 20; + curexp := q; + goto 30 + end; + p := findvariable(q); + if p <> (-30000) then + makeexpcopy(p) + else begin + obliterated(q); + helpline[2] := 661; + helpline[1] := 662; + helpline[0] := 663; + putgetflusherror(0) + end; + flushnodelist(q); + goto 30 {:852} + end + end + else + begin {:844} + badexp(633); + goto 20 + end; + getxnext; + 30: + if curcmd = 63 then + if curtype >= 16 then begin {859:} + p := stashcurexp; + getxnext; + scanexpression; + if curcmd <> 79 then begin {847:} + begin + backinput; + backexpr; + curcmd := 63; + curmod := 0; + cursym := 2232 + end {:847}; + unstashcurexp(p) + end else begin + q := stashcurexp; + getxnext; + scanexpression; + if curcmd <> 64 then begin + missingerr(93); + begin + helpptr := 3; + helpline[2] := 665; + helpline[1] := 666; + helpline[0] := 563 + end; + backerror + end; + r := stashcurexp; + makeexpcopy(q); + dobinary(r, 70); + dobinary(p, 71); + dobinary(q, 69); + getxnext + end + end {:859} + end; {:823} {860:} + + procedure scansuffix; + label + 30; + var + h, t: halfword; + p: halfword; + begin + h := getavail; + t := h; + while true do begin + if curcmd = 63 then begin {861:} + getxnext; + scanexpression; + if curtype <> 16 then + badsubscript; + if curcmd <> 64 then begin + missingerr(93); + begin + helpptr := 3; + helpline[2] := 667; + helpline[1] := 666; + helpline[0] := 563 + end; + backerror + end; + curcmd := 42; + curmod := curexp + end {:861}; + if curcmd = 42 then + p := newnumtok(curmod) + else if (curcmd = 41) or (curcmd = 40) then begin + p := getavail; + mem[p].hh.lh := cursym + end else + goto 30; + mem[t].hh.rh := p; + t := p; + getxnext + end; + 30: + curexp := mem[h].hh.rh; + begin + mem[h].hh.rh := avail; + avail := h + end {dynused:=dynused-1;}; + curtype := 20 + end; {:860} {862:} + + procedure scansecondary; + label + 20, 22; + var + p, q, r: halfword; + c, d: halfword; + macname: halfword; + begin + 20: + if (curcmd < 30) or (curcmd > 43) then + badexp(668); + scanprimary; + 22: + if curcmd <= 55 then + if curcmd >= 52 then begin + p := stashcurexp; + c := curmod; + d := curcmd; + if d = 53 then begin + macname := cursym; + mem[c].hh.lh := mem[c].hh.lh + 1 + end; + getxnext; + scanprimary; + if d <> 53 then + dobinary(p, c) + else begin + backinput; + binarymac(p, c, macname); + mem[c].hh.lh := mem[c].hh.lh - 1; + getxnext; + goto 20 + end; + goto 22 + end + end; {:862} +{864:} + + procedure scantertiary; + label + 20, 22; + var + p: halfword; + c, d: halfword; + macname: halfword; + begin + 20: + if (curcmd < 30) or (curcmd > 43) then + badexp(669); + scansecondary; + if curtype = 8 then + materializepen; + 22: + if curcmd <= 45 then + if curcmd >= 43 then begin + p := stashcurexp; + c := curmod; + d := curcmd; + if d = 44 then begin + macname := cursym; + mem[c].hh.lh := mem[c].hh.lh + 1 + end; + getxnext; + scansecondary; + if d <> 44 then + dobinary(p, c) + else begin + backinput; + binarymac(p, c, macname); + mem[c].hh.lh := mem[c].hh.lh - 1; + getxnext; + goto 20 + end; + goto 22 + end + end; {:864} +{868:} + + procedure scanexpression; + label + 20, 30, 22, 25, 26, 10; + var + p, q, r, pp, qq: halfword; + c, d: halfword; + myvarflag: 0..82; + macname: halfword; + cyclehit: boolean; + x, y: scaled; + t: 0..4; + begin + myvarflag := varflag; + 20: + if (curcmd < 30) or (curcmd > 43) then + badexp(672); + scantertiary; + 22: + if curcmd <= 51 then + if curcmd >= 46 then + if (curcmd <> 51) or (myvarflag <> 77) then begin + p := stashcurexp; + c := curmod; + d := curcmd; + if d = 49 then begin + macname := cursym; + mem[c].hh.lh := mem[c].hh.lh + 1 + end; + if (d < 48) or ((d = 48) and ((mem[p].hh.b0 = 14) or (mem[p].hh.b0 = 9))) then begin {869:} + cyclehit := false; {870:} + begin + unstashcurexp(p); + if curtype = 14 then + p := newknot + else if curtype = 9 then + p := curexp + else + goto 10; + q := p; + while mem[q].hh.rh <> p do + q := mem[q].hh.rh; + if mem[p].hh.b0 <> 0 then begin + r := copyknot(p); + mem[q].hh.rh := r; + q := r + end; + mem[p].hh.b0 := 4; + mem[q].hh.b1 := 4 + end {:870}; + 25: {874:} + if curcmd = 46 then begin {879:} + t := scandirection; + if t <> 4 then begin + mem[q].hh.b1 := t; + mem[q + 5].int := curexp; + if mem[q].hh.b0 = 4 then begin + mem[q].hh.b0 := t; + mem[q + 3].int := curexp + end + end + end {:879}; + d := curcmd; + if d = 47 then begin {881:} + getxnext; + if curcmd = 58 then begin {882:} + getxnext; + y := curcmd; + if curcmd = 59 then + getxnext; + scanprimary; {883:} + if (curtype <> 16) or (curexp < 49152) then begin + disperr(-30000, 690); + begin + helpptr := 1; + helpline[0] := 691 + end; + putgetflusherror(65536) + end {:883}; + if y = 59 then + curexp := -curexp; + mem[q + 6].int := curexp; + if curcmd = 52 then begin + getxnext; + y := curcmd; + if curcmd = 59 then + getxnext; + scanprimary; {883:} + if (curtype <> 16) or (curexp < 49152) then begin + disperr(-30000, 690); + begin + helpptr := 1; + helpline[0] := 691 + end; + putgetflusherror(65536) + end {:883}; + if y = 59 then + curexp := -curexp + end; + y := curexp + end else if curcmd = 57 then begin {:882} {884:} + mem[q].hh.b1 := 1; + t := 1; + getxnext; + scanprimary; + knownpair; + mem[q + 5].int := curx; + mem[q + 6].int := cury; + if curcmd <> 52 then begin + x := mem[q + 5].int; + y := mem[q + 6].int + end else begin + getxnext; + scanprimary; + knownpair; + x := curx; + y := cury + end + end else begin {:884} + mem[q + 6].int := 65536; + y := 65536; + backinput; + goto 30 + end; + if curcmd <> 47 then begin + missingerr(279); + begin + helpptr := 1; + helpline[0] := 689 + end; + backerror + end; + 30: {:881} + + end else if d <> 48 then + goto 26; + getxnext; + if curcmd = 46 then begin {880:} + t := scandirection; + if mem[q].hh.b1 <> 1 then + x := curexp + else + t := 1 + end else if mem[q].hh.b1 <> 1 then begin {:880} + t := 4; + x := 0 + end {:874}; + if curcmd = 36 then begin {886:} + cyclehit := true; + getxnext; + pp := p; + qq := p; + if d = 48 then + if p = q then begin + d := 47; + mem[q + 6].int := 65536; + y := 65536 + end + end else begin {:886} + scantertiary; {885:} + begin + if curtype <> 9 then + pp := newknot + else + pp := curexp; + qq := pp; + while mem[qq].hh.rh <> pp do + qq := mem[qq].hh.rh; + if mem[pp].hh.b0 <> 0 then begin + r := copyknot(pp); + mem[qq].hh.rh := r; + qq := r + end; + mem[pp].hh.b0 := 4; + mem[qq].hh.b1 := 4 + end {:885} + end; {887:} + begin + if d = 48 then + if (mem[q + 1].int <> mem[pp + 1].int) or (mem[q + 2].int <> mem[pp + 2].int) then begin + begin + if interaction = 3 then + ; + printnl(133); + print(692) + end; + begin + helpptr := 3; + helpline[2] := 693; + helpline[1] := 694; + helpline[0] := 695 + end; + putgeterror; + d := 47; + mem[q + 6].int := 65536; + y := 65536 + end; +{889:} + if mem[pp].hh.b1 = 4 then + if (t = 3) or (t = 2) then begin + mem[pp].hh.b1 := t; + mem[pp + 5].int := x + end {:889}; + if d = 48 then begin {890:} + if mem[q].hh.b0 = 4 then + if mem[q].hh.b1 = 4 then begin + mem[q].hh.b0 := 3; + mem[q + 3].int := 65536 + end; + if mem[pp].hh.b1 = 4 then + if t = 4 then begin + mem[pp].hh.b1 := 3; + mem[pp + 5].int := 65536 + end; + mem[q].hh.b1 := mem[pp].hh.b1; + mem[q].hh.rh := mem[pp].hh.rh; + mem[q + 5].int := mem[pp + 5].int; + mem[q + 6].int := mem[pp + 6].int; + freenode(pp, 7); + if qq = pp then + qq := q + end else begin {:890} {888:} + if mem[q].hh.b1 = 4 then + if (mem[q].hh.b0 = 3) or (mem[q].hh.b0 = 2) then begin + mem[q].hh.b1 := mem[q].hh.b0; + mem[q + 5].int := mem[q + 3].int + end {:888}; + mem[q].hh.rh := pp; + mem[pp + 4].int := y; + if t <> 4 then begin + mem[pp + 3].int := x; + mem[pp].hh.b0 := t + end + end; + q := qq + end {:887}; + if curcmd >= 46 then + if curcmd <= 48 then + if not cyclehit then + goto 25; + 26: {891:} + if cyclehit then begin + if d = 48 then + p := q + end else begin + mem[p].hh.b0 := 0; + if mem[p].hh.b1 = 4 then begin + mem[p].hh.b1 := 3; + mem[p + 5].int := 65536 + end; + mem[q].hh.b1 := 0; + if mem[q].hh.b0 = 4 then begin + mem[q].hh.b0 := 3; + mem[q + 3].int := 65536 + end; + mem[q].hh.rh := p + end; + makechoices(p); + curtype := 9; + curexp := p {:891} + end else begin {:869} + getxnext; + scantertiary; + if d <> 49 then + dobinary(p, c) + else begin + backinput; + binarymac(p, c, macname); + mem[c].hh.lh := mem[c].hh.lh - 1; + getxnext; + goto 20 + end + end; + goto 22 + end; + 10: + + end; {:868} {892:} + + procedure getboolean; + begin + getxnext; + scanexpression; + if curtype <> 2 then begin + disperr(-30000, 696); + begin + helpptr := 2; + helpline[1] := 697; + helpline[0] := 698 + end; + putgetflusherror(31); + curtype := 2 + end + end; {:892} {224:} + + procedure printcapsule; + begin + printchar(40); + printexp(gpointer, 0); + printchar(41) + end; + + procedure tokenrecycle; + begin + recyclevalue(gpointer) + end; {:224} {1205:} + + procedure closefilesandtermina; + var + k: integer; + lh: integer; + p: halfword; + x: scaled; + {if internal[12]>0 then[1208:]if jobname>0 then begin writeln( + logfile,' '); + writeln(logfile,'Here is how much of METAFONT''s memory',' you used:'); + write(logfile,' ',maxstrptr-initstrptr:1,' string'); + if maxstrptr<>initstrptr+1 then write(logfile,'s'); + writeln(logfile,' out of ',maxstrings-initstrptr:1); + writeln(logfile,' ',maxpoolptr-initpoolptr:1, + ' string characters out of ',poolsize-initpoolptr:1); + writeln(logfile,' ',lomemmax+30000+memend-himemmin+2:1, + ' words of memory out of ',memend+30001:1); + writeln(logfile,' ',stcount:1,' symbolic tokens out of ',2100:1); + writeln(logfile,' ',maxinstack:1,'i,',intptr:1,'n,',maxroundingptr:1, + 'r,',maxparamstack:1,'p,',maxbufstack+1:1,'b stack positions out of ', + stacksize:1,'i,',maxinternal:1,'n,',maxwiggle:1,'r,',150:1,'p,',bufsize: + 1,'b');end[:1208];} + begin + {1206:} + if (gfprevptr > 0) or (internal[33] > 0) then begin {1207:} + rover := -29977; + mem[rover].hh.rh := 32767; + lomemmax := himemmin - 1; + if (lomemmax - rover) > 32767 then + lomemmax := 32767 + rover; + mem[rover].hh.lh := lomemmax - rover; + mem[rover + 1].hh.lh := rover; + mem[rover + 1].hh.rh := rover; + mem[lomemmax].hh.rh := -30000; + mem[lomemmax].hh.lh := -30000 {:1207}; {1124:} + mem[29999].hh.rh := -29981; + for k := bc to ec do + if charexists[k] then + tfmwidth[k] := sortin(tfmwidth[k]); + nw := skimp(255) + 1; + dimenhead[1] := mem[29999].hh.rh; + if perturbation >= 4096 then + tfmwarning(20) {:1124}; + fixdesignsize; + fixchecksum; + if internal[33] > 0 then begin {1126:} + mem[29999].hh.rh := -29981; + for k := bc to ec do + if charexists[k] then + if tfmheight[k] = 0 then + tfmheight[k] := -29985 + else + tfmheight[k] := sortin(tfmheight[k]); + nh := skimp(15) + 1; + dimenhead[2] := mem[29999].hh.rh; + if perturbation >= 4096 then + tfmwarning(21); + mem[29999].hh.rh := -29981; + for k := bc to ec do + if charexists[k] then + if tfmdepth[k] = 0 then + tfmdepth[k] := -29985 + else + tfmdepth[k] := sortin(tfmdepth[k]); + nd := skimp(15) + 1; + dimenhead[3] := mem[29999].hh.rh; + if perturbation >= 4096 then + tfmwarning(22); + mem[29999].hh.rh := -29981; + for k := bc to ec do + if charexists[k] then + if tfmitalcorr[k] = 0 then + tfmitalcorr[k] := -29985 + else + tfmitalcorr[k] := sortin(tfmitalcorr[k]); + ni := skimp(63) + 1; + dimenhead[4] := mem[29999].hh.rh; + if perturbation >= 4096 then + tfmwarning(23) {:1126}; {1134:} + if jobname = 0 then + openlogfile; + packjobname(901); + while not bopenout(tfmfile, nameoffile) do + promptfilename(902, 901); + metricfilename := bmakenamestring(tfmfile); {1135:} + k := headersize; + while headerbyte[k] < 0 do + k := k - 1; + lh := (k + 3) div 4; + if bc > ec then + bc := 1; + bwrite2bytes(tfmfile, (((((((((6 + lh) + ((ec - bc) + 1)) + nw) + nh) + nd) + ni) + nl) + nk) + ne) + np); + bwrite2bytes(tfmfile, lh); + bwrite2bytes(tfmfile, bc); + bwrite2bytes(tfmfile, ec); + bwrite2bytes(tfmfile, nw); + bwrite2bytes(tfmfile, nh); + bwrite2bytes(tfmfile, nd); + bwrite2bytes(tfmfile, ni); + bwrite2bytes(tfmfile, nl); + bwrite2bytes(tfmfile, nk); + bwrite2bytes(tfmfile, ne); + bwrite2bytes(tfmfile, np); + for k := 1 to 4 * lh do begin + if headerbyte[k] < 0 then + headerbyte[k] := 0; + bwritebyte(tfmfile, headerbyte[k]) + end {:1135}; {1137:} + for k := bc to ec do + if not charexists[k] then + bwrite4bytes(tfmfile, 0) + else begin + bwritebyte(tfmfile, mem[tfmwidth[k]].hh.lh); + bwritebyte(tfmfile, (mem[tfmheight[k]].hh.lh * 16) + mem[tfmdepth[k]].hh.lh); + bwritebyte(tfmfile, (mem[tfmitalcorr[k]].hh.lh * 4) + chartag[k]); + bwritebyte(tfmfile, charremainder[k]) + end {:1137}; {1138:} + tfmchanged := 0; + for k := 1 to 4 do begin + bwrite4bytes(tfmfile, 0); + p := dimenhead[k]; + while p <> (-29981) do begin + bwrite4bytes(tfmfile, dimenout(mem[p + 1].int)); + p := mem[p].hh.rh + end + end {:1138}; {1139:} + for k := 0 to nl - 1 do + tfmqqqq(ligkern[k]); + for k := 0 to nk - 1 do + bwrite4bytes(tfmfile, dimenout(kern[k])) {:1139}; +{1140:} + for k := 0 to ne - 1 do + tfmqqqq(exten[k]) {:1140}; {1141:} + for k := 1 to np do + if k = 1 then + if abs(param[1]) < 134217728 then + bwrite4bytes(tfmfile, param[1] * 16) + else begin + tfmchanged := tfmchanged + 1; + if param[1] > 0 then + bwrite4bytes(tfmfile, 2147483647) + else + bwrite4bytes(tfmfile, -2147483647) + end + else + bwrite4bytes(tfmfile, dimenout(param[k])); + if tfmchanged > 0 then begin + if tfmchanged = 1 then + printnl(904) + else begin + printnl(40); + printint(tfmchanged); + print(905) + end; + print(906) + end {:1141}; +{if internal[12]>0 then[1136:]begin writeln(logfile,' '); +writeln(logfile,'(You used ',nw:1,'w,',nh:1,'h,',nd:1,'d,',ni:1,'i,',nl: +1,'l,',nk:1,'k,',ne:1,'e,',np:1,'p metric file positions'); +writeln(logfile,' out of ','256w,16h,16d,64i,',ligtablesize:1, +'l,256k,256e,',maxfontdimen:1,'p)');end[:1136];} + printnl(903); + print(metricfilename); + bclose(tfmfile) {:1134} + end; + if gfprevptr > 0 then begin {1182:} + begin + gfbuf[gfptr] := 248; + gfptr := gfptr + 1; + if gfptr = gflimit then + gfswap + end; + gffour(gfprevptr); + gfprevptr := (gfoffset + gfptr) - 5; + gffour(internal[26] * 16); + for k := 1 to 4 do begin + gfbuf[gfptr] := headerbyte[k]; + gfptr := gfptr + 1; + if gfptr = gflimit then + gfswap + end; + gffour(internal[27]); + gffour(internal[28]); + gffour(gfminm); + gffour(gfmaxm); + gffour(gfminn); + gffour(gfmaxn); + for k := 0 to 255 do + if charexists[k] then begin + x := gfdx[k] div 65536; + if (((gfdy[k] = 0) and (x >= 0)) and (x < 256)) and (gfdx[k] = (x * 65536)) then begin + begin + gfbuf[gfptr] := 246; + gfptr := gfptr + 1; + if gfptr = gflimit then + gfswap + end; + begin + gfbuf[gfptr] := k; + gfptr := gfptr + 1; + if gfptr = gflimit then + gfswap + end; + begin + gfbuf[gfptr] := x; + gfptr := gfptr + 1; + if gfptr = gflimit then + gfswap + end + end else begin + begin + gfbuf[gfptr] := 245; + gfptr := gfptr + 1; + if gfptr = gflimit then + gfswap + end; + begin + gfbuf[gfptr] := k; + gfptr := gfptr + 1; + if gfptr = gflimit then + gfswap + end; + gffour(gfdx[k]); + gffour(gfdy[k]) + end; + x := mem[tfmwidth[k] + 1].int; + if abs(x) > maxtfmdimen then + if x > 0 then + x := 16777215 + else + x := -16777215 + else + x := makescaled(x * 16, internal[26]); + gffour(x); + gffour(charptr[k]) + end; + begin + gfbuf[gfptr] := 249; + gfptr := gfptr + 1; + if gfptr = gflimit then + gfswap + end; + gffour(gfprevptr); + begin + gfbuf[gfptr] := 131; + gfptr := gfptr + 1; + if gfptr = gflimit then + gfswap + end; + k := 4 + ((gfbufsize - gfptr) mod 4); + while k > 0 do begin + begin + gfbuf[gfptr] := 223; + gfptr := gfptr + 1; + if gfptr = gflimit then + gfswap + end; + k := k - 1 + end; {1156:} + if gflimit = halfbuf then + bwritebuf(gffile, gfbuf, halfbuf, gfbufsize - 1); + if gfptr > 0 then + bwritebuf(gffile, gfbuf, 0, gfptr - 1) {:1156}; + printnl(917); + print(outputfilename); + print(425); + printint(totalchars); + print(918); + if totalchars <> 1 then + printchar(115); + print(919); + printint(gfoffset + gfptr); + print(920); + bclose(gffile) + end {:1182} + end {:1206}; + if jobname > 0 then begin + writeln(logfile); + aclose(logfile); + selector := selector - 2; + if selector = 1 then begin + printnl(929); + print(logname); + printchar(46) + end + end; + println; + if (editnamestart <> 0) and (interaction > 0) then + calledit(strpool[editnamestart], editnamelength, editline) + end; {:1205} {1209:} + + procedure finalcleanup; + label + 10; + var + c: smallnumber; + begin + c := curmod; + if jobname = 0 then + openlogfile; + while condptr <> (-30000) do begin + printnl(930); + printcmdmod(2, curif); + if ifline <> 0 then begin + print(931); + printint(ifline) + end; + print(932); + ifline := mem[condptr + 1].int; + curif := mem[condptr].hh.b1; + condptr := mem[condptr].hh.rh + end; + if history <> 0 then + if (history = 1) or (interaction < 3) then + if selector = 3 then begin + selector := 1; + printnl(933); + selector := 3 + end; + if c = 1 then begin {storebasefile;goto 10;} + printnl(934); + goto 10 + end; + 10: + + end; {:1209} {1210:} + {procedure initprim;begin[192:]primitive(280,40,1); + primitive(281,40,2);primitive(282,40,3);primitive(283,40,4); + primitive(284,40,5);primitive(285,40,6);primitive(286,40,7); + primitive(287,40,8);primitive(288,40,9);primitive(289,40,10); + primitive(290,40,11);primitive(291,40,12);primitive(292,40,13); + primitive(293,40,14);primitive(294,40,15);primitive(295,40,16); + primitive(296,40,17);primitive(297,40,18);primitive(298,40,19); + primitive(299,40,20);primitive(300,40,21);primitive(301,40,22); + primitive(302,40,23);primitive(303,40,24);primitive(304,40,25); + primitive(305,40,26);primitive(306,40,27);primitive(307,40,28); + primitive(308,40,29);primitive(309,40,30);primitive(310,40,31); + primitive(311,40,32);primitive(312,40,33);primitive(313,40,34); + primitive(314,40,35);primitive(315,40,36);primitive(316,40,37); + primitive(317,40,38);primitive(318,40,39);primitive(319,40,40); + [:192][211:]primitive(279,47,0);primitive(91,63,0); + eqtb[2232]:=eqtb[cursym];primitive(93,64,0);primitive(125,65,0); + primitive(123,46,0);primitive(58,78,0);eqtb[2234]:=eqtb[cursym]; + primitive(329,77,0);primitive(44,79,0);primitive(59,80,0); + eqtb[2235]:=eqtb[cursym];primitive(92,7,0);primitive(330,18,0); + primitive(331,72,0);primitive(332,59,0);primitive(333,32,0); + bgloc:=cursym;primitive(334,57,0);primitive(335,19,0); + primitive(336,60,0);primitive(337,27,0);primitive(338,11,0); + primitive(323,81,0);eqtb[2239]:=eqtb[cursym];egloc:=cursym; + primitive(339,26,0);primitive(340,6,0);primitive(341,9,0); + primitive(342,70,0);primitive(343,73,0);primitive(344,13,0); + primitive(345,14,0);primitive(346,15,0);primitive(347,69,0); + primitive(348,28,0);primitive(349,24,0);primitive(350,12,0); + primitive(351,8,0);primitive(352,17,0);primitive(353,74,0); + primitive(354,35,0);primitive(355,58,0);primitive(356,71,0); + primitive(357,75,0);[:211][683:]primitive(520,16,1);primitive(521,16,2); + primitive(522,16,53);primitive(523,16,44);primitive(524,16,49); + primitive(324,16,0);eqtb[2237]:=eqtb[cursym];primitive(525,4,2242); + primitive(526,4,2392);primitive(527,4,1);primitive(325,4,0); + eqtb[2236]:=eqtb[cursym];[:683][688:]primitive(528,61,0); + primitive(529,61,1);primitive(64,61,2);primitive(530,61,3); + [:688][695:]primitive(541,56,2242);primitive(542,56,2392); + primitive(543,56,2542);primitive(544,56,1);primitive(545,56,2); + primitive(546,56,3);[:695][709:]primitive(556,3,0);primitive(482,3,1); + [:709][740:]primitive(583,1,1);primitive(322,2,2); + eqtb[2238]:=eqtb[cursym];primitive(584,2,3);primitive(585,2,4); + [:740][893:]primitive(218,33,30);primitive(219,33,31); + primitive(220,33,32);primitive(221,33,33);primitive(222,33,34); + primitive(223,33,35);primitive(224,33,36);primitive(225,33,37); + primitive(226,34,38);primitive(227,34,39);primitive(228,34,40); + primitive(229,34,41);primitive(230,34,42);primitive(231,34,43); + primitive(232,34,44);primitive(233,34,45);primitive(234,34,46); + primitive(235,34,47);primitive(236,34,48);primitive(237,34,49); + primitive(238,34,50);primitive(239,34,51);primitive(240,34,52); + primitive(241,34,53);primitive(242,34,54);primitive(243,34,55); + primitive(244,34,56);primitive(245,34,57);primitive(246,34,58); + primitive(247,34,59);primitive(248,34,60);primitive(249,34,61); + primitive(250,34,62);primitive(251,34,63);primitive(252,34,64); + primitive(253,34,65);primitive(254,34,66);primitive(255,34,67); + primitive(256,36,68);primitive(43,43,69);primitive(45,43,70); + primitive(42,55,71);primitive(47,54,72);eqtb[2233]:=eqtb[cursym]; + primitive(257,45,73);primitive(181,45,74);primitive(259,52,76); + primitive(258,45,75);primitive(60,50,77);primitive(260,50,78); + primitive(62,50,79);primitive(261,50,80);primitive(61,51,81); + primitive(262,50,82);primitive(272,37,94);primitive(273,37,95); + primitive(274,37,96);primitive(275,37,97);primitive(276,37,98); + primitive(277,37,99);primitive(278,37,100);primitive(38,48,83); + primitive(263,55,84);primitive(264,55,85);primitive(265,55,86); + primitive(266,55,87);primitive(267,55,88);primitive(268,55,89); + primitive(269,55,90);primitive(270,55,91);primitive(271,45,92); + [:893][1013:]primitive(211,30,15);primitive(197,30,4); + primitive(195,30,2);primitive(202,30,9);primitive(199,30,6); + primitive(204,30,11);primitive(206,30,13);primitive(207,30,14); + [:1013][1018:]primitive(776,82,0);primitive(777,82,1); + [:1018][1024:]primitive(143,23,0);primitive(144,23,1); + primitive(145,23,2);primitive(783,23,3); + [:1024][1027:]primitive(784,21,0);primitive(785,21,1); + [:1027][1037:]primitive(799,22,0);primitive(800,22,1); + primitive(801,22,2);primitive(802,22,3);primitive(803,22,4); + [:1037][1052:]primitive(820,68,1);primitive(821,68,0); + primitive(822,68,2);primitive(823,66,6);primitive(824,66,16); + primitive(825,67,0);primitive(826,67,1); + [:1052][1079:]primitive(856,25,0);primitive(857,25,1); + primitive(858,25,2);[:1079][1101:]primitive(868,20,0); + primitive(869,20,1);primitive(870,20,2);primitive(871,20,3); + primitive(872,20,4);[:1101][1109:]primitive(889,76,0); + primitive(890,76,128);[:1109][1176:]primitive(912,29,4); + primitive(913,29,16);[:1176];end;procedure inittab;var k:integer; + begin[176:]rover:=-29977;mem[rover].hh.rh:=32767;mem[rover].hh.lh:=1000; + mem[rover+1].hh.lh:=rover;mem[rover+1].hh.rh:=rover; + lomemmax:=rover+1000;mem[lomemmax].hh.rh:=-30000; + mem[lomemmax].hh.lh:=-30000; + for k:=29998 to 30000 do mem[k]:=mem[lomemmax];avail:=-30000; + memend:=30000;himemmin:=29998;varused:=23;dynused:=-1; + [:176][193:]intname[1]:=280;intname[2]:=281;intname[3]:=282; + intname[4]:=283;intname[5]:=284;intname[6]:=285;intname[7]:=286; + intname[8]:=287;intname[9]:=288;intname[10]:=289;intname[11]:=290; + intname[12]:=291;intname[13]:=292;intname[14]:=293;intname[15]:=294; + intname[16]:=295;intname[17]:=296;intname[18]:=297;intname[19]:=298; + intname[20]:=299;intname[21]:=300;intname[22]:=301;intname[23]:=302; + intname[24]:=303;intname[25]:=304;intname[26]:=305;intname[27]:=306; + intname[28]:=307;intname[29]:=308;intname[30]:=309;intname[31]:=310; + intname[32]:=311;intname[33]:=312;intname[34]:=313;intname[35]:=314; + intname[36]:=315;intname[37]:=316;intname[38]:=317;intname[39]:=318; + intname[40]:=319;[:193][203:]hashused:=2229;stcount:=0; + hash[2240].rh:=321;hash[2238].rh:=322;hash[2239].rh:=323; + hash[2237].rh:=324;hash[2236].rh:=325;hash[2235].rh:=59; + hash[2234].rh:=58;hash[2233].rh:=47;hash[2232].rh:=91;hash[2231].rh:=41; + hash[2229].rh:=326;eqtb[2231].lh:=62; + [:203][229:]mem[-29981].hh.lh:=2242;mem[-29981].hh.rh:=-30000; + [:229][324:]mem[30000].hh.lh:=32767; + [:324][475:]mem[-29997].hh.lh:=-30000;mem[-29997].hh.rh:=-30000; + mem[-29996].hh.lh:=1;mem[-29996].hh.rh:=-30000; + for k:=-29995 to-29989 do mem[k]:=mem[-29996];mem[-29988].int:=0; + mem[-30000].hh.rh:=-30000;mem[-30000].hh.lh:=-30000;mem[-29999].int:=0; + mem[-29998].int:=0;[:475][587:]serialno:=0;mem[-29987].hh.rh:=-29987; + mem[-29986].hh.lh:=-29987;mem[-29987].hh.lh:=-30000; + mem[-29986].hh.rh:=-30000;[:587][702:]mem[-29979].hh.b1:=0; + mem[-29979].hh.rh:=2240;eqtb[2240].rh:=-29979;eqtb[2240].lh:=41; + [:702][759:]eqtb[2230].lh:=88;hash[2230].rh:=600; + [:759][911:]mem[-29983].hh.b1:=11; + [:911][1116:]mem[-29980].int:=1073741824; + [:1116][1127:]mem[-29984].int:=0;mem[-29985].hh.lh:=0; + [:1127][1185:]baseident:=921;[:1185]end;} +{:1210} +{1212:} +{procedure debughelp;label 888,10;var k,l,m,n:integer; +begin while true do begin;printnl(935);flush(output);read(input,m); +if m<0 then goto 10 else if m=0 then begin goto 888; +888:m:=0; +['BREAKPOINT'] +end else begin read(input,n);case m of[1213:]1:printword(mem[n]); +2:printint(mem[n].hh.lh);3:printint(mem[n].hh.rh); +4:begin printint(eqtb[n].lh);printchar(58);printint(eqtb[n].rh);end; +5:printvariablename(n);6:printint(internal[n]);7:doshowdependencies; +9:showtokenlist(n,-30000,100000,0);10:print(n);11:checkmem(n>0); +12:searchmem(n);13:begin read(input,l);printcmdmod(n,l);end; +14:for k:=0 to n do print(buffer[k]);15:panicking:=not panicking; +[:1213]others:print(63)end;end;end;10:end;} +{:1212} +{:1202} +{1204:} + +begin +{-----------------------------------} + init_ps(psfile); +{-----------------------------------} + history := 3; + setpaths; + if readyalready = 314159 then + goto 1; {14:} + bad := 0; + if (halferrorline < 30) or (halferrorline > (errorline - 15)) then + bad := 1; + if maxprintline < 60 then + bad := 2; + if (gfbufsize mod 8) <> 0 then + bad := 3; + if (-28900) > 30000 then + bad := 4; + if 1777 > 2100 then + bad := 5; + if (headersize mod 4) <> 0 then + bad := 6; {:14} {154:} +{if memmax<>30000 then bad:=10;} + if memmax < 30000 then + bad := 10; + if ((-128) > 0) or (127 < 127) then + bad := 11; + if ((-32768) > 0) or (32767 < 32767) then + bad := 12; + if ((-128) < (-32768)) or (127 > 32767) then + bad := 13; + if ((-30000) < (-32768)) or (memmax >= 32767) then + bad := 14; + if maxstrings > 32767 then + bad := 15; + if bufsize > 32767 then + bad := 16; + if (255 < 255) or (65535 < 65535) then + bad := 17; {:154} {204:} + if (2241 + maxinternal) > 32767 then + bad := 21; {:204} {214:} + if 2692 > 32767 then + bad := 22; {:214} {310:} + if (15 * 11) > bistacksize then + bad := 31; {:310} {553:} + if (20 + (17 * 45)) > bistacksize then + bad := 32; {:553} {777:} + if 10 > filenamesize then + bad := 41; {:777} + if bad > 0 then begin + writeln(output, 'Ouch---my internal constants have been clobbered!', '---case ', bad: 1); + {if not getstringsstarted then goto 9999; + inittab;initprim;} + goto 9999 + end; + initialize; + readyalready := 314159; +1: {55:} + selector := 1; + tally := 0; + termoffset := 0; + fileoffset := 0; {:55} {61:} + write(output, 'This is METAFONT, Version 1.0 for Berkeley UNIX'); + {-----------------------------------------------------------------} + writeln(output); + writeln(output,'*** embedded METAFONT to PostScript Compiler ***'); + {-----------------------------------------------------------------} + if baseident = 0 then + writeln(output, ' (no base preloaded)') + else begin + print(baseident); + println + end; + flush(output); {:61} {783:} + jobname := 0; {:783} +{792:} + outputfilename := 0; {:792} {1211:} {657:} + begin + begin + inputptr := 0; + maxinstack := 0; + inopen := 0; + maxbufstack := 0; + paramptr := 0; + maxparamstack := 0; + first := 1; + curinput.startfield := 1; + curinput.indexfield := 0; + line := 0; + curinput.namefield := 0; + forceeof := false; + if not initterminal then + goto 9999; + curinput.limitfield := last; + first := last + 1 + end; {:657} {660:} + scannerstatus := 0; {:660} + if (baseident = 0) or (buffer[curinput.locfield] = 38) then begin + if baseident <> 0 then + initialize; + if not openbasefile then + goto 9999; + if not loadbasefile then begin + wclose(basefile); + goto 9999 + end; + wclose(basefile); + while (curinput.locfield < curinput.limitfield) and (buffer[curinput.locfield] = 32) do + curinput.locfield := curinput.locfield + 1 + end; + buffer[curinput.limitfield] := 37; + fixdateandtime; + initrandoms((internal[17] div 65536) + internal[16]); {70:} + if interaction = 0 then + selector := 0 + else + selector := 1 {:70}; + if curinput.locfield < curinput.limitfield then + if buffer[curinput.locfield] <> 92 then + startinput + end {:1211}; + initstrptr := strptr; + initpoolptr := poolptr; + maxstrptr := strptr; + maxpoolptr := poolptr; + history := 0; + if startsym > 0 then begin + cursym := startsym; + backinput + end; + maincontrol; + finalcleanup; +9998: + closefilesandtermina; +9999: + readyalready := 0; +{---------------------------------} +tini_ps(g); +{---------------------------------} + if (history <> 0) and (history <> 1) then + exit(1) + else + exit(0); +end. {:1204} + diff --git a/MultiSource/Benchmarks/MallocBench/p2c/INPUT/ptc.p b/MultiSource/Benchmarks/MallocBench/p2c/INPUT/ptc.p new file mode 100644 index 00000000..5af0da90 --- /dev/null +++ b/MultiSource/Benchmarks/MallocBench/p2c/INPUT/ptc.p @@ -0,0 +1,9736 @@ +(***************************************************************************) +(***************************************************************************) +(** **) +(** Copyright (C) 1987 by Per Bergsten, Gothenburg, Sweden **) +(** **) +(** No part of this program, or parts derived from this program, **) +(** may be sold, hired or otherwise exploited without the author's **) +(** written consent. **) +(** **) +(** The program may be freely redistributed provided that: **) +(** **) +(** 1) the original program text, including this notice, **) +(** is reproduced unaltered, **) +(** 2) no charge (other than a nominal media cost) is **) +(** demanded for the copy. **) +(** **) +(** The program may be included in a package only on the condition **) +(** that the package as a whole is distributed at media cost. **) +(** **) +(***************************************************************************) +(***************************************************************************) +(** **) +(** The program ptc is a Pascal-to-C translator. **) +(** It accepts a correct Pascal program and creates a C program **) +(** with the same behaviour. It is not a complete compiler in the **) +(** sense that it does NOT do complete typechecking or error- **) +(** reporting. Only a minimal typecheck is done so that the meaning **) +(** of each construct can be determined. Therefore, an incorrect **) +(** Pascal program can easily cause the translator to malfunction. **) +(** **) +(***************************************************************************) +(***************************************************************************) +(** **) +(** Things which are known to be dependent on the underlying cha- **) +(** racterset are marked with a comment containing the word CHAR. **) +(** Things that are known to be dependent on the host operating **) +(** system are marked with a comment containing the word OS. **) +(** Things known to be dependent on the cpu and/or the target C- **) +(** implementation are marked with the word CPU. **) +(** Things dependent on the target C-library are marked with LIB. **) +(** **) +(** The code generated by the translator assumes that there is a **) +(** C-implementation with at least a reasonable <stdio> library **) +(** since all input/output is implemented in terms of C functions **) +(** like fprintf(), getc(), fopen(), rewind() etc. **) +(** If the source-program uses Pascal functions like sin(), sqrt() **) +(** etc, there must also exist such functions in the C-library. **) +(** **) +(***************************************************************************) +(***************************************************************************) + +program ptc(input, output); + +label 9999; (* end of program *) + +const version = '@(#)ptc.p 1.5 Date 87/05/01'; + + keytablen = 38; (* nr of keywords *) + keywordlen = 10; (* length of a keyword *) + othersym = 'otherwise '; (* keyword for others *) + externsym = 'external '; (* keyword for external *) + dummysym = ' '; (* dummy keyword *) + + (* a Pascal set is implemented as an array of "wordtype" where *) + (* each element contains bits numbered from 0 to "setbits" *) + wordtype = 'unsigned short'; (* CPU *) + setbits = 15; (* CPU *) + + (* a Pascal file is implemented as a struct which (among other *) + (* things) contain a flag-field, currently 3 bits are used *) + filebits = 'unsigned short'; (* flags for files *) + filefill = 12; (* 16 less used 3 bits *) + + maxsetrange = 15; (* nr of words in a set *) + scalbase = 0; (* ordinal value of first scalar member *) + + maxprio = 7; + + maxmachdefs = 8; (* max nr of machine integer types *) + machdeflen = 16; (* max length of machine int type name *) + + (* limit of identifier table, identifiers and strings are saved *) + (* in an array 0 .. maxblkcnt of ^ array 0 .. maxstrblk of char *) + maxstrblk = 1023; + maxblkcnt = 63; + maxstrstor = 65535; (* maxstrstor should be == + (maxblkcnt+1) * (maxstrblk+1) - 1 *) + + maxtoknlen = 127; (* max size of token (i.e. identifier, + string or number); must be > keywordlen + and should be <= 256, see hashtokn() *) + + hashmax = 64; (* size of hashtable - 1 *) + + null = 0; (* "impossible" character value, CHAR; + a char with this value is used as delimiter + of strings in "strstor" and in toknbuffers; + it is also used as end-of-input marker by + the input procedures in lexical analysis *) + + minchar = null; + maxchar = 127; (* greatest possible character, CHAR; limits + the number of elements in type "char" *) + + (* tmpfilename is used in the generated code to obtain names of + temporary files for reset/rewrite, the last character is supplied + by the reset/rewrite routine *) + tmpfilename = '"/tmp/ptc%d%c", getpid(), '; (* OS *) + + (* some frequently used characters *) + space = ' '; + tab1 = ' '; + tab2 = ' '; + tab3 = ' '; + tab4 = ' '; + bslash = '\'; + nlchr = '''\n'''; + ffchr = '''\f'''; + nulchr = '''\0'''; + spchr = ''' '''; + quote = ''''; + cite = '"'; + xpnent = 'e'; (* exponent char in output. CPU *) + percent = '%'; + uscore = '_'; + badchr = '?'; (* CHAR *) + okchr = quote; (* CHAR *) + + tabwidth = 8; (* width of a tab-stop. OS *) + + echo = false; (* echo input as read *) + diffcomm = false; (* comment delimiters different *) + lazyfor = false; (* compile for-stmts a la C *) + unionnew = true; (* malloc unions for variants *) + + inttyp = 'int'; (* for predefined functions *) + chartyp = 'char'; + setwtyp = 'setword'; + setptyp = 'setptr'; + floattyp = 'float'; + doubletyp = 'double'; + dblcast = '(double)'; (* for predefined functions *) + + realtyp = doubletyp; (* user real-vars and functions *) + + voidtyp = 'void'; (* for procedures *) + voidcast = '(void)'; + + intlen = 10; (* length of written integer *) + fixlen = 20; (* length of written real *) + +type + hashtyp = 0 .. hashmax; (* index to hash-tables *) + + strindx = 0 .. maxstrstor; (* index to "strstor" *) + + (* string-table "strstor" is implemented as an array that is grown + dynamically by adding blocks when needed *) + strbidx = 0 .. maxstrblk; + strblk = array [ strbidx ] of char; + strptr = ^ strblk; + strbcnt = 0 .. maxblkcnt; + + (* table for stored identifiers *) + (* an identifier in any scope is represented by an idnode which is + hooked to a slot in "idtab" as determined by a hash-function. + whenever the input procedures find an identifier its idnode is + immediately located, or created, if none was found; the identifier + is then always handled though a pointer to the idnode. the actual + text of the identifier is stored in "strstor". *) + idptr = ^ idnode; + idnode = record + inext : idptr; (* chain of idnode's *) + inref : 0 .. 127; (* # of refs to this id *) + ihash : hashtyp; (* its hash value *) + istr : strindx; (* index to "strstor" *) + end; + + (* toknbuf is used to handle identifiers and strings in those situations + where the actual text is of intrest *) + toknidx = 1 .. maxtoknlen; + toknbuf = array [ toknidx ] of char; + + (* a type to hold Pascal keywords *) + keyword = packed array [ 1 .. keywordlen ] of char; + + (* predefined identifier enumeration *) + predefs = ( + dabs, darctan, dargc, dargv, + dboolean, dchar, dchr, dclose, + dcos, ddispose, deof, deoln, + dexit, dexp, dfalse, dflush, + dget, dhalt, dinput, dinteger, + dln, dmaxint, dmessage, dnew, + dodd, dord, doutput, dpage, + dpack, dpred, dput, dread, + dreadln, dreal, dreset, drewrite, + dround, dsin, dsqr, dsqrt, + dsucc, dtext, dtrue, dtrunc, + dtan, dwrite, dwriteln, dunpack, + dzinit, dztring + ); + + (* lexical symbol enumeration *) + symtyp = ( + (* keywords and eof are sorted alphabetically ...... *) + sand, sarray, sbegin, scase, + sconst, sdiv, sdo, sdownto, + selse, send, sextern, sfile, + sfor, sforward, sfunc, sgoto, + sif, sinn, slabel, smod, + snil, snot, sof, sor, + sother, spacked, sproc, spgm, + srecord, srepeat, sset, sthen, + sto, stype, suntil, svar, + swhile, swith, seof, + (* ...... sorted *) + sinteger, + sreal, sstring, schar, sid, + splus, sminus, smul, squot, + sarrow, slpar, srpar, slbrack, + srbrack, seq, sne, slt, + sle, sgt, sge, scomma, + scolon, ssemic, sassign, sdotdot, + sdot + ); + symset = set of symtyp; + + (* lexical symbol definition *) + (* the lexical symbol holds a descriptor and the value of a symbol + read by the input procedures; note that real values are represented + as strings saved in "strstor" like ordinary strings to avoid using + float-variables and float-arithmetic in the translator *) + lexsym = + record + case st : symtyp of + sid: (vid : idptr); + schar: (vchr : char); + sinteger: (vint : integer); + sreal: (vflt : strindx); + sstring: (vstr : strindx); + end; + + (* enumeration of symnode variants *) + ltypes = ( + lpredef, lidentifier, lfield, lforward, + lpointer, lstring, llabel, lforwlab, + linteger, lreal, lcharacter + ); + + declptr = ^ declnode; + treeptr = ^ treenode; + symptr = ^ symnode; + (* identifier/literal symbol definition *) + (* in a given scope an identifier or a label is uniquely represented + by a "symnode"; in order to have a uniform treatment of all objects + occurring in the same syntactical positions (and hence in the parse- + tree) the literal constants are represented in a similar manner *) + symnode = + record + lsymdecl : treeptr; (* symbol decl. point *) + lnext : symptr; (* symtab chain pointer *) + ldecl : declptr; (* backptr to symtab *) + case lt : ltypes of + lpredef, (* a predefined id *) + lfield, (* a record field *) + lpointer, (* a pointer id *) + lidentifier, (* an identifier *) + lforward: + ( + lid : idptr; (* ptr to its idnode *) + lused : boolean (* true if symbol used *) + ); + lstring: (* a string literal *) + ( + lstr : strindx (* index to "strstor" *) + ); + lreal: (* a real literal *) + ( + lfloat : strindx (* index to "strstor" *) + ); + lforwlab, (* a declared label *) + llabel: (* label decl & defined *) + ( + lno : integer; (* label number *) + lgo : boolean (* non-local usage *) + ); + linteger: (* an integer literal *) + ( + linum : integer (* its value *) + ); + lcharacter: (* a character literal *) + ( + lchar : char (* its value *) + ) + end; + + (* symbol table definition *) + (* the symbol table consists of symnodes chained along the lnext + field; the nodes are connected in reverse order of occurence (last + declared, first in chain) in the slot in the declnode determined + by the hashfunction; when a new scope is entered a new declnode is + manufactured and the previous one is hooked to the dprev field, thus + nested scopes are represented by a list of declnodes *) + declnode = record + dprev : declptr; + ddecl : array [ hashtyp ] of symptr + end; + + (* enumeration of nodes in parse tree *) + (* NOTE: the subrange [ assignment .. nil ] have priorities *) + treetyp = ( + npredef, npgm, nfunc, nproc, + nlabel, nconst, ntype, nvar, + nvalpar, nvarpar, nparproc, nparfunc, + nsubrange, nvariant, nfield, nrecord, + narray, nconfarr, nfileof, nsetof, + nbegin, nptr, nscalar, nif, + nwhile, nrepeat, nfor, ncase, + nchoise, ngoto, nwith, nwithvar, + nempty, nlabstmt, nassign, nformat, + nin, neq, nne, nlt, + nle, ngt, nge, nor, + nplus, nminus, nand, nmul, + ndiv, nmod, nquot, nnot, + numinus, nuplus, nset, nrange, + nindex, nselect, nderef, ncall, + nid, nchar, ninteger, nreal, + nstring, nnil, npush, npop, + nbreak + ); + + (* enumeration of predefined types *) + pretyps = ( + tnone, tboolean, tchar, tinteger, + treal, tstring, tnil, tset, + ttext, tpoly, terror + ); + + (* enumeration of some special attributes *) + attributes = ( + anone, aregister, aextern, areference + ); + + (* parse tree definition *) + (* the sourceprogram is represented by a treestructure built from + treenodes where each node corresponds to one syntactic form from + the pascal program *) + treenode = + record + tnext, (* ptr to next node in a list *) + ttype, (* pointer to nodes type *) + tup : treeptr; (* ptr to parent node *) + case tt : treetyp of + npredef: (* predefined object decl *) + ( + tdef: (* predefined object descr. *) + predefs; + tobtyp: (* object type *) + pretyps + ); + npgm, (* program declaration *) + nproc, (* procedure declaration *) + nfunc: (* function declaration *) + ( + tsubid, (* subr. identifier (nid) *) + tsubpar, (* parameter list *) + tfuntyp, (* function type (nid) *) + tsublab, (* label decl list (nlabel) *) + tsubconst, (* const decl list (nconst) *) + tsubtype, (* type decl list (ntype) *) + tsubvar, (* var decl list (nvar) *) + tsubsub, (* subr. decl (nproc/nfunc) *) + tsubstmt: (* stmt. list (NOT nbegin) *) + treeptr; + tstat: (* static declaration level *) + integer; + tscope: (* symbol table for local id's *) + declptr + ); + nvalpar, (* value parameter declaration *) + nvarpar, (* var parameter declaration *) + nconst, (* constant declaration *) + ntype, (* type declaration *) + nfield, (* record field declaration *) + nvar: (* var declaration declaration *) + ( + tidl, (* list of declared id's (nid) *) + tbind: (* var/type-type, const-value *) + treeptr; + tattr: (* special attributes for vars *) + attributes + ); + nparproc, (* parameter procedure *) + nparfunc: (* parameter function *) + ( + tparid, (* parm proc/func id (nid) *) + tparparm, (* parm proc/func parm decl *) + tpartyp: (* parm func type (nid) *) + treeptr + ); + nptr: (* pointer constructor *) + ( + tptrid: (* referenced type (nid) *) + treeptr; + tptrflag: (* have seen node before *) + boolean + ); + nscalar: (* scalar type constructor *) + ( + tscalid: (* list of scalar ids (nid) *) + treeptr + ); + nfileof, (* file type constructor *) + nsetof: (* set type constructor *) + ( + tof: (* set/file component type *) + treeptr + ); + nsubrange: (* subrange type constructor *) + ( + tlo, thi: (* subrange limits *) + treeptr + ); + nvariant: (* record variant constructor *) + ( + tselct, (* selector list (constants) *) + tvrnt: (* variant field decl (nrecord) *) + treeptr + ); + + (* the tuid field is used to attach a name to variants since + C requires all union members to have names *) + nrecord: (* record/variant constructor *) + ( + tflist, (* fixed field list (nfield) *) + tvlist: (* variant list (nvariant) *) + treeptr; + tuid: (* variant name *) + idptr; + trscope: (* symbol table for local id's *) + declptr + ); + nconfarr: (* conformant array constructor *) + ( + tcindx, (* index declaration *) + tindtyp, (* conf. arr. index type (nid) *) + tcelem: (* array element type decl *) + treeptr; + tcuid: (* variant name *) + idptr + ); + narray: (* array type constructor *) + ( + taindx, (* index declaration *) + taelem: (* array element type decl *) + treeptr + ); + nbegin: (* begin statement *) + ( + tbegin: (* statement list *) + treeptr + ); + nlabstmt: (* labeled statement *) + ( + tlabno, (* label number (nlabel) *) + tstmt: (* statement *) + treeptr + ); + ngoto: (* goto statement *) + ( + tlabel: (* label to go to (nlabel) *) + treeptr + ); + + nassign: (* assignment statement *) + ( + tlhs, (* variable *) + trhs: (* value *) + treeptr + ); + + (* npush/npop is used in proc/func which have local variables + used in local proc/funcs; those variables are converted to + global ptrs initialized to reference the local variable *) + npush, (* init code for proc/func *) + npop: (* exit code for proc/func *) + ( + tglob, (* global identifier (nid) *) + tloc, (* local identifier (nid) *) + ttmp: (* temp store for global (nid) *) + treeptr + ); + + nbreak: + ( + tbrkid, (* for-variable *) + tbrkxp: (* value for break *) + treeptr + ); + + ncall: (* procedure/function call *) + ( + tcall, (* called identifier *) + taparm: (* actual paramters *) + treeptr + ); + nif: (* if statement *) + ( + tifxp, (* conditional expression *) + tthen, (* stmt execd if true condition *) + telse: (* stmt execd if true condition *) + treeptr + ); + nwhile: (* while statemnet *) + ( + twhixp, (* conditional expression *) + twhistmt: (* stmt execd if true condition *) + treeptr + ); + nrepeat: (* repeat statement *) + ( + treptstmt, (* statement list *) + treptxp: (* conditional expression *) + treeptr + ); + nfor: (* for statement *) + ( + tforid, (* loop control variable (nid) *) + tfrom, (* initial value *) + tto, (* final value *) + tforstmt: (* stmt execd in loop *) + treeptr; + tincr: (* to/downto flag true <==> to *) + boolean + ); + ncase: (* case statement *) + ( + tcasxp, (* selecting expression *) + tcaslst, (* list of choises *) + tcasother: (* default action *) + treeptr + ); + nchoise: (* a choise in a case-stmt *) + ( + tchocon, (* list of constants *) + tchostmt: (* execd statement *) + treeptr + ); + nwith: (* with statment *) + ( + twithvar, (* list of variables (nwithvar) *) + twithstmt: (* statement execd in new scope *) + treeptr + ); + + (* the local symbol table holds identifiers, picked from + the record fields, temporarily declared during parsing + of remainder of with-statement; these identifiers are + later converted into fields referenced through a ptr *) + nwithvar: (* variable in with statement *) + ( + texpw: (* record variable *) + treeptr; + tenv: (* symbol table for local scope *) + declptr + ); + + nindex: (* array indexing expression *) + ( + tvariable, (* indexed variable *) + toffset: (* index expression *) + treeptr + ); + nselect: (* record field selection expr *) + ( + trecord, (* record variable *) + tfield: (* selected field (nid) *) + treeptr + ); + + (* binary operators or constructors *) + nrange, (* .. (set range) *) + nformat, (* : (write format) *) + nin, (* in *) + neq, (* = *) + nne, (* <> *) + nlt, (* < *) + nle, (* <= *) + ngt, (* > *) + nge, (* >= *) + nor, (* or *) + nplus, (* + *) + nminus, (* - *) + nand, (* and *) + nmul, (* * *) + ndiv, (* div *) + nmod, (* mod *) + nquot: (* / *) + ( + texpl, (* left operand expr *) + texpr: (* right operand expr *) + treeptr + ); + + (* unary operators or constructors; note that uplus is + used to represent any parenthesized expression *) + nderef, (* ^ (ptr dereference) *) + nnot, (* not *) + nset, (* [ ] (set constr) *) + nuplus, (* + *) + numinus: (* - *) + ( + texps: (* operand expression *) + treeptr + ); + + nid, (* identifier in decl or stmt *) + nreal, (* literal real (decl or stmt) *) + ninteger, (* literal int ( - " - ) *) + nchar, (* literal char ( - " - ) *) + nstring, (* literal string ( - " - ) *) + nlabel: (* label (decl, defpt or use) *) + ( + tsym: + symptr + ); + + nnil, (* nil (pointer constant) *) + nempty: (* empty statement *) + ( ); + end; + + (* "reserved" words and standard identifiers from C, C LIB and + OS environment excluding those reserved in Pascal *) + cnames = ( + cabort, cbreak, ccontinue, cdefine, + cdefault, cdouble, cedata, cenum, + cetext, cextern, cfgetc, cfclose, + cfflush, cfloat, cfloor, cfprintf, + cfputc, cfread, cfscanf, cfwrite, + cgetc, cgetpid, cint, cinclude, + clong, clog, cmain, cmalloc, + cprintf, cpower, cputc, cread, + creturn, cregister, crewind, cscanf, + csetbits, csetword, csetptr, cshort, + csigned, csizeof, csprintf, cstdin, + cstdout, cstderr, cstrncmp, cstrncpy, + cstruct, cstatic, cswitch, ctypedef, + cundef, cungetc, cunion, cunlink, + cunsigned, cwrite + ); + + (* these are the detected errors. some are user-errors, + some are internal problems and some are host system errors *) + errors = ( + ebadsymbol, elongstring, elongtokn, erange, + emanytokn, enotdeclid, emultdeclid, enotdecllab, + emultdecllab, emuldeflab, ebadstring, enulchr, + ebadchar, eeofcmnt, eeofstr, evarpar, + enew, esetbase, esetsize, eoverflow, + etree, etag, euprconf, easgnconf, + ecmpconf, econfconf, evrntfile, evarfile, + emanymachs, ebadmach + ); + + machdefstr = packed array [ 1 .. machdeflen ] of char; + +var + usemax, (* program needs max-function *) + usejmps, (* source program uses non-local gotos *) + usecase, (* source program has case-statement *) + usesets, (* source program uses set-operations *) + useunion, + usediff, + usemksub, + useintr, + usesge, + usesle, + useseq, + usesne, + usememb, + useins, + usescpy, + usecomp, (* source program uses string-compare *) + usefopn, (* source program uses reset/rewrite *) + usescan, + usegetl, + usenilp, (* source program uses nil-pointer *) + usebool : boolean; (* source program writes boolean-values *) + + top : treeptr; (* top of parsetree, result from parse *) + + setlst : treeptr; (* list of set-initializations *) + setcnt : integer; (* counter for setlst length *) + + currsym : lexsym; (* current lexical symbol *) + + keytab : array [ 0 .. keytablen ] of (* table of keywords *) + record + wrd : keyword; (* keyword text *) + sym : symtyp (* corresponding symbol *) + end; + + strstor : array [ strbcnt ] of strptr; (* store for strings *) + strfree : strindx; (* first free position *) + strleft : strbidx; (* room in last blk *) + + idtab : array [ hashtyp ] of idptr; (* hashed table of id's *) + + symtab : declptr; (* table of symbols *) + + statlvl, (* static decl. level *) + maxlevel : integer; (* - " - maximum value *) + + deftab : array [ predefs ] of treeptr; (* predefined idents. *) + defnams : array [ predefs ] of symptr; (* - " - *) + typnods : array [ pretyps ] of treeptr; (* predef. types. *) + + pprio, + cprio : array [ nassign .. nnil ] of 0 .. maxprio; + + ctable : array [ cnames ] of idptr; (* table of C-keywords *) + + nmachdefs : 0 .. maxmachdefs; + machdefs : array [ 1 .. maxmachdefs ] of (* table of C-types *) + record + lolim, hilim : integer; + typstr : strindx + end; + + lineno, (* input line number *) + colno, (* input column number *) + lastcol, (* last OK input column *) + lastline : integer; (* last OK input line *) + + lasttok : toknbuf; (* last input token *) + + varno : integer; (* counter for unique id's *) + + hexdig : packed array [ 0 .. 15 ] of char; + +(* Prtmsg produces an error message. It asssumes that procedure *) +(* "message" (predefined) will "writeln" to user tty. OS *) +procedure prtmsg(m : errors); + +const user = 'Error: '; + restr = 'Implementation restriction: '; + inter = '* Internal error * '; + xtoklen = 64; (* should be <= maxtoklen *) + +var i : toknidx; + xtok : packed array [ 1 .. xtoklen ] of char; + +begin + case m of + ebadsymbol: + message(user, 'Unexpected symbol'); + ebadchar: + message(user, 'Bad character'); + elongstring: + message(restr, 'Too long string'); + ebadstring: + message(user, 'Newline in string or character'); + eeofstr: + message(user, 'End of file in string or character'); + eeofcmnt: + message(user, 'End of file in comment'); + elongtokn: + message(restr, 'Too long identfier'); + emanytokn: + message(restr, 'Too many strings, identifiers or real numbers'); + enotdeclid: + message(user, 'Identifier not declared'); + emultdeclid: + message(user, 'Identifier declared twice'); + enotdecllab: + message(user, 'Label not declared'); + emultdecllab: + message(user, 'Label declared twice'); + emuldeflab: + message(user, 'Label defined twice'); + evarpar: + message(user, 'Actual parameter not a variable'); + enulchr: + message(restr, 'Cannot handle nul-character in strings'); + enew: + message(restr, 'New returned a nil-pointer'); + eoverflow: + message(restr, 'Token buffer overflowed'); + esetbase: + message(restr, 'Cannot handle sets with base >> 0'); + esetsize: + message(restr, 'Cannot handle sets with very large range'); + etree: + message(inter, 'Bad tree structure'); + etag: + message(inter, 'Cannot find tag'); + evrntfile: + message(restr, 'Cannot initialize files in record variants'); + evarfile: + message(restr, 'Cannot handle files in structured variables'); + euprconf: + message(inter, 'No upper bound on conformant arrays'); + easgnconf: + message(inter, 'Cannot assign conformant arrays'); + ecmpconf: + message(inter, 'Cannot compare conformant arrays'); + econfconf: + message(restr, 'Cannot handle nested conformat arrays'); + erange: + message(inter, 'Cannot find C-type for integer-subrange'); + emanymachs: + message(restr, 'Too many machine integer types'); + ebadmach: + message(inter, 'Bad name for machine integer type'); + end;(* case *) + if lastline <> 0 then + begin + (* error detected during parsing, + report line/column and print the offending symbol *) + message('Line ', lastline:1, ', col ', lastcol:1, ':'); + if m in [enulchr, ebadchar, ebadstring, ebadsymbol, + emuldeflab, emultdecllab, enotdecllab, emultdeclid, + enotdeclid, elongtokn, elongstring] then + begin + i := 1; + while (i < xtoklen) and (lasttok[i] <> chr(null)) do + begin + xtok[i] := lasttok[i]; + i := i + 1 + end; + while i < xtoklen do + begin + xtok[i] := ' '; + i := i + 1 + end; + xtok[xtoklen] := ' '; + message('Current symbol: ', xtok) + end + end +end; + +procedure fatal(m : errors); forward; +procedure error(m : errors); forward; + +(* Map letters to upper-case. *) +(* This function assumes a machine collating sequence where the *) +(* letters of either case form a contigous sequence, CHAR. *) +function uppercase(c : char) : char; + +begin + if (c >= 'a') and (c <= 'z') then + uppercase := chr(ord(c) + ord('A') - ord('a')) + else + uppercase := c +end; + + +(* Map letters to lower-case. *) +(* This function assumes a machine collating sequence where the *) +(* letters of either case form a contigous sequence, CHAR. *) +function lowercase(c : char) : char; + +begin + if (c >= 'A') and (c <= 'Z') then + lowercase := chr(ord(c) - ord('A') + ord('a')) + else + lowercase := c +end; + +(* Retrieve a string from strstor. *) +procedure gettokn(i : strindx; var t : toknbuf); + +var c : char; + k : toknidx; + j : strbidx; + p : strptr; + +begin + k := 1; + (* compute block and offset in block *) + p := strstor[i div (maxstrblk + 1)]; + j := i mod (maxstrblk + 1); + (* retrieve text up to null *) + repeat + c := p^[j]; + t[k] := c; + j := j + 1; + k := k + 1; + if k = maxtoknlen then + begin + c := chr(null); + t[maxtoknlen] := chr(null); + prtmsg(eoverflow) + end + until c = chr(null) +end; + +(* Deposit a string into strstor at a given start-position. *) +procedure puttokn(i : strindx; var t : toknbuf); + +var c : char; + k : toknidx; + j : strbidx; + p : strptr; + +begin + k := 1; + p := strstor[i div (maxstrblk + 1)]; + j := i mod (maxstrblk + 1); + repeat + c := t[k]; + p^[j] := c; + k := k + 1; + j := j + 1 + until c = chr(null) +end; + +(* Write a token on standard output. *) +procedure writetok(var w : toknbuf); + +var j : toknidx; + +begin + j := 1; + while w[j] <> chr(null) do + begin + write(w[j]); + j := j + 1 + end +end; + +(* Print a float number on standard output. *) +procedure printtok(i : strindx); + +var w : toknbuf; + +begin + gettokn(i, w); + writetok(w) +end; + +(* Print an identifier on standard output. *) +procedure printid(ip : idptr); + +begin + printtok(ip^.istr) +end; + +(* Print a character on standard output with proper C-quoting. *) +procedure printchr(c : char); + +begin + if (c = quote) or (c = bslash) then + write(quote, bslash, c, quote) + else + write(quote, c, quote) +end; + +(* Print a string on standard output with proper C-quoting. *) +procedure printstr(i : strindx); + +var k : toknidx; + c : char; + w : toknbuf; + +begin + gettokn(i, w); + write(cite); + k := 1; + while w[k] <> chr(null) do + begin + c := w[k]; + k := k + 1; + if (c = cite) or (c = bslash) then + write(bslash); + write(c) + end; + write(cite) +end; + +(* Return a pointer to the declarationpoint of an identifier. *) +function idup(ip : treeptr) : treeptr; + +begin + idup := ip^.tsym^.lsymdecl^.tup +end; + +(* Compute a hashvalue for an identifier or a string. *) +function hashtokn(var id : toknbuf) : hashtyp; + +var h : integer; + i : toknidx; + +begin + i := 1; + h := 0; + while id[i] <> chr(null) do + begin + (* if ord() of a character ranges from 0 to 127 then we can loop + 256 times without causing h to exceed 32767, this is safe as + both strings and identifiers are limited in length *) + h := h + ord(id[i]); (* CHAR, CPU *) + i := i + 1 + end; + hashtokn := h mod hashmax +end; + +(* Global string table update. *) +(* This function accepts a string and stores it in strstor. *) +(* It returns the id-number for the new string. *) +function savestr(var t : toknbuf) : strindx; + +var k : toknidx; + i : strindx; + j : strbcnt; + +begin + (* find length of new string including null-char *) + k := 1; + while t[k] <> chr(null) do + k := k + 1; + if k > strleft then + begin + (* out of space in strstore *) + if strstor[maxblkcnt] <> nil then (* last slot used *) + error(emanytokn); + (* allocate a new block *) + j := (strfree + maxstrblk) div (maxstrblk + 1); + new(strstor[j]); + if strstor[j] = nil then + error(enew); + strfree := j * (maxstrblk + 1); + strleft := maxstrblk + end; + (* copy new str, update location of last used cell, + return starting location for new str *) + i := strfree; + strfree := strfree + k; + strleft := strleft - k; + puttokn(i, t); + savestr := i +end; + +(* Global id table lookup. *) +(* This procedure accepts an identifier and determines if it has *) +(* been seen before. If that is the case a pointer to its idnode *) +(* is returned, otherwise the identifier is saved and a pointer to *) +(* a new node is returned. *) +function saveid(var id : toknbuf) : idptr; + +label 999; + +var k : toknidx; + ip : idptr; + h : hashtyp; + t : toknbuf; + +begin + h := hashtokn(id); + ip := idtab[h]; (* scan hashlist for id *) + while ip <> nil do + begin + gettokn(ip^.istr, t); (* look at saved token *) + k := 1; + while id[k] = t[k] do + if id[k] = chr(null) then + goto 999 (* found it! *) + else + k := k + 1; (* look at next char *) + ip := ip^.inext + end; + + (* identifier wasn't previously seen, manufacture a new idnode, + save index to strstor and hashvalue, insert idnode in idtab *) + new(ip); + if ip = nil then + error(enew); + ip^.inref := 0; + ip^.istr := savestr(id); + ip^.ihash := h; + ip^.inext := idtab[h]; + idtab[h] := ip; + +999: + (* return the idnode *) + saveid := ip +end; + +(* This function creates a new variable by concatenating one name *) +(* with another injecting a given separator. *) +function mkconc(sep : char; p, q : idptr) : idptr; + +var w, x : toknbuf; + i, j : toknidx; + +begin + (* fetch second part and determine its length *) + gettokn(q^.istr, x); + j := 1; + while x[j] <> chr(null) do + j := j + 1; + (* fetch first part and locate its end *) + w[1] := chr(null); + if p <> nil then + gettokn(p^.istr, w); + i := 1; + while w[i] <> chr(null) do + i := i + 1; + (* check total length *) + if i + j + 2 >= maxtoknlen then + error(eoverflow); + + (* add separators *) + if sep = '>' then + begin + (* special case 1: > gives arrow: a->b *) + w[i] := '-'; + i := i + 1 + end; + if sep <> space then + begin + (* special case 2: space gives nothing: ab *) + w[i] := sep; + i := i + 1 + end; + (* add second part *) + j := 1; + repeat + w[i] := x[j]; + i := i + 1; + j := j + 1 + until w[i-1] = chr(null); + (* save new identifier *) + mkconc := saveid(w) +end; + +(* Create a new id with name-prefix from w. *) +function mkuniqname(var t : toknbuf) : idptr; + +var i : toknidx; + + procedure dig(n : integer); + begin + if n > 0 then + begin + dig(n div 10); + if i = maxtoknlen then + error(eoverflow); + t[i] := chr(n mod 10 + ord('0')); (* CHAR *) + i := i + 1 + end + end; + +begin + i := 1; + while t[i] <> chr(null) do + i := i + 1; + varno := varno + 1; + dig(varno); + t[i] := chr(null); + mkuniqname := saveid(t) +end; + +(* Make a new unique variable with given char as prefix. *) +function mkvariable(c : char) : idptr; + +var t : toknbuf; + +begin + t[1] := c; + t[2] := chr(null); + mkvariable := mkuniqname(t) +end; + +(* Make a new unique variable with given char as prefix and *) +(* with a given id as tail. Commonly used for renaming id's. *) +function mkrename(c : char; ip : idptr) : idptr; + +begin + mkrename := mkconc(uscore, mkvariable(c), ip) +end; + +(* Make a name for a variant. Variants are mapped onto C unions, *) +(* which we always give the name "U", thus the name of the variant *) +(* becomes "U.Vnnn" where "nnn" is a unique number. *) +function mkvrnt : idptr; + +var t : toknbuf; + +begin + t[1] := 'U'; + t[2] := '.'; + t[3] := 'V'; + t[4] := chr(null); + mkvrnt := mkuniqname(t) +end; + +procedure checksymbol(ss : symset); +begin + if not (currsym.st in ss) then + error(ebadsymbol); +end; + +(* Lexical analysis routine. *) +(* This procedure reads and classifies the next lexical token in *) +(* the input stream. The token is saved in the global variable *) +(* "currsym". The found symbol should be one of the symbols given *) +(* in the parameter "ss" otherwise the error routine is called. *) +procedure nextsymbol(ss : symset); + +var lastchr : 0 .. maxtoknlen; + + (* This function reads the next character from the input *) + (* and updates "lineno" and "colno" accordingly. *) + function nextchar : char; + + var c : char; + + begin + if eof then + c := chr(null) + else begin + colno := colno + 1; + if eoln then + begin + lineno := lineno + 1; + colno := 0 + end; + read(c); + if echo then + if colno = 0 then + writeln + else + write(c); + if c = tab1 then + colno := ((colno div tabwidth) + 1) * tabwidth + end; + if lastchr > 0 then + begin + lasttok[lastchr] := c; + lastchr := lastchr + 1 + end; + nextchar := c + end; + + (* This function looks at the next input character. *) + function peekchar : char; + + begin + if eof then + peekchar := chr(null) + else + peekchar := input^ + end; + + (* Read and classify the next token. *) + procedure nexttoken(realok : boolean); + + var c : char; + n : integer; + + ready : boolean; + + wl : toknidx; + wb : toknbuf; + + (* Determine if c is valid in an identifier. *) + (* This function assumes a machine collating *) + (* sequence where letters and digits form conti- *) + (* gous sequences, CHAR. *) + function idchar(c : char) : boolean; + + begin + idchar := + (c >= 'a') and (c <= 'z') or + (c >= '0') and (c <= '9') or + (c >= 'A') and (c <= 'Z') or + (c = uscore) + end; + + (* Determine if c is valid in a number. CHAR. *) + function numchar(c : char) : boolean; + + begin + numchar := (c >= '0') and (c <= '9') + end; + + (* Convert a digit to its numeric value. CHAR *) + function numval(c : char) : integer; + + begin + numval := ord(c) - ord('0') + end; + + (* Determine if the current token is a keyword. *) + function keywordcheck(var w : toknbuf; l : toknidx) : symtyp; + + var n : 1 .. keywordlen; + i, j, k : 0 .. keytablen; + wrd : keyword; + kwc : symtyp; + + begin + (* quick check on token length, + pascal keywords range from 2 to 9 chars in length *) + if (l > 1) and (l < keywordlen) then + begin + (* could be a keyword, initialize wrd *) + wrd := keytab[keytablen].wrd; + (* copy w to wrd *) + for n := 1 to l do + wrd[n] := w[n]; + + (* binary search for tokn, + relies on symtyp being sorted *) + i := 0; + j := keytablen; + while j > i do + begin + k := (i + j) div 2; + if keytab[k].wrd >= wrd then + j := k + else + i := k + 1 + end; + if keytab[j].wrd = wrd then + kwc := keytab[j].sym + else + kwc := sid + end + else + kwc := sid; + keywordcheck := kwc + end; + + begin (* nexttoken *) + (* don't save blanks/comments *) + lastchr := 0; + (* read non-blank character *) + repeat + c := nextchar; + (* skip comments, the two comment delimiters of pascal + are treated as different if "diffcomm" is true *) + if c = '{' then + begin + repeat + c := nextchar; + if diffcomm then + ready := c = '}' + else + ready := ((c = '*') and + (peekchar = ')')) + or (c = '}') + until ready or eof; + if eof and not ready then + error(eeofcmnt); + if (c = '*') and not eof then + c := nextchar; + c := space + end + else if (c = '(') and (peekchar = '*') then + begin + c := nextchar; + repeat + c := nextchar; + if diffcomm then + ready := (c = '*') and + (peekchar = ')') + else + ready := ((c = '*') and + (peekchar = ')')) + or (c = '}') + until ready or eof; + if eof and not ready then + error(eeofcmnt); + if (c = '*') and not eof then + c := nextchar; + c := space + end + until (c <> space) and (c <> tab1); + + (* save characters from this token and save line- and column- + numbers for errormessages *) + lasttok[1] := c; + lastchr := 2; + lastcol := colno; + lastline := lineno; + + (* map all CHAR control characters onto "badchr" *) + if c < okchr then + c := badchr; + + (* decode symbol *) + with currsym do + if eof then + begin + lasttok[1] := '*'; + lasttok[2] := 'E'; + lasttok[3] := 'O'; + lasttok[4] := 'F'; + lasttok[5] := '*'; + lastchr := 6; + st := seof + end + else + case c of + + + (* CHAR, chars not in Pascal *) + '|', '`', '~', '}', + bslash, uscore, badchr: + error(ebadchar); + + (* identifiers or keywords *) + 'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', + 'k', 'l', 'm', 'n', 'o', 'p', 'q', 'r', 's', 't', + 'u', 'v', 'w', 'x', 'y', 'z', + 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', + 'K', 'L', 'M', 'N', 'O', 'P', 'Q', 'R', 'S', 'T', + 'U', 'V', 'W', 'X', 'Y', 'Z': + begin + (* read token into buffer *) + wb[1] := lowercase(c); + wl := 2; + while (wl < maxtoknlen) and idchar(peekchar) do + begin + wb[wl] := lowercase(nextchar); + wl := wl + 1 + end; + if wl >= maxtoknlen then + begin + lasttok[lastchr] := chr(null); + error(elongtokn) + end; + (* terminate token and match *) + wb[wl] := chr(null); + (* check if keyword/identifier *) + st := keywordcheck(wb, wl-1); + if st = sid then + vid := saveid(wb) + end; + + (* integer or real numbers *) + '0', '1', '2', '3', '4', '5', '6', '7' ,'8', '9': + begin + (* assume integer number, save it in buffer *) + wb[1] := c; + wl := 2; + n := numval(c); + while numchar(peekchar) do + begin + c := nextchar; + n := n * 10 + numval(c); + wb[wl] := c; + wl := wl + 1 + end; + st := sinteger; + vint := n; + if realok then + begin + (* accept real numbers *) + if peekchar = '.' then + begin + (* this is a real number *) + st := sreal; + wb[wl] := nextchar; + wl := wl + 1; + while numchar(peekchar) do + begin + wb[wl] := nextchar; + wl := wl + 1 + end + end; + c := peekchar; + if (c = 'e') or (c = 'E') then + begin + (* this is a real number *) + st := sreal; + c := nextchar; + wb[wl] := xpnent; + wl := wl + 1; + c := peekchar; + if (c = '-') or (c = '+') then + begin + wb[wl] := nextchar; + wl := wl + 1 + end; + while numchar(peekchar) do + begin + wb[wl] := nextchar; + wl := wl + 1 + end + end; + if st = sreal then + begin + wb[wl] := chr(null); + vflt := savestr(wb) + end + end + end; + + '(': + if peekchar = '.' then + begin + (* some compilers on non-ascii systems + use (. for [ and .) for ] *) + c := nextchar; + st := slbrack + end + else + st := slpar; + ')': + st := srpar; + '[': + st := slbrack; + ']': + st := srbrack; + '.': + if peekchar = '.' then + begin + c := nextchar; + st := sdotdot + end + else if peekchar = ')' then + begin + c := nextchar; + st := srbrack + end + else + st := sdot; + ';': + st := ssemic; + ':': + if peekchar = '=' then + begin + c := nextchar; + st := sassign + end + else + st := scolon; + ',': + st := scomma; + '@', + '^': + st := sarrow; + '=': + st := seq; + '<': + if peekchar = '=' then + begin + c := nextchar; + st := sle + end + else if peekchar = '>' then + begin + c := nextchar; + st := sne + end + else + st := slt; + '>': + if peekchar = '=' then + begin + c := nextchar; + st := sge + end + else + st := sgt; + '+': + st := splus; + '-': + st := sminus; + '*': + st := smul; + '/': + st := squot; + quote: + begin + (* assume the symbol is a literal string *) + wl := 0; + ready := false; + repeat + if eoln then + begin + lasttok[lastchr] := chr(null); + error(ebadstring) + end; + c := nextchar; + if c = quote then + if peekchar = quote then + c := nextchar + else + ready := true; + if c = chr(null) then + begin + if eof then + error(eeofstr); + lasttok[lastchr] := chr(null); + error(enulchr) + end; + if not ready then + begin + wl := wl + 1; + if wl >= maxtoknlen then + begin + lasttok[lastchr] := + chr(null); + error(elongstring) + end; + wb[wl] := c + end + until ready; + if wl = 1 then + begin + (* only 1 character => not a string *) + st := schar; + vchr := wb[1] + end + else begin + (* > 1 character => its a string *) + wl := wl + 1; + if wl >= maxtoknlen then + begin + lasttok[lastchr] := chr(null); + error(elongstring) + end; + wb[wl] := chr(null); + st := sstring; + vstr := savestr(wb) + end + end + + end;(* case *) + if lastchr = 0 then + lastchr := 1; + lasttok[lastchr] := chr(null) + end; (* nexttoken *) + +begin (* nextsymbol *) + nexttoken(sreal in ss); + checksymbol(ss) +end; (* nextsymbol *) + +(* Return a pointer to the node describing the type of tp. This *) +(* function also stores the result in the node for future ref. *) +function typeof(tp : treeptr) : treeptr; + +var tf, tq : treeptr; + +begin + tq := tp; + tf := tq^.ttype; + (* keep working until a type is found *) + while tf = nil do + begin + case tq^.tt of + nchar: + tf := typnods[tchar]; + + ninteger: + tf := typnods[tinteger]; + + nreal: + tf := typnods[treal]; + + nstring: + tf := typnods[tstring]; + + nnil: + tf := typnods[tnil]; + + nid: + begin + tq := idup(tq); + if tq = nil then + fatal(etree) + end; + + ntype, + nvar, + nconst, + nfield, + nvalpar, + nvarpar: + tq := tq^.tbind; + + npredef, + nptr, + nscalar, + nrecord, + nconfarr, + narray, + nfileof, + nsetof: + tf := tq; (* these nodetypes represent types *) + + nsubrange: + if tq^.tup^.tt = nconfarr then + tf := tq^.tup^.tindtyp + else + tf := tq; + + ncall: + begin + tf := typeof(tq^.tcall); + if tf = typnods[tpoly] then + tf := typeof(tq^.taparm) + end; + + nfunc: + tq := tq^.tfuntyp; + + nparfunc: + tq := tq^.tpartyp; + + nproc, + nparproc: + tf := typnods[tnone]; + + nvariant, + nlabel, + npgm, + nempty, + nbegin, + nlabstmt, + nassign, + npush, + npop, + nif, + nwhile, + nrepeat, + nfor, + ncase, + nchoise, + ngoto, + nwith, + nwithvar: + fatal(etree); + + nformat, + nrange: + tq := tq^.texpl; + + nplus, + nminus, + nmul: + begin + tf := typeof(tq^.texpl); + if tf = typnods[tinteger] then + tf := typeof(tq^.texpr) + else if tf^.tt = nsetof then + tf := typnods[tset] + end; + + numinus, + nuplus: + tq := tq^.texps; + + nmod, + ndiv: + tf := typnods[tinteger]; + + nquot: + tf := typnods[treal]; + + neq, + nne, + nlt, + nle, + ngt, + nge, + nin, + nor, + nand, + nnot: + tf := typnods[tboolean]; + + nset: + tf := typnods[tset]; + + nselect: + tq := tq^.tfield; + + nderef: + begin + tq := typeof(tq^.texps); + case tq^.tt of + nptr: + tq := tq^.tptrid; + nfileof: + tq := tq^.tof; + npredef: + tf := typnods[tchar] (* textfile *) + end (* case *) + end; + + nindex: + begin + tq := typeof(tq^.tvariable); + if tq^.tt = nconfarr then + tq := tq^.tcelem + else if tq = typnods[tstring] then + tf := typnods[tchar] + else + tq := tq^.taelem + end; + + end (* case *) + end; + if tp^.ttype = nil then + tp^.ttype := tf; (* remember type for future reference *) + typeof := tf +end; (* typeof *) + +(* Connect all nodes to their fathers. *) +procedure linkup(up, tp : treeptr); + +begin + while tp <> nil do + begin + if tp^.tup = nil then + begin + tp^.tup := up; + case tp^.tt of + npgm, + nfunc, + nproc: + begin + linkup(tp, tp^.tsubid); + linkup(tp, tp^.tsubpar); + linkup(tp, tp^.tfuntyp); + linkup(tp, tp^.tsublab); + linkup(tp, tp^.tsubconst); + linkup(tp, tp^.tsubtype); + linkup(tp, tp^.tsubvar); + linkup(tp, tp^.tsubsub); + linkup(tp, tp^.tsubstmt) + end; + + + nvalpar, + nvarpar, + nconst, + ntype, + nfield, + nvar: + begin + linkup(tp, tp^.tidl); + linkup(tp, tp^.tbind) + end; + + nparproc, + nparfunc: + begin + linkup(tp, tp^.tparid); + linkup(tp, tp^.tparparm); + linkup(tp, tp^.tpartyp) + end; + + nptr: + linkup(tp, tp^.tptrid); + nscalar: + linkup(tp, tp^.tscalid); + + nsubrange: + begin + linkup(tp, tp^.tlo); + linkup(tp, tp^.thi) + end; + nvariant: + begin + linkup(tp, tp^.tselct); + linkup(tp, tp^.tvrnt) + end; + nrecord: + begin + linkup(tp, tp^.tflist); + linkup(tp, tp^.tvlist) + end; + nconfarr: + begin + linkup(tp, tp^.tcindx); + linkup(tp, tp^.tcelem); + linkup(tp, tp^.tindtyp) + end; + narray: + begin + linkup(tp, tp^.taindx); + linkup(tp, tp^.taelem) + end; + nfileof, + nsetof: + linkup(tp, tp^.tof); + nbegin: + linkup(tp, tp^.tbegin); + nlabstmt: + begin + linkup(tp, tp^.tlabno); + linkup(tp, tp^.tstmt) + end; + nassign: + begin + linkup(tp, tp^.tlhs); + linkup(tp, tp^.trhs) + end; + npush, + npop: + begin + linkup(tp, tp^.tglob); + linkup(tp, tp^.tloc); + linkup(tp, tp^.ttmp) + end; + ncall: + begin + linkup(tp, tp^.tcall); + linkup(tp, tp^.taparm ) + end; + nif: + begin + linkup(tp, tp^.tifxp); + linkup(tp, tp^.tthen); + linkup(tp, tp^.telse) + end; + nwhile: + begin + linkup(tp, tp^.twhixp); + linkup(tp, tp^.twhistmt) + end; + nrepeat: + begin + linkup(tp, tp^.treptstmt); + linkup(tp, tp^.treptxp) + end; + nfor: + begin + linkup(tp, tp^.tforid); + linkup(tp, tp^.tfrom); + linkup(tp, tp^.tto); + linkup(tp, tp^.tforstmt) + end; + ncase: + begin + linkup(tp, tp^.tcasxp); + linkup(tp, tp^.tcaslst); + linkup(tp, tp^.tcasother) + end; + nchoise: + begin + linkup(tp, tp^.tchocon); + linkup(tp, tp^.tchostmt) + end; + nwith: + begin + linkup(tp, tp^.twithvar); + linkup(tp, tp^.twithstmt) + end; + nwithvar: + linkup(tp, tp^.texpw); + nindex: + begin + linkup(tp, tp^.tvariable); + linkup(tp, tp^.toffset) + end; + nselect: + begin + linkup(tp, tp^.trecord); + linkup(tp, tp^.tfield) + end; + + ngoto: + linkup(tp, tp^.tlabel); + + nrange, nformat, + nin, neq, + nne, nlt, nle, + ngt, nge, nor, + nplus, nminus, + nand, nmul, + ndiv, nmod, + nquot: + begin + linkup(tp, tp^.texpl); + linkup(tp, tp^.texpr) + end; + + nderef, + nnot, nset, + numinus, + nuplus: + linkup(tp, tp^.texps); + + nid, + nnil, ninteger, + nreal, nchar, + nstring, npredef, + nlabel, nempty: + (* no op *) + end (* case *) + end; + tp := tp^.tnext + end +end; (* linkup *) + +(* Allocate a new symbol node. *) +function mksym(vt : ltypes) : symptr; + +var mp : symptr; + +begin + new(mp); + if mp = nil then + error(enew); + mp^.lt := vt; + mp^.lnext := nil; + mp^.lsymdecl := nil; + mp^.ldecl := nil; + mksym := mp +end; + +(* Enter a symbol at current declarationlevel. *) +procedure declsym(sp : symptr); + +var h : hashtyp; + +begin + if sp^.lt in [lpredef, lidentifier, lfield, lforward, lpointer] then + h := sp^.lid^.ihash + else + h := hashmax; + sp^.lnext := symtab^.ddecl[h]; + symtab^.ddecl[h] := sp; + sp^.ldecl := symtab +end; + +(* Create a node of selected type. *) +function mknode(nt : treetyp) : treeptr; + +var tp : treeptr; + +begin + tp := nil; + case nt of + npredef: new(tp, npredef); + npgm: new(tp, npgm); + nfunc: new(tp, nfunc); + nproc: new(tp, nproc); + nlabel: new(tp, nlabel); + nconst: new(tp, nconst); + ntype: new(tp, ntype); + nvar: new(tp, nvar); + nvalpar: new(tp, nvalpar); + nvarpar: new(tp, nvarpar); + nparproc: new(tp, nparproc); + nparfunc: new(tp, nparfunc); + nsubrange: new(tp, nsubrange); + nvariant: new(tp, nvariant); + nfield: new(tp, nfield); + nrecord: new(tp, nrecord); + nconfarr: new(tp, nconfarr); + narray: new(tp, narray); + nfileof: new(tp, nfileof); + nsetof: new(tp, nsetof); + nbegin: new(tp, nbegin); + nptr: new(tp, nptr); + nscalar: new(tp, nscalar); + nif: new(tp, nif); + nwhile: new(tp, nwhile); + nrepeat: new(tp, nrepeat); + nfor: new(tp, nfor); + ncase: new(tp, ncase); + nchoise: new(tp, nchoise); + ngoto: new(tp, ngoto); + nwith: new(tp, nwith); + nwithvar: new(tp, nwithvar); + nempty: new(tp, nempty); + nlabstmt: new(tp, nlabstmt); + nassign: new(tp, nassign); + nformat: new(tp, nformat); + nin: new(tp, nin); + neq: new(tp, neq); + nne: new(tp, nne); + nlt: new(tp, nlt); + nle: new(tp, nle); + ngt: new(tp, ngt); + nge: new(tp, nge); + nor: new(tp, nor); + nplus: new(tp, nplus); + nminus: new(tp, nminus); + nand: new(tp, nand); + nmul: new(tp, nmul); + ndiv: new(tp, ndiv); + nmod: new(tp, nmod); + nquot: new(tp, nquot); + nnot: new(tp, nnot); + numinus: new(tp, numinus); + nuplus: new(tp, nuplus); + nset: new(tp, nset); + nrange: new(tp, nrange); + nindex: new(tp, nindex); + nselect: new(tp, nselect); + nderef: new(tp, nderef); + ncall: new(tp, ncall); + nid: new(tp, nid); + nchar: new(tp, nchar); + ninteger: new(tp, ninteger); + nreal: new(tp, nreal); + nstring: new(tp, nstring); + nnil: new(tp, nnil); + npush: new(tp, npush); + npop: new(tp, npop); + nbreak: new(tp, nbreak) + end;(* case *) + if tp = nil then + error(enew); + tp^.tt := nt; + tp^.tnext := nil; + tp^.tup := nil; + tp^.ttype := nil; + mknode := tp +end; + +(* Create a node with a literal value. *) +function mklit : treeptr; + +var sp : symptr; + tp : treeptr; + +begin + case currsym.st of + sinteger: + begin + sp := mksym(linteger); + sp^.linum := currsym.vint; + tp := mknode(ninteger); + end; + sreal: + begin + sp := mksym(lreal); + sp^.lfloat := currsym.vflt; + tp := mknode(nreal); + end; + schar: + begin + sp := mksym(lcharacter); + sp^.lchar := currsym.vchr; + tp := mknode(nchar); + end; + sstring: + begin + sp := mksym(lstring); + sp^.lstr := currsym.vstr; + tp := mknode(nstring); + end + end;(* case *) + tp^.tsym := sp; + sp^.lsymdecl := tp; + mklit := tp +end; + +(* Look up an identifier among declared symbols. *) +function lookupid(ip : idptr; fieldok : boolean) : symptr; + +label 999; + +var sp : symptr; + dp : declptr; + vs : set of ltypes; + +begin + lookupid := nil; + if fieldok then + vs := [lidentifier, lforward, lpointer, lfield] + else + vs := [lidentifier, lforward, lpointer]; + sp := nil; + + (* pick up symboltable from innermost scope *) + dp := symtab; + while dp <> nil do + begin + (* scan linked symbols with same hasvalue *) + sp := dp^.ddecl[ip^.ihash]; + while sp <> nil do + begin + (* break out when proper id found *) + if (sp^.lt in vs) and (sp^.lid = ip) then + goto 999; + sp := sp^.lnext + end; + (* proceed to enclosing scope *) + dp := dp^.dprev + end; +999: + lookupid := sp +end; + +(* Look up a label. *) +function lookuplabel(i : integer) : symptr; + +label 999; + +var sp : symptr; + dp : declptr; + +begin + sp := nil; + dp := symtab; + while dp <> nil do + begin + sp := dp^.ddecl[hashmax]; + while sp <> nil do + begin + if (sp^.lt in [lforwlab, llabel]) and (sp^.lno = i) then + goto 999; + sp := sp^.lnext + end; + dp := dp^.dprev + end; +999: + lookuplabel := sp +end; + +(* Create a new declaration level (a new scope) link declnode to *) +(* previous node. dp is non-nil when a procedure/function body *) +(* is encountered for which we have seen a forward declaration. *) +procedure enterscope(dp : declptr); + +var h : hashtyp; + +begin + if dp = nil then + begin + new(dp); + for h := 0 to hashmax do + dp^.ddecl[h] := nil + end; + dp^.dprev := symtab; + symtab := dp +end; + +(* Return current scope (as a pointer to symbol-table). *) +function currscope : declptr; + +begin + currscope := symtab +end; + +(* Drop innermost declaration scope. *) +procedure leavescope; + +begin + symtab := symtab^.dprev +end; + +(* Create a new identifier symbol. *) +function mkid(ip : idptr) : symptr; + +var sp : symptr; + +begin + sp := mksym(lidentifier); + sp^.lid := ip; + sp^.lused := false; + declsym(sp); + ip^.inref := ip^.inref + 1; + mkid := sp +end; + +(* Check that the current identifier is new then save it in the *) +(* current scope. Create and return a new node representing this *) +(* instance of the identifier. *) +function newid(ip : idptr) : treeptr; + +var sp : symptr; + tp : treeptr; + +begin + sp := lookupid(ip, false); + if sp <> nil then + if sp^.ldecl <> symtab then + sp := nil; + if sp = nil then + begin + (* new identifier *) + tp := mknode(nid); + sp := mkid(ip); + sp^.lsymdecl := tp; + tp^.tsym := sp + end + else if sp^.lt = lpointer then + begin + (* previously declared as a pointer type *) + tp := mknode(nid); + tp^.tsym := sp; + sp^.lt := lidentifier; + sp^.lsymdecl := tp + end + else if sp^.lt = lforward then + begin + (* previously forward declared *) + sp^.lt := lidentifier; + tp := sp^.lsymdecl + end + else + error(emultdeclid); + newid := tp +end; + +(* Check that the current identifier is already declared, *) +(* we fail unless l in [lforward, lpointer]. *) +(* Create and return a new node referencing it. *) +function oldid(ip : idptr; l : ltypes) : treeptr; + +var sp : symptr; + tp : treeptr; + +begin + sp := lookupid(ip, true); + if sp = nil then + begin + if l in [lforward, lpointer] then + begin + tp := newid(ip); + tp^.tsym^.lt := l + end + else + error(enotdeclid) + end + else begin + sp^.lused := true; + tp := mknode(nid); + tp^.tsym := sp; + if (sp^.lt = lpointer) and (l = lidentifier) then + begin + sp^.lt := lidentifier; + sp^.lsymdecl := tp + end + end; + oldid := tp +end; + +(* Look up a field in a record declaration. *) +(* Return nil if field isn't declared in "tp" or its variants. *) +function oldfield(tp : treeptr; ip : idptr) : treeptr; + +label 999; + +var tq, ti, + fp : treeptr; + +begin + fp := nil; + tq := tp^.tflist; + while tq <> nil do + begin + ti := tq^.tidl; + while ti <> nil do + begin + if ti^.tsym^.lid = ip then + begin + fp := mknode(nid); + fp^.tsym := ti^.tsym; + goto 999 + end; + ti := ti^.tnext + end; + tq := tq^.tnext + end; + tq := tp^.tvlist; + while tq <> nil do + begin + fp := oldfield(tq^.tvrnt, ip); + if fp <> nil then + tq := nil + else + tq := tq^.tnext + end; +999: + oldfield := fp +end; + +(* This is the main parsing routine. It parses a correct pascal- *) +(* program and builds a parsetree which is left in the global *) +(* variable top. *) +(* Parsing is done through recursive descent using a set of *) +(* mutually recursive functions. *) +procedure parse; + + function plabel : treeptr; forward; + function pidlist(l : ltypes) : treeptr; forward; + function pconst : treeptr; forward; + function pconstant(realok : boolean) : treeptr; forward; + function precord(cs : symtyp; dp : declptr) : treeptr; forward; + function ptypedef : treeptr; forward; + function ptype : treeptr; forward; + function pvar : treeptr; forward; + function psubs : treeptr; forward; + function psubpar : treeptr; forward; + function plabstmt : treeptr; forward; + function pstmt : treeptr; forward; + function psimple : treeptr; forward; + function pvariable(varptr : treeptr) : treeptr; forward; + function pexpr(tnp : treeptr) : treeptr; forward; + function pcase : treeptr; forward; + function pif : treeptr; forward; + function pwhile : treeptr; forward; + function prepeat : treeptr; forward; + function pfor : treeptr; forward; + function pwith : treeptr; forward; + function pgoto : treeptr; forward; + function pbegin(retain : boolean) : treeptr; forward; + + (* Open scope of a record variable. *) + procedure scopeup(tp : treeptr); + + (* Scan a record-declaration and add all fields to *) + (* current scope. *) + procedure addfields(rp : treeptr); + + var fp, ip, vp : treeptr; + sp : symptr; + + begin + fp := rp^.tflist; + while fp <> nil do + begin + ip := fp^.tidl; + while ip <> nil do + begin + sp := mksym(lfield); + sp^.lid := ip^.tsym^.lid; + sp^.lused := false; + sp^.lsymdecl := ip; + declsym(sp); + ip := ip^.tnext + end; + fp := fp^.tnext + end; + vp := rp^.tvlist; + while vp <> nil do + begin + addfields(vp^.tvrnt); + vp := vp^.tnext + end + end; + begin + addfields(typeof(tp)) + end; + + (* Check that the current label is new then save it in the *) + (* current scope. Create and return a new node referencing *) + (* the label. *) + function newlbl : treeptr; + + var sp : symptr; + tp : treeptr; + + begin + tp := mknode(nlabel); + sp := lookuplabel(currsym.vint); + if sp <> nil then + if sp^.ldecl <> symtab then + sp := nil; + if sp = nil then + begin + sp := mksym(lforwlab); + sp^.lno := currsym.vint; + sp^.lgo := false; + sp^.lsymdecl := tp; + declsym(sp) + end + else + error(emultdecllab); + tp^.tsym := sp; + newlbl := tp + end; + + (* Check that the current label is already declared. *) + (* Create and return a new node referencing it. *) + function oldlbl(defpt : boolean) : treeptr; + + var sp : symptr; + tp : treeptr; + + begin + sp := lookuplabel(currsym.vint); + if sp = nil then + begin + prtmsg(enotdecllab); + tp := newlbl; + sp := tp^.tsym + end + else begin + tp := mknode(nlabel); + tp^.tsym := sp + end; + if defpt then + begin + + if sp^.lt = lforwlab then + sp^.lt := llabel + else + error(emuldeflab); + end; + oldlbl := tp + end; + + (* Parse declaration and statement-body for prog/subs. *) + procedure pbody(tp : treeptr); + + var tq : treeptr; + + begin + statlvl := statlvl + 1; + if currsym.st = slabel then + begin + tp^.tsublab := plabel; + linkup(tp, tp^.tsublab) + end + else + tp^.tsublab := nil; + if currsym.st = sconst then + begin + tp^.tsubconst := pconst; + linkup(tp, tp^.tsubconst) + end + else + tp^.tsubconst := nil; + if currsym.st = stype then + begin + tp^.tsubtype := ptype; + linkup(tp, tp^.tsubtype) + end + else + tp^.tsubtype := nil; + if currsym.st = svar then + begin + tp^.tsubvar := pvar; + linkup(tp, tp^.tsubvar) + end + else + tp^.tsubvar := nil; + tp^.tsubsub := nil; + tq := nil; + while (currsym.st = sproc) or (currsym.st = sfunc) do + begin + if tq = nil then + begin + tq := psubs; + tp^.tsubsub := tq + end + else begin + tq^.tnext := psubs; + tq := tq^.tnext + end + end; + linkup(tp, tp^.tsubsub); + checksymbol([sbegin, seof]); + if currsym.st = sbegin then + begin + tp^.tsubstmt := pbegin(false); + linkup(tp, tp^.tsubstmt) + end; + statlvl := statlvl - 1 + end; + + (* Parse program-declaration. *) + function pprogram : treeptr; + + var tp : treeptr; + + (* Parse a program parameter id-list. *) + function pprmlist : treeptr; + + label 999; + + var tp, + tq : treeptr; + din, + dut : idptr; + + begin + tp := nil; + din := deftab[dinput]^.tidl^.tsym^.lid; + dut := deftab[doutput]^.tidl^.tsym^.lid; + while (currsym.vid = din) or (currsym.vid = dut) do + begin + (* ignore input/output as parameters so that + they will be bound to stdin/stdout unless + declared as variables *) + if currsym.vid = din then + defnams[dinput]^.lused := true + else + defnams[doutput]^.lused := true; + nextsymbol([scomma, srpar]); + if currsym.st = srpar then + goto 999; + nextsymbol([sid]) + end; + tq := newid(currsym.vid); + tq^.tsym^.lt := lpointer; + tp := tq; + nextsymbol([scomma, srpar]); + while currsym.st = scomma do + begin + nextsymbol([sid]); + if currsym.vid = din then + defnams[dinput]^.lused := true + else if currsym.vid = dut then + defnams[doutput]^.lused := true + else begin + tq^.tnext := newid(currsym.vid); + tq := tq^.tnext; + tq^.tsym^.lt := lpointer; + end; + nextsymbol([scomma, srpar]) + end; + 999: + pprmlist := tp + end; + + begin (* pprogram *) + enterscope(nil); + tp := mknode(npgm); + nextsymbol([sid]); + tp^.tstat := statlvl; + tp^.tsubid := mknode(nid); + tp^.tsubid^.tup := tp; + tp^.tsubid^.tsym := mksym(lidentifier); + tp^.tsubid^.tsym^.lid := currsym.vid; + tp^.tsubid^.tsym^.lsymdecl := tp^.tsubid; + linkup(tp, tp^.tsubid); + nextsymbol([slpar, ssemic]); + if currsym.st = slpar then + begin + nextsymbol([sid]); + tp^.tsubpar := pprmlist; + linkup(tp, tp^.tsubpar); + nextsymbol([ssemic]) + end + else + tp^.tsubpar := nil; + nextsymbol([slabel, sconst, stype, svar, + sproc, sfunc, sbegin]); + pbody(tp); + checksymbol([sdot]); + tp^.tscope := currscope; + leavescope; + pprogram := tp + end; (* pprogram *) + + (* Parse a module. *) + function pmodule : treeptr; + + var tp : treeptr; + + begin (* pmodule *) + enterscope(nil); + tp := mknode(npgm); + tp^.tstat := statlvl; + tp^.tsubid := nil; + tp^.tsubpar := nil; + pbody(tp); + checksymbol([ssemic]); + tp^.tscope := currscope; + leavescope; + pmodule := tp + end; (* pmodule *) + + + (* Parse label-clause. *) + function plabel; + + var tp, + tq : treeptr; + + begin + tq := nil; + repeat + nextsymbol([sinteger]); + if tq = nil then + begin + tq := newlbl; + tp := tq + end + else begin + tq^.tnext := newlbl; + tq := tq^.tnext; + end; + nextsymbol([scomma, ssemic]) + until currsym.st = ssemic; + nextsymbol([sconst, stype, svar, sbegin, sproc, sfunc]); + plabel := tp + end; + + (* Parse an id-list. *) + function pidlist; + + var tp, + tq : treeptr; + + begin + tq := newid(currsym.vid); + tq^.tsym^.lt := l; + tp := tq; + nextsymbol([scomma, scolon, seq, srpar]); + while currsym.st = scomma do + begin + nextsymbol([sid]); + tq^.tnext := newid(currsym.vid); + tq := tq^.tnext; + tq^.tsym^.lt := l; + nextsymbol([scomma, scolon, seq, srpar]) + end; + pidlist := tp + end; + + (* Parse const-clause. *) + function pconst; + + var tp, + tq : treeptr; + + begin + tq := nil; + nextsymbol([sid]); + repeat + if tq = nil then + begin + tq := mknode(nconst); + tq^.tattr := anone; + tp := tq + end + else begin + tq^.tnext := mknode(nconst); + tq := tq^.tnext; + tq^.tattr := anone + end; + tq^.tidl := pidlist(lidentifier); + checksymbol([seq]); + nextsymbol([sid, schar, sstring, sinteger, sreal, + splus, sminus]); + tq^.tbind := pconstant(true); + nextsymbol([ssemic]); + nextsymbol([sid, stype, svar, sbegin, + sfunc, sproc, seof]) + until currsym.st <> sid; + pconst := tp + end; + + (* Parse a declared constant or a case-statment const. *) + function pconstant; + + var tp, + tq : treeptr; + neg : boolean; + + begin + neg := currsym.st = sminus; + if currsym.st in [splus, sminus] then + if realok then + nextsymbol([sid, sinteger, sreal]) + else + nextsymbol([sid, sinteger]); + if currsym.st = sid then + tp := oldid(currsym.vid, lidentifier) + else + tp := mklit; + if neg then + begin + tq := mknode(numinus); + tq^.texps := tp; + tp := tq + end; + pconstant := tp + end; + + (* Parse a record (or record-variant) declaration. *) + (* Cs is the expected closing symbol, dp the scope. *) + function precord; + + label 999; + + var tp, + tq, + tl, + tv : treeptr; + tsym : lexsym; + + begin + tp := mknode(nrecord); + tp^.tflist := nil; + tp^.tvlist := nil; + tp^.tuid := nil; + tp^.trscope := nil; + if cs = send then + begin + enterscope(dp); + dp := currscope + end; + nextsymbol([sid, scase] + [cs]); + tq := nil; + while currsym.st = sid do + begin + if tq = nil then + begin + tq := mknode(nfield); + tq^.tattr := anone; + tp^.tflist := tq + end + else begin + tq^.tnext := mknode(nfield); + tq := tq^.tnext; + tq^.tattr := anone + end; + tq^.tidl := pidlist(lfield); + checksymbol([scolon]); + leavescope; + tq^.tbind := ptypedef; + enterscope(dp); + if currsym.st = ssemic then + nextsymbol([sid, scase] + [cs]) + end; + if currsym.st = scase then + begin + nextsymbol([sid]); + tsym := currsym; + nextsymbol([scolon, sof]); + if currsym.st = scolon then + begin + tv := newid(tsym.vid); + if tq = nil then + begin + tq := mknode(nfield); + tp^.tflist := tq + end + else begin + tq^.tnext := mknode(nfield); + tq := tq^.tnext + end; + tq^.tidl := tv; + tv^.tsym^.lt := lfield; + nextsymbol([sid]); + leavescope; + tq^.tbind := oldid(currsym.vid, lidentifier); + enterscope(dp); + nextsymbol([sof]) + end; + tq := nil; + repeat + tv := nil; + repeat + nextsymbol([sid, sinteger, schar, splus, + sminus] + [cs]); + if currsym.st = cs then + goto 999; + if tv = nil then + begin + tv := pconstant(false); + tl := tv + end + else begin + tv^.tnext := pconstant(false); + tv := tv^.tnext + end; + nextsymbol([scolon, scomma]) + until currsym.st = scolon; + nextsymbol([slpar]); + if tq = nil then + begin + tq := mknode(nvariant); + tp^.tvlist := tq; + end + else begin + tq^.tnext := mknode(nvariant); + tq := tq^.tnext; + end; + tq^.tselct := tl; + tq^.tvrnt := precord(srpar, dp) + until currsym.st = cs + end; + 999: + if cs = send then + begin + tp^.trscope := dp; + leavescope + end; + nextsymbol([ssemic, send, srpar]); + (* currsym is the symbol following record end/rpar, + (usually semicolon, sometimes enclosing end/rpar) *) + precord := tp + end; + + function ptypedef; + + var tp, + tq : treeptr; + st : symtyp; + ss : symset; + + begin + nextsymbol([sid, slpar, sarrow, sinteger, schar, splus, sminus, + spacked, sarray, srecord, sfile, sset]); + + (* the "packed" keyword is completely ignored *) + if currsym.st = spacked then + nextsymbol([sarray, srecord, sfile, sset]); + + ss := [ssemic, send, srpar, scomma, srbrack]; + case currsym.st of + splus, + sminus, + schar, + sinteger, + sid: + begin + st := currsym.st; + tp := pconstant(false); + if st = sid then + nextsymbol([sdotdot] + ss) + else + nextsymbol([sdotdot]); + if currsym.st = sdotdot then + begin + nextsymbol([sid, sinteger, schar, + splus, sminus]); + tq := mknode(nsubrange); + tq^.tlo := tp; + tq^.thi := pconstant(false); + tp := tq; + nextsymbol(ss) + end + end; + slpar: + begin + tp := mknode(nscalar); + nextsymbol([sid]); + tp^.tscalid := pidlist(lidentifier); + checksymbol([srpar]); + nextsymbol(ss) + end; + sarrow: + begin + tp := mknode(nptr); + nextsymbol([sid]); + tp^.tptrid := oldid(currsym.vid, lpointer); + tp^.tptrflag := false; + nextsymbol([ssemic, send, srpar]) + end; + sarray: + begin + nextsymbol([slbrack]); + tp := mknode(narray); + tp^.taindx := ptypedef; (* parse subrange ... *) + tq := tp; + while currsym.st = scomma do + begin + (* expand: array [ A , B ] of X + to: array [ A ] of array [ B ] of X *) + tq^.taelem := mknode(narray); + tq := tq^.taelem; + tq^.taindx := ptypedef (* ... again *) + end; + checksymbol([srbrack]); + nextsymbol([sof]); + tq^.taelem := ptypedef + end; + srecord: + tp := precord(send, nil); + sfile, + sset: + begin + if currsym.st = sfile then + tp := mknode(nfileof) + else begin + tp := mknode(nsetof); + usesets := true + end; + nextsymbol([sof]); + tp^.tof := ptypedef + end + end; + (* at this point "currsym" holds the symbol following the type + (usually semicolon, sometimes the following end/rpar) *) + ptypedef := tp + end; + + (* Parse type-clause. *) + function ptype; + + var tp, + tq : treeptr; + + begin + tq := nil; + nextsymbol([sid]); + repeat + if tq = nil then + begin + tq := mknode(ntype); + tq^.tattr := anone; + tp := tq + end + else begin + tq^.tnext := mknode(ntype); + tq := tq^.tnext; + tq^.tattr := anone + end; + tq^.tidl := pidlist(lidentifier); + checksymbol([seq]); + tq^.tbind := ptypedef; + nextsymbol([sid, svar, sbegin, sfunc, sproc, seof]) + until currsym.st <> sid; + ptype := tp; + end; + + (* Parse var-clause. *) + function pvar; + + var ti, + tp, + tq : treeptr; + + begin + tq := nil; + nextsymbol([sid]); + repeat + if tq = nil then + begin + tq := mknode(nvar); + tq^.tattr := anone; + tp := tq + end + else begin + tq^.tnext := mknode(nvar); + tq := tq^.tnext; + tq^.tattr := anone + end; + + ti := newid(currsym.vid); + tq^.tidl := ti; + nextsymbol([scomma, scolon]); + while currsym.st = scomma do + begin + nextsymbol([sid]); + ti^.tnext := newid(currsym.vid); + ti := ti^.tnext; + nextsymbol([scomma, scolon]) + end; + + tq^.tbind := ptypedef; + nextsymbol([sid, sbegin, sfunc, sproc, seof]) + until currsym.st <> sid; + pvar := tp + end; + + (* Parse subroutine-declaration. *) + function psubs; + + var tp, (* return value *) + tv, tq : treeptr; (* temporary *) + func : boolean; (* true for functions *) + colsem : symtyp; (* colon/semicolon *) + + begin + (* parsing function or procedure *) + func := currsym.st = sfunc; + if func then + colsem := scolon + else + colsem := ssemic; + + (* parse id, it may already be forward declared *) + nextsymbol([sid]); + tq := newid(currsym.vid); + if tq^.tup = nil then + begin + enterscope(nil); + (* id wasn't previously declared, params possible *) + if func then + tp := mknode(nfunc) + else + tp := mknode(nproc); + tp^.tstat := statlvl; + tp^.tsubid := tq; + linkup(tp, tq); + nextsymbol([slpar, colsem]); + if currsym.st = slpar then + begin + tp^.tsubpar := psubpar; + linkup(tp, tp^.tsubpar); + nextsymbol([colsem]) + end + else + tp^.tsubpar := nil; + if func then + begin + (* parse function type *) + nextsymbol([sid]); + tp^.tfuntyp := oldid(currsym.vid, lidentifier); + nextsymbol([ssemic]) + end + else + tp^.tfuntyp := mknode(nempty); + linkup(tp, tp^.tfuntyp); + nextsymbol([sextern, sforward, + slabel, sconst, stype, svar, + sproc, sfunc, sbegin]); + end + else begin + (* id was forward declared => + pick up declarations from parameterlist *) + enterscope(tq^.tup^.tscope); + if func then + tp := mknode(nfunc) + else + tp := mknode(nproc); + tp^.tfuntyp := tq^.tup^.tfuntyp; + (* steal id and params from forward decl *) + tv := tq^.tup^.tsubpar; + tp^.tsubpar := tv; + while tv <> nil do + begin + tv^.tup := tp; + tv := tv^.tnext + end; + tp^.tsubid := tq; + tq^.tup := tp; + (* id was forward declared => + no params, no function type, no forward *) + nextsymbol([ssemic]); + nextsymbol([slabel, sconst, stype, svar, + sproc, sfunc, sbegin]); + end; + if currsym.st in [sforward, sextern] then + begin + tp^.tsubid^.tsym^.lt := lforward; + nextsymbol([ssemic]); + tp^.tsublab := nil; + tp^.tsubconst := nil; + tp^.tsubtype := nil; + tp^.tsubvar := nil; + tp^.tsubsub := nil; + tp^.tsubstmt := nil + end + else + pbody(tp); + nextsymbol([sproc, sfunc, sbegin, seof]); + tp^.tscope := currscope; + leavescope; + psubs := tp + end; + + (* Parse a conformant array index type. *) + function pconfsub : treeptr; + + var tp : treeptr; + + begin + tp := mknode(nsubrange); + nextsymbol([sid]); + tp^.tlo := newid(currsym.vid); + nextsymbol([sdotdot]); + nextsymbol([sid]); + tp^.thi := newid(currsym.vid); + nextsymbol([scolon]); + pconfsub := tp + end; + + (* Parse a conformant array-declaration. *) + function pconform : treeptr; + + var tp, tq : treeptr; + + begin + nextsymbol([slbrack]); + tp := mknode(nconfarr); + tp^.tcuid := mkvariable('S'); + tp^.tcindx := pconfsub; (* parse subrange ... *) + nextsymbol([sid]); + tp^.tindtyp := oldid(currsym.vid, lidentifier); + nextsymbol([ssemic, srbrack]); + tq := tp; + while currsym.st = ssemic do + begin + error(econfconf); (* what size does tp have *) + + (* expand: array [ A ; B ] of X + to: array [ A ] of array [ B ] of X *) + tq^.tcelem := mknode(nconfarr); + tq := tq^.tcelem; + tq^.tcindx := pconfsub; (* ... again *) + nextsymbol([sid]); + tq^.tindtyp := oldid(currsym.vid, lidentifier); + nextsymbol([ssemic, srbrack]) + end; + nextsymbol([sof]); + nextsymbol([sid, sarray]); + case currsym.st of + sid: + tq^.tcelem := oldid(currsym.vid, lidentifier); + sarray: + begin + error(econfconf); (* what size does tp have *) + + tq^.tcelem := pconform + end; + end;(* case *) + pconform := tp + end; + + (* Parse subroutine parameter list. *) + function psubpar; + + var tp, + tq : treeptr; + nt : treetyp; + + begin + tq := nil; + repeat + nextsymbol([sid, svar, sfunc, sproc]); + case currsym.st of + sid: + nt := nvalpar; + svar: + nt := nvarpar; + sfunc: + nt := nparfunc; + sproc: + nt := nparproc; + end; + if nt <> nvalpar then + nextsymbol([sid]); + if tq = nil then + begin + tq := mknode(nt); + tp := tq + end + else begin + tq^.tnext := mknode(nt); + tq := tq^.tnext + end; + case nt of + nvarpar, + nvalpar: + begin + tq^.tidl := pidlist(lidentifier); + tq^.tattr := anone; + checksymbol([scolon]); + if nt = nvalpar then + nextsymbol([sid]) + else + nextsymbol([sid, sarray]); + case currsym.st of + sid: + tq^.tbind := + oldid(currsym.vid, lidentifier); + sarray: + tq^.tbind := pconform + end;(* case *) + nextsymbol([srpar, ssemic]) + end; + nparproc: + begin + tq^.tparid := newid(currsym.vid); + nextsymbol([ssemic, slpar, srpar]); + if currsym.st = slpar then + begin + enterscope(nil); + tq^.tparparm := psubpar; + nextsymbol([ssemic, srpar]); + leavescope + end + else + tq^.tparparm := nil; + tq^.tpartyp := nil + end; + nparfunc: + begin + tq^.tparid := newid(currsym.vid); + nextsymbol([scolon, slpar]); + if currsym.st = slpar then + begin + enterscope(nil); + tq^.tparparm := psubpar; + nextsymbol([scolon]); + leavescope + end + else + tq^.tparparm := nil; + nextsymbol([sid]); + tq^.tpartyp := oldid(currsym.vid, lidentifier); + nextsymbol([srpar, ssemic]) + end + end (* case *) + until currsym.st = srpar; + psubpar := tp + end; + + (* Parse a (possibly labeled) statement. *) + function plabstmt; + + var tp : treeptr; + + begin + nextsymbol([sid, sinteger, sif, swhile, srepeat, sfor, scase, + swith, sbegin, sgoto, + selse, ssemic, send, suntil]); + if currsym.st = sinteger then + begin + tp := mknode(nlabstmt); + tp^.tlabno := oldlbl(true); + nextsymbol([scolon]); + nextsymbol([sid, sif, swhile, srepeat, sfor, scase, + swith, sbegin, sgoto, + selse, ssemic, send, suntil]); + tp^.tstmt := pstmt + end + else + tp := pstmt; + plabstmt := tp + end; + + (* Parse an unlabeled statement. *) + function pstmt; + + var tp : treeptr; + + begin + case currsym.st of + sid: + tp := psimple; + sif: + tp := pif; + swhile: + tp := pwhile; + srepeat: + tp := prepeat; + sfor: + tp := pfor; + scase: + tp := pcase; + swith: + tp := pwith; + sbegin: + tp := pbegin(true); + sgoto: + tp := pgoto; + send, + selse, + suntil, + ssemic: + tp := mknode(nempty); + end; + pstmt := tp + end; + + (* Parse an assignment or a procedure call. *) + function psimple; + + var tq, + tp : treeptr; + + begin + tp := pvariable(oldid(currsym.vid, lidentifier)); + if currsym.st = sassign then + begin + tq := mknode(nassign); + tq^.tlhs := tp; + tq^.trhs := pexpr(nil); + tp := tq + end; + psimple := tp + end; + + (* Parse a varable-reference (or a subroutine-call). *) + function pvariable; + + var tp, + tq : treeptr; + + begin + nextsymbol([slpar, slbrack, sdot, sarrow, + sassign, ssemic, scomma, scolon, sdotdot, + splus, sminus, smul, sdiv, smod, squot, + sand, sor, sinn, srpar, srbrack, + sle, slt, seq, sge, sgt, sne, + send, suntil, sthen, selse, sdo, sdownto, sto, sof]); + if currsym.st in [slpar, slbrack, sdot, sarrow] then + begin + case currsym.st of + slpar: + begin + tp := mknode(ncall); + tp^.tcall := varptr; + tq := nil; + repeat + if tq = nil then + begin + tq := pexpr(nil); + tp^.taparm := tq + end + else begin + tq^.tnext := pexpr(nil); + tq := tq^.tnext + end; + until currsym.st = srpar + end; + slbrack: + begin + tq := varptr; + repeat + tp := mknode(nindex); + tp^.tvariable := tq; + tp^.toffset := pexpr(nil); + tq := tp + until currsym.st = srbrack + end; + sdot: + begin + tp := mknode(nselect); + tp^.trecord := varptr; + nextsymbol([sid]); + tq := typeof(varptr); + enterscope(tq^.trscope); + tp^.tfield := oldid(currsym.vid, lfield); + leavescope + end; + sarrow: + begin + tp := mknode(nderef); + tp^.texps := varptr + end + end;(* case *) + tp := pvariable(tp) + end + else begin + tp := varptr; + if tp^.tt = nid then + begin + tq := idup(tp); + if tq <> nil then + if tq^.tt in [nfunc, nproc, + nparproc, nparfunc] then + begin + (* subroutine-call without + parameters *) + tp := mknode(ncall); + tp^.tcall := varptr; + tp^.taparm := nil + end + end + end; + pvariable := tp + end; + + (* Parse an expression. *) + function pexpr; + + var tp, + tq : treeptr; + nt : treetyp; + next : boolean; + + function padjust(tu, tr : treeptr) : treeptr; + begin + if pprio[tu^.tt] >= pprio[tr^.tt] then + begin + if tr^.tt in [nnot, numinus, nuplus, + nset, nderef] then + tr^.texps := padjust(tu, tr^.texps) + else + tr^.texpl := padjust(tu, tr^.texpl); + padjust := tr + end + else begin + if tu^.tt in [nnot, numinus, nuplus, + nset, nderef] then + tu^.texps := tr + else + tu^.texpr := tr; + padjust := tu + end + end; + + begin + nextsymbol([sid, schar, sinteger, sreal, sstring, snil, + splus, sminus, snot, slpar, slbrack, srbrack]); + next := true; + case currsym.st of + splus: + begin + tp := mknode(nuplus); + tp^.texps := nil; + tp := pexpr(tp); + next := false + end; + sminus: + begin + tp := mknode(numinus); + tp^.texps := nil; + tp := pexpr(tp); + next := false + end; + snot: + begin + tp := mknode(nnot); + tp^.texps := nil; + tp := pexpr(tp); + next := false + end; + schar, + sinteger, + sreal, + sstring: + tp := mklit; + snil: + begin + usenilp := true; + tp := mknode(nnil); + end; + sid: + begin + tp := pvariable(oldid(currsym.vid, lidentifier)); + next := false + end; + slpar: + begin + tp := mknode(nuplus); + tp^.texps := pexpr(nil) + end; + slbrack: + begin + usesets := true; + tp := mknode(nset); + tp^.texps := nil; + tq := nil; + repeat + if tq = nil then + begin + tq := pexpr(nil); + tp^.texps := tq + end + else begin + tq^.tnext := pexpr(nil); + tq := tq^.tnext + end + until currsym.st = srbrack; + end; + srbrack: + begin + tp := mknode(nempty); + next := false + end + end; + if next then + nextsymbol([ + scolon, ssemic, scomma, sdotdot, srpar, srbrack, + sle, slt, seq, sge, sgt, sne, + splus, sminus, smul, sdiv, smod, squot, + sand, sor, sinn, + send, suntil, sthen, selse, sdo, sdownto, sto, + sof, slpar, slbrack]); + case currsym.st of + sdotdot: + nt := nrange; + splus: + nt := nplus; + sminus: + nt := nminus; + smul: + nt := nmul; + sdiv: + nt := ndiv; + smod: + nt := nmod; + squot: + begin + defnams[dreal]^.lused := true; + nt := nquot; + end; + sand: + nt := nand; + sor: + nt := nor; + sinn: + begin + nt := nin; + usesets := true + end; + sle: + nt := nle; + slt: + nt := nlt; + seq: + nt := neq; + sge: + nt := nge; + sgt: + nt := ngt; + sne: + nt := nne; + scolon: + nt := nformat; + sid, schar, sinteger, sreal, sstring, snil, + ssemic, scomma, slpar, slbrack, srpar, srbrack, + send, suntil, sthen, selse, sdo, sdownto, sto, sof: + nt := nnil + end;(* case *) + if nt in [nin .. nor, nand, nnot] then + defnams[dboolean]^.lused := true; + if nt <> nnil then + begin + (* binary operator *) + tq := mknode(nt); + tq^.texpl := tp; + tq^.texpr := nil; + tp := pexpr(tq) + end; + + (* this statement yilds proper operator precedence *) + if tnp <> nil then + tp := padjust(tnp, tp); + pexpr := tp + end; + + (* Parse a case-statement. *) + function pcase; + + label 999; + + var tp, + tq, + tv : treeptr; + + begin + tp := mknode(ncase); + tp^.tcasxp := pexpr(nil); + checksymbol([sof]); + tq := nil; + repeat + if tq = nil then + begin + tq := mknode(nchoise); + tp^.tcaslst := tq + end + else begin + tq^.tnext := mknode(nchoise); + tq := tq^.tnext + end; + tv := nil; + repeat + nextsymbol([sid, sinteger, schar, + splus, sminus, send, sother]); + if currsym.st in [send, sother] then + goto 999; + if tv = nil then + begin + tv := pconstant(false); + tq^.tchocon := tv + end + else begin + tv^.tnext := pconstant(false); + tv := tv^.tnext + end; + nextsymbol([scomma, scolon]) + until currsym.st = scolon; + tq^.tchostmt := plabstmt + until currsym.st = send; + 999: + if currsym.st = sother then + begin + nextsymbol([scolon, sid, sif, swhile, srepeat, sfor, + scase, swith, sbegin, sgoto, + selse, ssemic, send, suntil]); + if currsym.st = scolon then + nextsymbol([sid, sif, swhile, srepeat, sfor, + scase, swith, sbegin, sgoto, + selse, ssemic, send, suntil]); + tp^.tcasother := pstmt + end + else begin + tp^.tcasother := nil; + usecase := true + end; + nextsymbol([ssemic, send, selse, suntil]); + pcase := tp + end; + + (* Parse an if-statement. *) + function pif; + + var tp : treeptr; + + begin + tp := mknode(nif); + tp^.tifxp := pexpr(nil); + checksymbol([sthen]); + tp^.tthen := plabstmt; + if currsym.st = selse then + tp^.telse := plabstmt + else + tp^.telse := nil; + pif := tp; + end; + + (* Parse a while-statement. *) + function pwhile; + + var tp : treeptr; + + begin + tp := mknode(nwhile); + tp^.twhixp := pexpr(nil); + checksymbol([sdo]); + tp^.twhistmt := plabstmt; + pwhile := tp; + end; + + (* Parse a repeat-statement. *) + function prepeat; + + var tp, + tq : treeptr; + + begin + tp := mknode(nrepeat); + tq := nil; + repeat + if tq = nil then + begin + tq := plabstmt; + tp^.treptstmt := tq + end + else begin + tq^.tnext := plabstmt; + tq := tq^.tnext + end; + checksymbol([ssemic, suntil]) + until currsym.st = suntil; + tp^.treptxp := pexpr(nil); + prepeat := tp + end; + + (* Parse a for-statement. *) + function pfor; + + var tp : treeptr; + + begin + tp := mknode(nfor); + nextsymbol([sid]); + tp^.tforid := oldid(currsym.vid, lidentifier); + nextsymbol([sassign]); + tp^.tfrom := pexpr(nil); + checksymbol([sdownto, sto]); + tp^.tincr := currsym.st = sto; + tp^.tto := pexpr(nil); + checksymbol([sdo]); + tp^.tforstmt := plabstmt; + pfor := tp + end; + + (* Parse a with-statement. *) + function pwith; + + var tp, + tq : treeptr; + + begin + tp := mknode(nwith); + tq := nil; + repeat + if tq = nil then + begin + tq := mknode(nwithvar); + tp^.twithvar := tq + end + else begin + tq^.tnext := mknode(nwithvar); + tq := tq^.tnext + end; + enterscope(nil); + tq^.tenv := currscope; + tq^.texpw := pexpr(nil); + scopeup(tq^.texpw); + checksymbol([scomma, sdo]) + until currsym.st = sdo; + tp^.twithstmt := plabstmt; + tq := tp^.twithvar; + while tq <> nil do + begin + leavescope; + tq := tq^.tnext + end; + pwith := tp + end; + + (* Parse a goto-statement. *) + function pgoto; + + var tp : treeptr; + + begin + nextsymbol([sinteger]); + tp := mknode(ngoto); + tp^.tlabel := oldlbl(false); + nextsymbol([ssemic, send, suntil, selse]); + pgoto := tp + end; + + (* Parse a begin-statement. *) + function pbegin; + + var tp, + tq : treeptr; + + begin + tq := nil; + repeat + if tq = nil then + begin + tq := plabstmt; + tp := tq + end + else begin + tq^.tnext := plabstmt; + tq := tq^.tnext + end + until currsym.st = send; + if retain then + begin + tq := mknode(nbegin); + tq^.tbegin := tp; + tp := tq + end; + nextsymbol([send, selse, suntil, sdot, ssemic]); + pbegin := tp + end; + +begin (* parse *) + nextsymbol([spgm, sconst, stype, svar, sproc, sfunc]); + if currsym.st = spgm then + top := pprogram + else + top := pmodule; + nextsymbol([seof]); +end; (* parse *) + +(* Compute value for a node (which must be some kind of constant). *) +function cvalof(tp : treeptr) : integer; + +var v : integer; + tq : treeptr; + +begin + case tp^.tt of + nuplus: + cvalof := cvalof(tp^.texps); + numinus: + cvalof := - cvalof(tp^.texps); + nnot: + cvalof := 1 - cvalof(tp^.texps); + nid: + begin + tq := idup(tp); + if tq = nil then + fatal(etree); + tp := tp^.tsym^.lsymdecl; + case tq^.tt of + nscalar: + begin + v := 0; + tq := tq^.tscalid; + while tq <> nil do + if tq = tp then + tq := nil + else begin + v := v + 1; + tq := tq^.tnext + end; + cvalof := v + end; + nconst: + cvalof := cvalof(tq^.tbind); + end;(* case *) + end; + ninteger: + cvalof := tp^.tsym^.linum; + nchar: + cvalof := ord(tp^.tsym^.lchar); + end (* case *) +end; (* cvalof *) + +(* Compute lower value of subrange or scalar type. *) +function clower(tp : treeptr) : integer; + +var tq : treeptr; + +begin + tq := typeof(tp); + if tq^.tt = nscalar then + clower := scalbase + else if tq^.tt = nsubrange then + if tq^.tup^.tt = nconfarr then + clower := 0 + else + clower := cvalof(tq^.tlo) + else if tq = typnods[tchar] then + clower := 0 + else if tq = typnods[tinteger] then + clower := -maxint + else + fatal(etree) +end; (* clower *) + +(* Compute upper value of subrange or scalar type. *) +function cupper(tp : treeptr) : integer; + +var tq : treeptr; + i : integer; + +begin + tq := typeof(tp); + if tq^.tt = nscalar then + begin + tq := tq^.tscalid; + i := scalbase; + while tq^.tnext <> nil do + begin + i := i + 1; + tq := tq^.tnext + end; + cupper := i + end + else if tq^.tt = nsubrange then + if tq^.tup^.tt = nconfarr then + fatal(euprconf) + else + cupper := cvalof(tq^.thi) + else if tq = typnods[tchar] then + cupper := maxchar + else if tq = typnods[tinteger] then + cupper := maxint + else + fatal(etree) +end; (* cupper *) + +(* Compute the number of elements in a subrange. *) +function crange(tp : treeptr) : integer; + +begin + crange := cupper(tp) - clower(tp) + 1 +end; + +(* Return number of words uset to store a set. *) +function csetwords(i : integer) : integer; + +begin + i := (i+(setbits)) div (setbits+1); + if i > maxsetrange then + error(esetsize); + csetwords := i +end; + +(* Return number of words uset to store a set. *) +function csetsize(tp : treeptr) : integer; + +var tq : treeptr; + i : integer; + +begin + tq := typeof(tp^.tof); + i := clower(tq); + (* bits in sets are always numbered from 0, so we (arbitrarily) + decide that the base must be in the first 6 words to avoid + unnecessary waste of space *) + if (i < 0) or (i >= 6 * (setbits+1)) then + error(esetbase); + csetsize := csetwords(crange(tq)) + 1 +end; + +(* Determine if tp is declared in the procedure it is used in. *) +function islocal(tp : treeptr) : boolean; + +var tq : treeptr; + +begin + tq := tp^.tsym^.lsymdecl; + while not (tq^.tt in [nproc, nfunc, npgm]) do + tq := tq^.tup; + while not (tp^.tt in [nproc, nfunc, npgm]) do + tp := tp^.tup; + islocal := tp = tq +end; + +(* Perform necessary transformations on tree and identifiers *) +(* before generating code. *) +procedure transform; + + + (* Rename function when used as a variable. *) + procedure renamf(tp : treeptr); + + var ip, iq : symptr; + tq, tv : treeptr; + + (* This procedure recursively descends the tree *) + (* and replaces function-assignments with variable *) + (* assignments. *) + procedure crtnvar(tp : treeptr); + + begin + while tp <> nil do + begin + case tp^.tt of + npgm: + crtnvar(tp^.tsubsub); + nfunc, + nproc: + begin + crtnvar(tp^.tsubsub); + crtnvar(tp^.tsubstmt) + end; + nbegin: + crtnvar(tp^.tbegin); + nif: + begin + crtnvar(tp^.tthen); + crtnvar(tp^.telse) + end; + nwhile: + crtnvar(tp^.twhistmt); + nrepeat: + crtnvar(tp^.treptstmt); + nfor: + crtnvar(tp^.tforstmt); + ncase: + begin + crtnvar(tp^.tcaslst); + crtnvar(tp^.tcasother) + end; + nchoise: + crtnvar(tp^.tchostmt); + nwith: + crtnvar(tp^.twithstmt); + nlabstmt: + crtnvar(tp^.tstmt); + nassign: + begin + (* revoke calls in assignment lhs, (mis- + parsed due to ambiguous syntax) *) + if tp^.tlhs^.tt = ncall then + begin + tp^.tlhs := tp^.tlhs^.tcall; + tp^.tlhs^.tup := tp + end; + (* function name -> variable name *) + tv := tp^.tlhs; + if tv^.tt = nid then + if tv^.tsym = ip then + tv^.tsym := iq + end; + nbreak, + npush, + npop, + ngoto, + nempty, + ncall: + (* no op *) + end;(* case *) + tp := tp^.tnext + end + end; + + begin (* renamf *) + while tp <> nil do + begin + case tp^.tt of + npgm, + nproc: + renamf(tp^.tsubsub); + nfunc: + begin + (* create a variable to hold return value *) + tq := mknode(nvar); + tq^.tattr := aregister; + tq^.tup := tp; + tq^.tidl := newid(mkvariable('R')); + tq^.tidl^.tup := tq; + tq^.tbind := tp^.tfuntyp; + (* put it FIRST among variables, see esubr() *) + tq^.tnext := tp^.tsubvar; + tp^.tsubvar := tq; + + iq := tq^.tidl^.tsym; + ip := tp^.tsubid^.tsym; + crtnvar(tp^.tsubsub); + crtnvar(tp^.tsubstmt); + (* process inner functions *) + renamf(tp^.tsubsub) + end; + end;(* case *) + tp := tp^.tnext + end + end; (* renamf *) + + (* This procedure rearranges the tree such that multiple *) + (* vardeclarations don't have (structured) types attached *) + (* to them. If such a declararation is found, a new name *) + (* is created and the type is moved to the type section. *) + procedure extract(tp : treeptr); + + var vp : treeptr; + + (* Create a declaration for tp, enter in pp type- *) + (* list and return an identifier referencing it. *) + function xtrit(tp, pp : treeptr; last : boolean) : treeptr; + + var np, rp : treeptr; + ip : idptr; + + begin + (* create new declaration *) + np := mknode(ntype); + ip := mkvariable('T'); + np^.tidl := newid(ip); + np^.tidl^.tup := np; + + (* create substitute id *) + rp := oldid(ip, lidentifier); + rp^.tup := tp^.tup; + rp^.tnext := tp^.tnext; + + (* steal type description *) + np^.tbind := tp; + tp^.tup := np; + tp^.tnext := nil; + + (* add new declaration to tree *) + np^.tup := pp; + if last and (pp^.tsubtype <> nil) then + begin + pp := pp^.tsubtype; + while pp^.tnext <> nil do + pp := pp^.tnext; + pp^.tnext := np + end + else begin + np^.tnext := pp^.tsubtype; + pp^.tsubtype := np; + end; + + xtrit := rp; + end; + + (* Extract anonymous enumeration types. *) + function xtrenum(tp, pp : treeptr) : treeptr; + + (* Name record-types referenced by ptrs. *) + procedure nametype(tp : treeptr); + + begin + tp := typeof(tp); + if tp^.tt = nrecord then + if tp^.tuid = nil then + tp^.tuid := mkvariable('S'); + end; + + begin + if tp <> nil then + begin + case tp^.tt of + nfield, + ntype, + nvar: + tp^.tbind := + xtrenum(tp^.tbind, pp); + + nscalar: + if tp^.tup^.tt <> ntype then + tp := xtrit(tp, pp, false); + + narray: + begin + tp^.taindx := xtrenum(tp^.taindx, pp); + tp^.taelem := xtrenum(tp^.taelem, pp); + end; + nrecord: + begin + tp^.tflist := xtrenum(tp^.tflist, pp); + tp^.tvlist := xtrenum(tp^.tvlist, pp); + end; + nvariant: + tp^.tvrnt := xtrenum(tp^.tvrnt, pp); + nfileof: + tp^.tof := xtrenum(tp^.tof, pp); + + nptr: + nametype(tp^.tptrid); + + nid, + nsubrange, + npredef, + nempty, + nsetof: + (* no op *) + end;(* case *) + tp^.tnext := xtrenum(tp^.tnext, pp) + end; + xtrenum := tp + end; + + begin (* extract *) + while tp <> nil do + begin + (* tp points to a program/procedure/function node *) + tp^.tsubtype := xtrenum(tp^.tsubtype, tp); + tp^.tsubvar := xtrenum(tp^.tsubvar, tp); + vp := tp^.tsubvar; + while vp <> nil do + begin + (* variables of structured unnamed types *) + if vp^.tbind^.tt in [nscalar, narray, + nrecord, nfileof] then + vp^.tbind := xtrit(vp^.tbind, tp, true); + vp := vp^.tnext + end; + extract(tp^.tsubsub); + tp := tp^.tnext + end + end; (* extract *) + + (* This procedure moves all local constants and types *) + (* used in nested procedures to the outermost declaration *) + (* level so that nested procedures may be extracted. *) + procedure global(tp, dp : treeptr; depend : boolean); + + label 555; + + var ip : treeptr; + dep : boolean; + + (* Mark all declared identifiers as unused. *) + procedure markdecl(xp : treeptr); + + begin + while xp <> nil do + begin + case xp^.tt of + nid: + xp^.tsym^.lused := false; + nconst: + markdecl(xp^.tidl); + ntype, + nvar, + nvalpar, + nvarpar, + nfield: + begin + markdecl(xp^.tidl); + if xp^.tbind^.tt <> nid then + markdecl(xp^.tbind) + end; + nscalar: + markdecl(xp^.tscalid); + nrecord: + begin + markdecl(xp^.tflist); + markdecl(xp^.tvlist) + end; + nvariant: + markdecl(xp^.tvrnt); + nconfarr: + if xp^.tcelem^.tt <> nid then + markdecl(xp^.tcelem); + narray: + if xp^.taelem^.tt <> nid then + markdecl(xp^.taelem); + nsetof, + nfileof: + if xp^.tof^.tt <> nid then + markdecl(xp^.tof); + nparproc, + nparfunc: + markdecl(xp^.tparid); + nptr, + nsubrange: + (* no op *) + end;(* case *) + xp := xp^.tnext + end + end; (* markdecl *) + + (* Move all marked declarations to global scope. *) + function movedecl(tp : treeptr) : treeptr; + + var ip, np : treeptr; + sp : symptr; + move : boolean; + + begin + if tp <> nil then + begin + move := false; + case tp^.tt of + nconst, + ntype: + ip := tp^.tidl + end;(* case *) + while ip <> nil do + begin + if ip^.tsym^.lused then + begin + move := true; + sp := ip^.tsym; + if sp^.lid^.inref > 1 then + begin + sp^.lid := + mkrename( 'M', sp^.lid); + sp^.lid^.inref := + sp^.lid^.inref - 1 + end; + ip := nil + end + else + ip := ip^.tnext + end; + if move then + begin + np := tp^.tnext; + tp^.tnext := nil; + ip := tp; + while ip^.tt <> npgm do + ip := ip^.tup; + tp^.tup := ip; + case tp^.tt of + nconst: + begin + if ip^.tsubconst = nil then + ip^.tsubconst := tp + else begin + ip := ip^.tsubconst; + while ip^.tnext <> nil + do ip := ip^.tnext; + ip^.tnext := tp + end + end; + ntype: + begin + if ip^.tsubtype = nil then + ip^.tsubtype := tp + else begin + ip := ip^.tsubtype; + while ip^.tnext <> nil + do ip := ip^.tnext; + ip^.tnext := tp + end + end + end;(* case *) + (* tp is moved, drop it and process + remainder of declarationlist *) + tp := movedecl(np) + end + else + tp^.tnext := movedecl(tp^.tnext) + end; + movedecl := tp + end; (* movedecl *) + + (* This procedure lifts out variables/parameters *) + (* used in nested procedures/functions. *) + procedure movevars(tp, vp : treeptr); + + label 555; + + var ep, dp, np : treeptr; + ip : idptr; + sp : symptr; + + (* Move a variable declaration to global *) + (* var declaration lists. *) + procedure moveglob(tp, dp : treeptr); + + begin + while tp^.tt <> npgm do + tp := tp^.tup; + dp^.tup := tp; + dp^.tnext := tp^.tsubvar; + tp^.tsubvar := dp + end; + + (* Create nodes for saving a global *) + (* pointer variable. *) + function stackop(decl, glob, loc : treeptr) : treeptr; + + var op, ip, dp, tp : treeptr; + + begin + (* create a new variable to hold old value + of the global variable during a call *) + ip := newid(mkvariable('F')); + case vp^.tt of + nvarpar, + nvalpar, + nvar: + begin + dp := mknode(nvarpar); + dp^.tattr := areference; + dp^.tidl := ip; + (* use same type as the global var *) + dp^.tbind := decl^.tbind + end; + nparproc, + nparfunc: + begin + dp := mknode(vp^.tt); + dp^.tparid := ip; + dp^.tparparm := nil; + dp^.tpartyp := vp^.tpartyp + end + end;(* case *) + ip^.tup := dp; + + (* add variable to declarationlists *) + tp := decl; + while not (tp^.tt in [nproc, nfunc, npgm]) do + tp := tp^.tup; + dp^.tup := tp; + if tp^.tsubvar = nil then + tp^.tsubvar := dp + else begin + tp := tp^.tsubvar; + while tp^.tnext <> nil do + tp := tp^.tnext; + tp^.tnext := dp + end; + dp^.tnext := nil; + + (* create an assignment saving value *) + op := mknode(npush); + op^.tglob := glob; + op^.tloc := loc; + op^.ttmp := ip; + stackop := op + end; + + (* Take a "push" node, create "pop" node *) + (* and add both to tree. *) + procedure addcode(tp, push : treeptr); + + var pop : treeptr; + + begin + pop := mknode(npop); + (* share variables with "push"-node *) + pop^.tglob := push^.tglob; + pop^.ttmp := push^.ttmp; + pop^.tloc := nil; + + (* add npush to head of statement list *) + push^.tnext := tp^.tsubstmt; + tp^.tsubstmt := push; + push^.tup := tp; + + (* add npop to end of statement list *) + while push^.tnext <> nil do + push := push^.tnext; + push^.tnext := pop; + pop^.tup := tp + end; + + begin (* movevars *) + while vp <> nil do + begin + case vp^.tt of + nvar, + nvalpar, + nvarpar: + dp := vp^.tidl; + nparproc, + nparfunc: + begin + dp := vp^.tparid; + if dp^.tsym^.lused then + begin + (* create a var declaration *) + ep := mknode(vp^.tt); + ep^.tparparm := nil; + ep^.tpartyp := vp^.tpartyp; + np := newid(mkrename('G', + dp^.tsym^.lid)); + ep^.tparid := np; + np^.tup := ep; + (* swap id's and symbols *) + sp := np^.tsym; + ip := sp^.lid; + np^.tsym^.lid := dp^.tsym^.lid; + dp^.tsym^.lid := ip; + np^.tsym := dp^.tsym; + dp^.tsym := sp; + np^.tsym^.lsymdecl := np; + dp^.tsym^.lsymdecl := dp; + (* make declaration global *) + moveglob(tp, ep); + (* add save/restore-code *) + addcode(tp, stackop(vp, np, dp)) + end; + goto 555 + end + end;(* case *) + while dp <> nil do + begin + if dp^.tsym^.lused then + begin + (* create a varpar declaration, + (nvarpar will cause emit to + treat the new identifier + as a pointer) *) + ep := mknode(nvarpar); + ep^.tattr := areference; + np := newid(mkrename('G', + dp^.tsym^.lid)); + ep^.tidl := np; + np^.tup := ep; + ep^.tbind := vp^.tbind; + if ep^.tbind^.tt = nid then + ep^.tbind^.tsym^.lused + := true; + (* swap id's and symbols *) + sp := np^.tsym; + ip := sp^.lid; + np^.tsym^.lid := dp^.tsym^.lid; + dp^.tsym^.lid := ip; + np^.tsym := dp^.tsym; + dp^.tsym := sp; + np^.tsym^.lsymdecl := np; + dp^.tsym^.lsymdecl := dp; + (* note that dp is referenced *) + dp^.tup^.tattr := aextern; + (* make declaration global *) + moveglob(tp, ep); + (* add save/restore-code *) + addcode(tp, stackop(vp, np, dp)) + end; + dp := dp^.tnext + end; + 555: + vp := vp^.tnext + end + end; (* movevars *) + + (* Break out a local variable and set the register *) + (* attribute. *) + procedure registervar(tp : treeptr); + + var vp, xp : treeptr; + + begin + vp := idup(tp); + tp := tp^.tsym^.lsymdecl; + (* vp points to nvar node *) + if (vp^.tidl <> tp) or (tp^.tnext <> nil) then + begin + (* tp is not alone in list of identifiers, + create a new nvar-node and hook up tp *) + xp := mknode(nvar); + xp^.tattr := anone; + xp^.tidl := tp; + tp^.tup := xp; + (* enter new nvar node among declarations *) + xp^.tup := vp^.tup; + xp^.tbind := vp^.tbind; (* borrow type *) + xp^.tnext := vp^.tnext; + vp^.tnext := xp; + (* break tp out of list of identifiers *) + if vp^.tidl = tp then + vp^.tidl := tp^.tnext + else begin + vp := vp^.tidl; + while vp^.tnext <> tp do + vp := vp^.tnext; + vp^.tnext := tp^.tnext + end; + tp^.tnext := nil + end; + (* tp is alone in this declaration, set attribute *) + if tp^.tup^.tattr = anone then + tp^.tup^.tattr := aregister + end; (* registervar *) + + (* Check static declarationlevel for a label *) + (* used in a non-local goto. *) + procedure cklevel(tp : treeptr); + + begin + tp := tp^.tsym^.lsymdecl; + while not(tp^.tt in [npgm, nproc, nfunc]) do + tp := tp^.tup; + if tp^.tstat > maxlevel then + maxlevel := tp^.tstat + end; + + begin (* global *) + while tp <> nil do + begin + case tp^.tt of + nproc, + nfunc: + begin + (* procid/parameters/const/type/var not used *) + markdecl(tp^.tsubid); + markdecl(tp^.tsubpar); + markdecl(tp^.tsubconst); + markdecl(tp^.tsubtype); + markdecl(tp^.tsubvar); + + (* mark those used in nested subroutines *) + global(tp^.tsubsub, tp, false); + + (* move out variables used in inner scope *) + movevars(tp, tp^.tsubpar); + movevars(tp, tp^.tsubvar); + (* move out const/type used in inner scope *) + tp^.tsubtype := movedecl(tp^.tsubtype); + tp^.tsubconst := movedecl(tp^.tsubconst); + + (* mark identifiers used in this subroutine *) + global(tp^.tsubstmt, tp, true); + global(tp^.tsubpar, tp, false); + global(tp^.tsubvar, tp, false); + global(tp^.tsubtype, tp, false); + global(tp^.tfuntyp, tp, false); + end; + + npgm: + begin + markdecl(tp^.tsubconst); + markdecl(tp^.tsubtype); + markdecl(tp^.tsubvar); + global(tp^.tsubsub, tp, false); + global(tp^.tsubstmt, tp, true) + end; + + nconst, + ntype, + nvar, + nfield, + nvalpar, + nvarpar: + begin + ip := tp^.tidl; + dep := depend; + while (ip <> nil) and not dep do + begin + (* for all used identifiers, propagate + the use to their bindings *) + if ip^.tsym^.lused then + dep := true; + ip := ip^.tnext + end; + global(tp^.tbind, dp, dep); + end; + nparproc, + nparfunc: + begin + global(tp^.tparparm, dp, depend); + global(tp^.tpartyp, dp, depend) + end; + nsubrange: + begin + global(tp^.tlo, dp, depend); + global(tp^.thi, dp, depend) + end; + nvariant: + begin + global(tp^.tselct, dp, depend); + global(tp^.tvrnt, dp, depend) + end; + nrecord: + begin + global(tp^.tflist, dp, depend); + global(tp^.tvlist, dp, depend) + end; + nconfarr: + begin + global(tp^.tcindx, dp, depend); + global(tp^.tcelem, dp, depend) + end; + narray: + begin + global(tp^.taindx, dp, depend); + global(tp^.taelem, dp, depend) + end; + nfileof, + nsetof: + global(tp^.tof, dp, depend); + nptr: + global(tp^.tptrid, dp, depend); + nscalar: + global(tp^.tscalid, dp, depend); + nbegin: + global(tp^.tbegin, dp, depend); + nif: + begin + global(tp^.tifxp, dp, depend); + global(tp^.tthen, dp, depend); + global(tp^.telse, dp, depend) + end; + nwhile: + begin + global(tp^.twhixp, dp, depend); + global(tp^.twhistmt, dp, depend) + end; + nrepeat: + begin + global(tp^.treptstmt, dp, depend); + global(tp^.treptxp, dp, depend) + end; + nfor: + begin + ip := idup(tp^.tforid); + if ip^.tup^.tt in [nproc, nfunc] then + registervar(tp^.tforid); + global(tp^.tforid, dp, depend); + global(tp^.tfrom, dp, depend); + global(tp^.tto, dp, depend); + global(tp^.tforstmt, dp, depend) + end; + ncase: + begin + global(tp^.tcasxp, dp, depend); + global(tp^.tcaslst, dp, depend); + global(tp^.tcasother, dp, depend) + end; + nchoise: + begin + global(tp^.tchocon, dp, depend); + global(tp^.tchostmt, dp, depend); + end; + nwith: + begin + global(tp^.twithvar, dp, depend); + global(tp^.twithstmt, dp, depend) + end; + nwithvar: + begin + ip := typeof(tp^.texpw); + if ip^.tuid = nil then + ip^.tuid := mkvariable('S'); + global(tp^.texpw, dp, depend); + end; + nlabstmt: + global(tp^.tstmt, dp, depend); + neq, nne, nlt, nle, ngt, nge: + begin + global(tp^.texpl, dp, depend); + global(tp^.texpr, dp, depend); + ip := typeof(tp^.texpl); + if (ip = typnods[tstring]) or + (ip^.tt = narray) then + usecomp := true; + ip := typeof(tp^.texpr); + if (ip = typnods[tstring]) or + (ip^.tt = narray) then + usecomp := true + end; + nin, nor, nplus, nminus, + nand, nmul, ndiv, nmod, nquot, + nformat, nrange: + begin + global(tp^.texpl, dp, depend); + global(tp^.texpr, dp, depend) + end; + + nassign: + begin + global(tp^.tlhs, dp, depend); + global(tp^.trhs, dp, depend) + end; + + nnot, + numinus, + nuplus, + nderef: + global(tp^.texps, dp, depend); + nset: + global(tp^.texps, dp, depend); + nindex: + begin + global(tp^.tvariable, dp, depend); + global(tp^.toffset, dp, depend) + end; + nselect: + global(tp^.trecord, dp, depend); + ncall: + begin + global(tp^.tcall, dp, depend); + global(tp^.taparm, dp, depend) + end; + nid: + begin + (* find declaration point *) + ip := idup(tp); + if ip = nil then + goto 555; + (* ip points to nconst/ntype/nvar/nproc/nfunc/ + nvalpar/nvarpar/nparproc or nparfunc node, + move to beginning of enclosing scope *) + repeat + ip := ip^.tup; + if ip = nil then + goto 555 + (* stop only for locally declared items, + for global or predefined identifiers + we will have gone to label 555 *) + until ip^.tt in [npgm, nproc, nfunc]; + if dp = ip then + begin + (* identifier used here, mark it used *) + if depend then + tp^.tsym^.lused := true + end + else begin + (* identifier declared in enclosing + scope, mark it used *) + tp^.tsym^.lused := true + end; + 555: + end; + ngoto: + if not islocal(tp^.tlabel) then + begin + tp^.tlabel^.tsym^.lgo := true; + usejmps := true; + cklevel(tp^.tlabel) + end; + + nbreak, + npush, + npop, + npredef, + nempty, + nchar, + ninteger, + nreal, + nstring, + nnil: + end;(* case *) + tp := tp^.tnext + end + end; (* global *) + + (* Rename identifiers identical to C keywords. *) + procedure renamc; + + var ip : idptr; + cn : cnames; + + begin + (* rename identifiers that mustn't be redefined + if C and Pascal semantix are to be preserved *) + for cn := cabort to cwrite do + begin + ip := mkrename('C', ctable[cn]); + ctable[cn]^.istr := ip^.istr + end + end; + + (* Rename subroutines declared in other subroutines such *) + (* that they can be moved to a global scope without name- *) + (* clashes. *) + procedure renamp(tp : treeptr; on : boolean); + + var sp : symptr; + + begin + (* tp points to subroutine-list *) + while tp <> nil do + begin + renamp(tp^.tsubsub, true); + if on and (tp^.tsubstmt <> nil) then + begin + (* change name of subroutine by prefixing + a unique name *) + sp := tp^.tsubid^.tsym; + if sp^.lid^.inref > 1 then + begin + sp^.lid := mkrename('P', sp^.lid); + sp^.lid^.inref := sp^.lid^.inref - 1 + end + end; + tp := tp^.tnext + end + end; + + (* Add initialization-code for file-variables. *) + procedure initcode(tp : treeptr); + + var ti, tq, tu, tv : treeptr; + + (* Determine if a type contains a file. *) + function filevar(tp : treeptr) : boolean; + + var fv : boolean; + tq : treeptr; + + begin + case tp^.tt of + npredef: + fv := tp = typnods[ttext]; + nfileof: + fv := true; + nconfarr: + fv := filevar(typeof(tp^.tcelem)); + narray: + fv := filevar(typeof(tp^.taelem)); + nrecord: + begin + fv := false; + tq := tp^.tvlist; + while tq <> nil do + begin + if filevar(tq^.tvrnt) then + error(evrntfile); + tq := tq^.tnext + end; + tq := tp^.tflist; + while tq <> nil do + begin + if filevar(typeof(tq^.tbind)) then + begin + fv := true; + tq := nil + end + else + tq := tq^.tnext + end + end; + nptr: + begin + fv := false; + if not tp^.tptrflag then + begin + tp^.tptrflag := true; + if filevar(typeof(tp^.tptrid)) then + error(evarfile); + tp^.tptrflag := false + end + end; + nsubrange, + nscalar, + nsetof: + fv := false + end; + filevar := fv + end; + + (* Create code for initialization of files. *) + function fileinit(ti, tq : treeptr; opn : boolean) : treeptr; + + var tx, ty, tz : treeptr; + + begin + (* create 1 statement initializing "ti" *) + case tq^.tt of + narray: + begin + (* create declaration for a loopvariable *) + tz := newid(mkvariable('I')); + ty := mknode(nvar); + ty^.tattr := aregister; + ty^.tidl := tz; + ty^.tbind := typeof(tq^.taindx); + tz := tq; + while not(tz^.tt in [nproc, nfunc, npgm]) do + tz := tz^.tup; + linkup(tz, ty); + if tz^.tsubvar = nil then + tz^.tsubvar := ty + else begin + tz := tz^.tsubvar; + while tz^.tnext <> nil do + tz := tz^.tnext; + tz^.tnext := ty + end; + ty := ty^.tidl; + (* create a loop initializing tq *) + tz := mknode(nindex); + tz^.tvariable := ti; + tz^.toffset := ty; + tz := fileinit(tz, tq^.taelem, opn); + tx := mknode(nfor); + tx^.tforid := ty; + ty := typeof(tq^.taindx); + if ty^.tt = nsubrange then + begin + tx^.tfrom := ty^.tlo; + + tx^.tto := ty^.thi + end + else if ty^.tt = nscalar then + begin + ty := ty^.tscalid; + tx^.tfrom := ty; + while ty^.tnext <> nil do + ty := ty^.tnext; + tx^.tto := ty + end + else if ty = typnods[tchar] then + begin + currsym.st := schar; + currsym.vchr := chr(minchar); + tx^.tfrom := mklit; + currsym.st := schar; + currsym.vchr := chr(maxchar); + tx^.tto := mklit + end + else if ty = typnods[tinteger] then + begin + currsym.st := sinteger; + currsym.vint := -maxint; + tx^.tfrom := mklit; + currsym.st := sinteger; + currsym.vint := maxint; + tx^.tto := mklit + end + else + fatal(etree); + tx^.tforstmt := tz; + tx^.tincr := true + end; + npredef, + nfileof: + if opn then + begin + (* create file-struct initialization *) + ty := mknode(nselect); + ty^.trecord := ti; + ty^.tfield := + oldid(defnams[dzinit]^.lid, + lforward); + tx := mknode(nassign); + tx^.tlhs := ty; + currsym.st := sinteger; + currsym.vint := 0; + tx^.trhs := mklit + end + else begin + (* create file-struct wrapup *) + tx := mknode(ncall); + tx^.tcall := + oldid(defnams[dclose]^.lid, + lidentifier); + tx^.taparm := ti + end; + nrecord: + begin + ty := nil; + tq := tq^.tflist; + while tq <> nil do + begin + if filevar(typeof(tq^.tbind)) then + begin + tz := tq^.tidl; + while tz <> nil do + begin + tx := mknode(nselect); + tx^.trecord := ti; + tx^.tfield := tz; + tx := fileinit(tx, + typeof(tq^.tbind), + opn); + tx^.tnext := ty; + ty := tx; + tz := tz^.tnext + end + end; + tq := tq^.tnext + end; + tx := mknode(nbegin); + tx^.tbegin := ty + end; + end;(* case *) + fileinit := tx + end; + + begin (* initcode *) + while tp <> nil do + begin + initcode(tp^.tsubsub); + tv := tp^.tsubvar; + while tv <> nil do + begin + tq := typeof(tv^.tbind); + if filevar(tq) then + begin + ti := tv^.tidl; + while ti <> nil do + begin + tu := fileinit(ti, tq, true); + linkup(tp, tu); + tu^.tnext := tp^.tsubstmt; + tp^.tsubstmt := tu; + while tu^.tnext <> nil do + tu := tu^.tnext; + tu^.tnext := fileinit(ti, tq, + false); + linkup(tp, tu^.tnext); + ti := ti^.tnext + end + end; + tv := tv^.tnext; + end; + tp := tp^.tnext + end + end; (* initcode *) + +begin (* transform *) + renamc; + renamp(top^.tsubsub, false); + extract(top); + renamf(top); + initcode(top^.tsubsub); + global(top, top, false) +end; (* transform *) + +(* Emit C-code for program or module. *) +procedure emit; + +const include = '# include '; + define = '# define '; + ifdef = '# ifdef '; + ifndef = '# ifndef '; + elsif = '# else'; + endif = '# endif'; + static = 'static '; + xtern = 'extern '; + typdef = 'typedef '; + registr = 'register '; + usigned = 'unsigned '; + indstep = 8; + +var conflag, + setused, + dropset, + donearr : boolean; + doarrow, + indnt : integer; + + procedure increment; + begin + indnt := indnt + indstep + end; + + procedure decrement; + begin + indnt := indnt - indstep + end; + + (* Write tabs/blanks to properly (?) indent C-code. *) + procedure indent; + + var i : integer; + + begin + i := indnt; + (* limit indent to an integral number of tabs *) + if i > 60 then + i := i div tabwidth * tabwidth; + while i >= tabwidth do + begin + write(tab1); + i := i - tabwidth + end; + while i > 0 do + begin + write(space); + i := i - 1 + end; + end; + + (* Determine if tp must be cast to an integer before being *) + (* used in an arithmetic expression. *) + function arithexpr(tp : treeptr) : boolean; + + begin + tp := typeof(tp); + if tp^.tt = nsubrange then + if tp^.tup^.tt = nconfarr then + tp := typeof(tp^.tup^.tindtyp) + else + tp := typeof(tp^.tlo); + arithexpr := (tp = typnods[tinteger]) or + (tp = typnods[tchar]) or + (tp = typnods[treal]) + end; + + procedure eexpr(tp : treeptr); forward; + procedure etypedef(tp : treeptr); forward; + + (* Emit code to select a record member. *) + procedure eselect(tp : treeptr); + + begin + doarrow := doarrow + 1; + eexpr(tp); + doarrow := doarrow - 1; + if donearr then + donearr := false + else + write('.') + end; + + (* Emit code for call to a predefined function/procedure. *) + procedure epredef(ts, tp : treeptr); + + label 444, 555; + + var tq, + tv, tx : treeptr; + td : predefs; + nelems : integer; + ch : char; + txtfile : boolean; + + (* Determine a format-code for fprintf. *) + (* Update nelems as a sideeffect. *) + function typeletter(tp : treeptr) : char; + + label 999; + + var tq : treeptr; + + begin + tq := tp; + if tq^.tt = nformat then + begin + if tq^.texpl^.tt = nformat then + begin + typeletter := 'f'; + goto 999 + end; + tq := tp^.texpl + end; + tq := typeof(tq); + if tq^.tt = nsubrange then + tq := typeof(tq^.tlo); + if tq = typnods[tstring] then + typeletter := 's' + else if tq = typnods[tinteger] then + typeletter := 'd' + else if tq = typnods[tchar] then + typeletter := 'c' + else if tq = typnods[treal] then + if tp^.tt = nformat then + typeletter := 'e' + else + typeletter := 'g' + else if tq = typnods[tboolean] then + begin + typeletter := 'b'; + nelems := 6 + end + else if tq^.tt = narray then + begin + typeletter := 'a'; + nelems := crange(tq^.taindx) + end + else if tq^.tt = nconfarr then + begin + typeletter := 'v'; + nelems := 0 + end + else + fatal(etree); + 999: + end; (* typeletter *) + + procedure etxt(tp : treeptr); + + var w : toknbuf; + c : char; + i : toknidx; + + begin + case tp^.tt of + nid: + begin + tp := idup(tp); + if tp^.tt = nconst then + etxt(tp^.tbind) + else + fatal(etree) + end; + nstring: + begin + (* printf format string *) + gettokn(tp^.tsym^.lstr, w); + i := 1; + while w[i] <> chr(null) do + begin + c := w[i]; + if (c = cite) or (c = bslash) then + write(bslash) + else if c = percent then + write(percent); + write(c); + i := i + 1 + end + end; + nchar: + begin + (* single character in printf format *) + c := tp^.tsym^.lchar; + if (c = cite) or (c = bslash) then + write(bslash) + else if c = percent then + write(percent); + write(c) + end; + end;(* case *) + end; (* etxt *) + + (* Emit format for fprintf. *) + procedure eformat(tq : treeptr); + + var tx : treeptr; + i : integer; + + begin + case typeletter(tq) of + 'a': + begin + write(percent); + if tq^.tt = nformat then + if tq^.texpr^.tt = ninteger then + eexpr(tq^.texpr) + else + write('*'); + write('.', nelems:1, 's') + end; + 'b': + begin + write(percent); + if tq^.tt = nformat then + begin + if tq^.texpr^.tt = ninteger then + eexpr(tq^.texpr) + else + write('*') + end; + write('s') + end; + 'c': + if tq^.tt = nchar then + etxt(tq) + else begin + write(percent); + if tq^.tt = nformat then + if tq^.texpr^.tt = ninteger then + eexpr(tq^.texpr) + else + write('*'); + write('c') + end; + 'd': + begin + write(percent); + if tq^.tt = nformat then + begin + if tq^.texpr^.tt = ninteger then + eexpr(tq^.texpr) + else + write('*') + end + else + write(intlen:1); + write('d') + end; + 'e': + begin + write(percent, space); + tx := tq^.texpr; + if tx^.tt = ninteger then + begin + i := cvalof(tx); + write(i:1, '.'); + i := i - 7; + if i < 1 then + write('1') + else + write(i:1) + end + else + write('*.*'); + write('e') + end; + 'f': + begin + write(percent); + tx := tq^.texpl; + if tx^.texpr^.tt = ninteger then + begin + eexpr(tx^.texpr); + write('.'); + tx := tq^.texpr; + if tx^.tt = ninteger then + begin + i := cvalof(tx); + tx := tq^.texpl^.texpr; + if i > cvalof(tx) - 1 then + write('1') + else + write(i:1) + end + else + write('*'); + end + else + write('*.*'); + write('f') + end; + 'g': + write(percent, fixlen:1, 'e'); + 's': + if tq^.tt = nstring then + etxt(tq) + else begin + write(percent); + if tq^.tt = nformat then + if tq^.texpr^.tt = ninteger then + eexpr(tq^.texpr) + else + write('*.*'); + write('s') + end + end (* case *) + end; (* eformat *) + + (* Emit parameters to fprintf except format. *) + procedure ewrite(tq : treeptr); + + var tx : treeptr; + + begin + case typeletter(tq) of + 'a': + begin + write(', '); + tx := tq; + if tq^.tt = nformat then + begin + if tq^.texpr^.tt <> ninteger then + begin + eexpr(tq^.texpr); + write(', ') + end; + tx := tq^.texpl + end; + eexpr(tx); + write('.A') + end; + 'b': + begin + write(', '); + tx := tq; + if tq^.tt = nformat then + begin + if tq^.texpr^.tt <> ninteger then + begin + eexpr(tq^.texpr); + write(', ') + end; + tx := tq^.texpl + end; + usebool := true; + write('Bools[(int)('); + eexpr(tx); + write(')]') + end; + 'c': + begin + if tq^.tt = nformat then + begin + if tq^.texpr^.tt <> ninteger then + begin + write(', '); + eexpr(tq^.texpr) + end; + write(', '); + eexpr(tq^.texpl) + end + else if tq^.tt <> nchar then + begin + write(', '); + eexpr(tq) + end + end; + 'd': + begin + write(', '); + tx := tq; + if tq^.tt = nformat then + begin + if tq^.texpr^.tt <> ninteger then + begin + eexpr(tq^.texpr); + write(', ') + end; + tx := tq^.texpl + end; + eexpr(tx) + end; + 'e': + begin + write(', '); + tx := tq^.texpr; + if tx^.tt <> ninteger then + begin + usemax := true; + eexpr(tx); + write(', Max('); + eexpr(tx); + write(' - 7, 1), ') + end; + eexpr(tq^.texpl) + end; + 'f': + begin + write(', '); + tx := tq^.texpl; + if tx^.texpr^.tt <> ninteger then + begin + eexpr(tx^.texpr); + write(', ') + end; + if (tx^.texpr^.tt <> ninteger) or + (tq^.texpr^.tt <> ninteger) then + begin + usemax := true; + write('Max(('); + eexpr(tx^.texpr); + write(') - ('); + eexpr(tq^.texpr); + write(') - 1, 1), ') + end; + eexpr(tq^.texpl^.texpl) + end; + 'g': + begin + write(', '); + eexpr(tq) + end; + 's': + begin + if tq^.tt = nformat then + begin + if tq^.texpr^.tt <> ninteger then + begin + write(', '); + eexpr(tq^.texpr); + write(', '); + eexpr(tq^.texpr) + end; + write(', '); + eexpr(tq^.texpl) + end + else if tq^.tt <> nstring then + begin + write(', '); + eexpr(tq) + end + end + end (* case *) + end; (* ewrite *) + + (* Emit size of *tp for call to malloc. CPU *) + (* There is no safe way to compute the size of a *) + (* particular variant of a C-union, we assume that *) + (* the size can be computed by taking the address *) + (* of the first member and subracting the address *) + (* of the record and then adding the size of the *) + (* variant containing the record. *) + procedure enewsize(tp : treeptr); + + label 555; + + var tq, tx, ty : treeptr; + v : integer; + + (* Emit size of union member tq. *) + procedure esubsize(tp, tq : treeptr); + + label 555, 666; + + var tx, ty : treeptr; + addsize : boolean; + + begin + tx := tq^.tvrnt; + ty := tx^.tflist; + if ty = nil then + begin + ty := tx^.tvlist; + while ty <> nil do + begin + if ty^.tvrnt^.tflist <> nil then + begin + ty := ty^.tvrnt^.tflist; + goto 555 + end; + ty := ty^.tnext + end; + 555: + end; + addsize := true; + if ty = nil then + begin + (* empty variant, try using another *) + addsize := false; + ty := tx^.tup^.tup^.tvlist; + while ty <> nil do + begin + if ty^.tvrnt^.tflist <> nil then + begin + ty := ty^.tvrnt^.tflist; + goto 666 + end; + ty := ty^.tnext + end; + 666: + end; + if ty = nil then + begin + (* its getting too complicated, + ignore tag value *) + write('sizeof(*'); + eexpr(tp); + write(')') + end + else begin + (* compute offset to first member of + the selected union variant *) + write('Unionoffs('); + eexpr(tp); + write(', '); + printid(ty^.tidl^.tsym^.lid); + if addsize then + begin + (* add the size of the selected + union variant *) + write(') + sizeof('); + eexpr(tp); + write('->'); + printid(tx^.tuid) + end; + write(')') + end + end; + + begin (* newsize *) + if (tp^.tnext <> nil) and unionnew then + begin + (* tnext points to a tag-value, evaluate it *) + v := cvalof(tp^.tnext); + (* find union type *) + tq := typeof(tp); + tq := typeof(tq^.tptrid); + if tq^.tt <> nrecord then + fatal(etree); + (* find corresponding variant *) + tx := tq^.tvlist; + while tx <> nil do + begin + ty := tx^.tselct; + while ty <> nil do + begin + if v = cvalof(ty) then + goto 555; + ty := ty^.tnext + end; + tx := tx^.tnext + end; + fatal(etag); + 555: + (* emit size for that variant *) + esubsize(tp, tx) + end + else begin + write('sizeof(*'); + eexpr(tp); + write(')') + end + end; (* newsize *) + + begin (* epredef *) + td := ts^.tsubstmt^.tdef; + case td of + dabs: + begin + tq := typeof(tp^.taparm); + if (tq = typnods[tinteger]) or (tq^.tt = nsubrange) then + write('abs(') (* LIB *) + else + write('fabs('); (* LIB *) + eexpr(tp^.taparm); + write(')') + end; + dargv: + begin + write('Argvgt('); + eexpr(tp^.taparm); + write(', '); + eexpr(tp^.taparm^.tnext); + write('.A, sizeof('); + eexpr(tp^.taparm^.tnext); + writeln('.A));') + end; + dchr: + begin + tq := typeof(tp^.taparm); + if tq^.tt = nsubrange then + if tq^.tup^.tt = nconfarr then + tq := typeof(tq^.tup^.tindtyp) + else + tq := typeof(tq^.tlo); + if (tq = typnods[tinteger]) or + (tq = typnods[tchar]) then + eexpr(tp^.taparm) + else begin + write('(char)('); + eexpr(tp^.taparm); + write(')') + end + end; + ddispose: + begin + write('free('); (* LIB *) + eexpr(tp^.taparm); + writeln(');') + end; + deof: + begin + write('Eof('); + if tp^.taparm = nil then + begin + defnams[dinput]^.lused := true; + printid(defnams[dinput]^.lid) + end + else + eexpr(tp^.taparm); + write(')') + end; + deoln: + begin + write('Eoln('); + if tp^.taparm = nil then + begin + defnams[dinput]^.lused := true; + printid(defnams[dinput]^.lid) + end + else + eexpr(tp^.taparm); + write(')'); + end; + dexit: + begin + write('exit('); (* OS *) + if tp^.taparm = nil then + write('0') + else + eexpr(tp^.taparm); + writeln(');'); + end; + dflush: + begin + write('fflush('); (* LIB *) + if tp^.taparm = nil then + begin + defnams[doutput]^.lused := true; + printid(defnams[doutput]^.lid) + end + else + eexpr(tp^.taparm); + writeln('.fp);') + end; + dpage: + begin + (* write form-feed character *) + write('Putchr(', ffchr, ', '); (* CHAR *) + if tp^.taparm = nil then + begin + defnams[doutput]^.lused := true; + printid(defnams[doutput]^.lid) + end + else + eexpr(tp^.taparm); + writeln(');'); + end; + dput, + dget: + begin + if typeof(tp^.taparm) = typnods[ttext] then + if td = dget then + write('Getx') + else + write('Putx') + else begin + write(voidcast); + if td = dget then + write('Get') + else + write('Put') + end; + write('('); + eexpr(tp^.taparm); + writeln(');') + end; + dhalt: + writeln('abort();'); (* OS *) + dnew: + begin + eexpr(tp^.taparm); + write(' = ('); + etypedef(typeof(tp^.taparm)); + write(')malloc((unsigned)('); (* LIB *) + enewsize(tp^.taparm); + writeln('));') + end; + dord: + begin + write('(unsigned)('); + eexpr(tp^.taparm); + write(')') + end; + dread, + dreadln: + begin + txtfile := false; + tq := tp^.taparm; + if tq <> nil then + begin + tv := typeof(tq); + if tv = typnods[ttext] then + begin + (* reading from textfile *) + txtfile := true; + tv := tq; + tq := tq^.tnext + end + else if tv^.tt = nfileof then + begin + (* reading from other file *) + txtfile := typeof(tv^.tof) = + typnods[tchar]; + tv := tq; + tq := tq^.tnext + end + else begin + (* reading from std-input *) + txtfile := true; + tv := nil + end + end + else begin + tv := nil; + txtfile := true + end; + if txtfile then + begin + (* check for special case *) + if tq = nil then + goto 444; + if (tq^.tt <> nformat) and + (tq^.tnext = nil) and + (typeletter(tq) = 'c') then + begin + (* read single char *) + eexpr(tq); + write(' = '); + write('Getchr('); + if tv = nil then + printid(defnams[dinput]^.lid) + else + eexpr(tv); + write(')'); + if td = dreadln then + write(','); + goto 444 + end; + usescan := true; + write('Fscan('); + if tv = nil then + printid(defnams[dinput]^.lid) + else + eexpr(tv); + write('), '); + (* first pass, emit format string *) + while tq <> nil do + begin + write('Scan(', cite); + ch := typeletter(tq); + case ch of + 'a': + write(percent, 's'); + 'c': + write(percent, 'c'); + 'd': + write(percent, 'ld'); + 'g': + write(percent, 'le') + end;(* case *) + write(cite, ', '); + case ch of + 'a': + begin + eexpr(tq); + write('.A') + end; + 'c': + begin + write('&'); + eexpr(tq) + end; + 'd': + write('&Tmplng'); + 'g': + write('&Tmpdbl') + end;(* case *) + write(')'); + case ch of + 'd': + begin + write(', '); + eexpr(tq); + write(' = Tmplng') + end; + 'g': + begin + write(', '); + eexpr(tq); + write(' = Tmpdbl') + end; + 'a', + 'c': + (* no op *) + end;(* case *) + tq := tq^.tnext; + if tq <> nil then + begin + writeln(','); + indent; + write(tab1) + end + end; + write(', Getx('); + if tv = nil then + printid(defnams[dinput]^.lid) + else + eexpr(tv); + write(')'); + if td = dreadln then + write(','); + 444: + if td = dreadln then + begin + usegetl := true; + write('Getl(&'); + if tv = nil then + printid(defnams[dinput]^.lid) + else + eexpr(tv); + write(')') + end + end + else begin + increment; + while tq <> nil do + begin + write(voidcast, 'Fread('); + eexpr(tq); + write(', '); + eexpr(tv); + write('.fp)'); + tq := tq^.tnext; + if tq <> nil then + begin + writeln(','); + indent + end + end; + decrement + end; + writeln(';') + end; + dwrite, + dwriteln, + dmessage: + begin + txtfile := false; + tq := tp^.taparm; + if tq <> nil then + begin + tv := typeof(tq); + if tv = typnods[ttext] then + begin + (* writing to textfile *) + txtfile := true; + tv := tq; + tq := tq^.tnext + end + else if tv^.tt = nfileof then + begin + (* writing to other file *) + txtfile := typeof(tv^.tof) = + typnods[tchar]; + tv := tq; + tq := tq^.tnext + end + else begin + (* writing to std-output *) + txtfile := true; + tv := nil + end + end + else begin + tv := nil; + txtfile := true + end; + if txtfile then + begin + (* check for special case *) + if tq = nil then + begin + (* writeln whithout parameters *) + if td in [dwriteln, dmessage] then + begin + write('Putchr(', nlchr, ', '); + if tv = nil then + printid( + defnams[doutput]^.lid) + else + eexpr(tv); + write(')') + end; + writeln(';'); + goto 555 + end + else if (tq^.tt <> nformat) and + (tq^.tnext = nil) then + if typeletter(tq) = 'c' then + begin + (* print single char *) + write('Putchr('); + eexpr(tq); + write(', '); + if tv = nil then + printid( + defnams[doutput]^.lid) + else + eexpr(tv); + write(')'); + if td = dwriteln then + begin + write(',Putchr(', + nlchr, ', '); + if tv = nil then + printid( + defnams[doutput]^.lid) + else + eexpr(tv); + write(')'); + end; + writeln(';'); + goto 555 + end; + tx := nil; + write(voidcast, 'fprintf('); (* LIB *) + if td = dmessage then + write('stderr, ') + else begin + if tv = nil then + printid(defnams[doutput]^.lid) + else + eexpr(tv); + write('.fp, ') + end; + write(cite); + tx := tq; (* remember 1:st parm *) + (* first pass, emit format string *) + while tq <> nil do + begin + eformat(tq); + tq := tq^.tnext + end; + if (td = dmessage) or (td = dwriteln) then + write('\n'); + write(cite); + (* second pass, add parameters *) + tq := tx; + while tq <> nil do + begin + ewrite(tq); + tq := tq^.tnext + end; + write('), Putl('); + if tv = nil then + printid(defnams[doutput]^.lid) + else + eexpr(tv); + if td = dwrite then + write(', 0)') + else + write(', 1)') + end + else begin + increment; + tx := typeof(tv); + if tx = typnods[ttext] then + tx := typnods[tchar] + else if tx^.tt = nfileof then + tx := typeof(tx^.tof) + else + fatal(etree); + while tq <> nil do + begin + if (tq^.tt in [nid, nindex, nselect, + nderef]) and + (tx = typeof(tq)) then + begin + write(voidcast, 'Fwrite('); + eexpr(tq) + end + else begin + if tx^.tt = nsetof then + begin + usescpy := true; + write('Setncpy('); + eselect(tv); + write('buf.S, '); + eexpr(tq); + if typeof(tp^.trhs) = + typnods[tset] then + eexpr(tq) + else begin + eselect(tq); + write('S') + end; + write(', sizeof('); + eexpr(tv); + write('.buf))'); + end + else begin + eexpr(tv); + write('.buf = '); + eexpr(tq) + end; + write(', Fwrite('); + eexpr(tv); + write('.buf'); + end; + write(', '); + eexpr(tv); + write('.fp)'); + tq := tq^.tnext; + if tq <> nil then + begin + writeln(','); + indent + end + end; + decrement + end; + writeln(';'); + 555: + end; + dclose: + begin + tq := typeof(tp^.taparm); + txtfile := tq = typnods[ttext]; + if (not txtfile) and (tq^.tt = nfileof) then + if typeof(tq^.tof) = typnods[tchar] then + txtfile := true; + if txtfile then + write('Closex(') + else + write('Close('); + eexpr(tp^.taparm); + writeln(');'); + end; + dreset, + drewrite: + begin + tq := typeof(tp^.taparm); + txtfile := tq = typnods[ttext]; + if (not txtfile) and (tq^.tt = nfileof) then + if typeof(tq^.tof) = typnods[tchar] then + txtfile := true; + if txtfile then + if td = dreset then + write('Resetx(') + else + write('Rewritex(') + else + if td = dreset then + write('Reset(') + else + write('Rewrite('); + eexpr(tp^.taparm); + write(', '); + tq := tp^.taparm^.tnext; + if tq = nil then + write('NULL') + else begin + tq := typeof(tq); + if tq = typnods[tchar] then + begin + write(cite); + ch := chr(cvalof(tp^.taparm^.tnext)); + if (ch = bslash) or (ch = cite) then + write(bslash); + write(ch, cite) + end + else if tq = typnods[tstring] then + eexpr(tp^.taparm^.tnext) + else if tq^.tt in [narray, nconfarr] then + begin + eexpr(tp^.taparm^.tnext); + write('.A') + end + else + fatal(etree) + end; + writeln(');') + end; + darctan: + begin + write('atan('); (* LIB *) + if typeof(tp^.taparm) <> typnods[treal] then + write(dblcast); + eexpr(tp^.taparm); + write(')') + end; + dln: + begin + write('log('); (* LIB *) + if typeof(tp^.taparm) <> typnods[treal] then + write(dblcast); + eexpr(tp^.taparm); + write(')') + end; + dexp: + begin + write('exp('); (* LIB *) + if typeof(tp^.taparm) <> typnods[treal] then + write(dblcast); + eexpr(tp^.taparm); + write(')') + end; + dcos, + dsin, + dsqrt: + begin + eexpr(tp^.tcall); (* LIB *) + write('('); + if typeof(tp^.taparm) <> typnods[treal] then + write(dblcast); + eexpr(tp^.taparm); + write(')') + end; + dtan: + begin + write('atan('); (* LIB *) + if typeof(tp^.taparm) <> typnods[treal] then + write(dblcast); + eexpr(tp^.taparm); + write(')') + end; + dsucc, + dpred: + begin + tq := typeof(tp^.taparm); + if tq^.tt = nsubrange then + if tq^.tup^.tt = nconfarr then + tq := typeof(tq^.tup^.tindtyp) + else + tq := typeof(tq^.tlo); + if (tq = typnods[tinteger]) or + (tq = typnods[tchar]) then + begin + write('(('); + eexpr(tp^.taparm); + if td = dpred then + write(')-1)') + else + write(')+1)') + end + else begin + (* some sort of scalar type, casting needed *) + write('('); + tq := tq^.tup; + if tq^.tt = ntype then + begin + (* cast only if it is a named type *) + write('('); + printid(tq^.tidl^.tsym^.lid); + write(')') + end; + write('((int)('); + eexpr(tp^.taparm); + if td = dpred then + write(')-1))') + else + write(')+1))') + end + end; + dodd: + begin + write('('); + printid(defnams[dboolean]^.lid); + write(')(('); + eexpr(tp^.taparm); + write(') & 1)') + end; + dsqr: + begin + tq := typeof(tp^.taparm); + if (tq = typnods[tinteger]) or (tq^.tt = nsubrange) then + begin + write('(('); + eexpr(tp^.taparm); + write(') * ('); + eexpr(tp^.taparm); + write('))') + end + else begin + write('pow('); (* LIB *) + if typeof(tp^.taparm) <> typnods[treal] then + write(dblcast); + eexpr(tp^.taparm); + write(', 2.0)') + end + end; + dround: + begin + write('Round('); + eexpr(tp^.taparm); + write(')') + end; + dtrunc: + begin + write('Trunc('); + eexpr(tp^.taparm); + write(')') + end; + dpack: + begin + tq := typeof(tp^.taparm); + tx := typeof(tp^.taparm^.tnext^.tnext); + write('{ ', registr, inttyp, tab1, '_j, _i = '); + if not arithexpr(tp^.taparm^.tnext) then + write('(int)'); + eexpr(tp^.taparm^.tnext); + if tx^.tt = narray then + write(' - ', clower(tq^.taindx):1); + writeln(';'); + indent; + write(' for (_j = 0; _j < '); + if tq^.tt = nconfarr then + begin + write('(int)('); + printid(tx^.tcindx^.thi^.tsym^.lid); + write(')') + end + else + write(crange(tx^.taindx):1); + writeln('; )'); + indent; + write(tab1); + eexpr(tp^.taparm^.tnext^.tnext); + write('.A[_j++] = '); + eexpr(tp^.taparm); + writeln('.A[_i++];'); + indent; + writeln('}') + end; + dunpack: + begin + tq := typeof(tp^.taparm); + tx := typeof(tp^.taparm^.tnext); + write('{ ', registr, inttyp, tab1, '_j, _i = '); + if not arithexpr(tp^.taparm^.tnext^.tnext) then + write('(int)'); + eexpr(tp^.taparm^.tnext^.tnext); + if tx^.tt <> nconfarr then + write(' - ', clower(tx^.taindx):1); + writeln(';'); + indent; + write(' for (_j = 0; _j < '); + if tq^.tt = nconfarr then + begin + write('(int)('); + printid(tq^.tcindx^.thi^.tsym^.lid); + write(')') + end + else + write(crange(tq^.taindx):1); + writeln('; )'); + indent; + write(tab1); + eexpr(tp^.taparm^.tnext); + write('.A[_i++] = '); + eexpr(tp^.taparm); + writeln('.A[_j++];'); + indent; + writeln('}') + end; + end (* case *) + end; (* epredef *) + + procedure eaddr(tp : treeptr); + + begin + write('&'); + if not(tp^.tt in [nid, nselect, nindex, nderef]) then + error(evarpar); + eexpr(tp) + end; + + (* Emit code for a subroutine call. *) + procedure ecall(tp : treeptr); + + var tf, tq, tx : treeptr; + + begin + (* find first formal parameter id *) + tf := idup(tp^.tcall); + case tf^.tt of + nproc, + nfunc: + tf := tf^.tsubpar; + nparproc, + nparfunc: + tf := tf^.tparparm + end;(* case *) + if tf <> nil then + begin + case tf^.tt of + nvalpar, + nvarpar: + tf := tf^.tidl; + nparproc, + nparfunc: + tf := tf^.tparid + end (* case *) + end; + (* emit called function name *) + eexpr(tp^.tcall); + write('('); + (* emit actual parameters *) + tq := tp^.taparm; + while tq <> nil do + begin + if tf^.tup^.tt in [nparfunc, nparproc] then + begin + (* single subroutine-nid converted to ncall *) + if tq^.tt = ncall then + printid(tq^.tcall^.tsym^.lid) + else + printid(tq^.tsym^.lid) + end + else begin + tx := typeof(tq); + if tx = typnods[tboolean] then + begin + tx := tq; + while tx^.tt = nuplus do + tx := tx^.texps; + if tx^.tt in [nin .. nor, nand, nnot] + then + begin + write('('); + printid(defnams[dboolean]^.lid); + write(')('); + eexpr(tq); + write(')') + end + else + eexpr(tq); + end + else if (tx = typnods[tstring]) or + (tx = typnods[tset]) then + begin + (* cast literal to proper type *) + write('*(('); + etypedef(tf^.tup^.tbind); + write(' *)'); + if tx = typnods[tset] then + begin + dropset := true; + eexpr(tq); + dropset := false + end + else + eexpr(tq); + write(')') + end + else if tx = typnods[tnil] then + begin + write('('); + etypedef(tf^.tup^.tbind); + write(')NIL') + end + else if tf^.tup^.tbind^.tt = nconfarr then + begin + write('(struct '); + printid(tf^.tup^.tbind^.tcuid); + write(' *)&'); + eexpr(tq); + (* add upper bound of actual value *) + if tq^.tnext = nil then + write(', ', + crange(tx^.taindx):1) + end + else begin + if tf^.tup^.tt = nvarpar then + eaddr(tq) + else + eexpr(tq) + end + end; + tq := tq^.tnext; + if tq <> nil then + begin + write(', '); + (* next formal parameter *) + if tf^.tnext = nil then + begin + tf := tf^.tup^.tnext; + case tf^.tt of + nvalpar, + nvarpar: + tf := tf^.tidl; + nparproc, + nparfunc: + tf := tf^.tparid + end (* case *) + end + else + tf := tf^.tnext; + end; + end; + write(')') + end; (* ecall *) + + (* Emit code for a general expression. *) + procedure eexpr; + + label 999; + + var tq : treeptr; + flag : boolean; + + function constset(tp : treeptr) : boolean; + + function constxps(tp : treeptr) : boolean; + begin + case tp^.tt of + nrange: + if constxps(tp^.texpr) then + constxps := constxps(tp^.texpl) + else + constxps := false; + nempty, + ninteger, + nchar: + constxps := true; + nid: + begin + tp := idup(tp); + constxps := (tp^.tt = nconst) + or (tp^.tt = nscalar) + end; + nin, neq, nne, nlt, nle, ngt, nge, nor, + nplus, nminus, nand, nmul, ndiv, nmod, + nquot, nnot, numinus, nuplus, nset, + nindex, nselect, nderef, ncall, + nreal, nstring, nnil: + constxps := false + end (* case *) + end; + + begin + constset := true; + while tp <> nil do + if constxps(tp) then + tp := tp^.tnext + else begin + constset := false; + tp := nil + end + end; + + begin (* eexpr *) + donearr := false; + if tp^.tt in [nplus, nminus, nmul, nle, nge, neq, nne] then + begin + tq := typeof(tp^.texpl); + if (tq^.tt in [nset, nsetof]) or + (tq = typnods[tset]) then + begin + (* set operations *) + case tp^.tt of + nplus: + begin + setused := true; + useunion := true; + write('Union') + end; + nminus: + begin + setused := true; + usediff := true; + write('Diff') + end; + nmul: + begin + setused := true; + useintr := true; + write('Inter') + end; + neq: + begin + useseq := true; + write('Eq') + end; + nne: + begin + usesne := true; + write('Ne') + end; + nge: + begin + usesge := true; + write('Ge') + end; + nle: + begin + usesle := true; + write('Le') + end + end;(* case *) + if tp^.tt in [nplus, nminus, nmul] then + dropset := false; + write('('); + eexpr(tp^.texpl); + if tq^.tt = nsetof then + write('.S'); + write(', '); + eexpr(tp^.texpr); + tq := typeof(tp^.texpr); + if tq^.tt = nsetof then + write('.S'); + write(')'); + goto 999 + end + end; + if tp^.tt in [neq, nne, ngt, nlt, nge, nle] then + begin + tq := typeof(tp^.texpl); + if tq^.tt = nconfarr then + fatal(ecmpconf); + if (tq^.tt in [nstring, narray]) or + (tq = typnods[tstring]) then + begin + write('Cmpstr('); + eexpr(tp^.texpl); + if tq^.tt = narray then + write('.A'); + write(', '); + tq := typeof(tp^.texpr); + if tq^.tt = nconfarr then + fatal(ecmpconf); + eexpr(tp^.texpr); + if tq^.tt = narray then + write('.A'); + write(')'); + case tp^.tt of + neq: + write(' == '); + nne: + write(' != '); + ngt: + write(' > '); + nlt: + write(' < '); + nge: + write(' >= '); + nle: + write(' <= '); + end;(* case *) + write('0'); + goto 999 + end + end; + case tp^.tt of + neq, nne, nlt, nle, + ngt, nge, nor, nand, nplus, nminus, + nmul, ndiv, nmod, nquot: + begin + flag := cprio[tp^.tt] > cprio[tp^.texpl^.tt]; + if (tp^.tt in [nlt, nle, ngt, nge]) and + not arithexpr(tp^.texpl) then + begin + write('(int)'); + flag := true + end; + if flag then + write('('); + eexpr(tp^.texpl); + if flag then + write(')'); + case tp^.tt of + neq: + write(' == '); + nne: + write(' != '); + nlt: + write(' < '); + nle: + write(' <= '); + ngt: + write(' > '); + nge: + write(' >= '); + nor: + write(' || '); + nand: + write(' && '); + nplus: + write(' + '); + nminus: + write(' - '); + nmul: + write(' * '); + ndiv: + write(' / '); + nmod: + write(' % '); + nquot: + begin + write(' / (('); + printid(defnams[dreal]^.lid); + write(')') + end + end;(* case *) + flag := cprio[tp^.tt] > cprio[tp^.texpr^.tt]; + if (tp^.tt in [nlt, nle, ngt, nge]) and + not arithexpr(tp^.texpr) then + begin + write('(int)'); + flag := true + end; + if flag then + write('('); + eexpr(tp^.texpr); + if flag then + write(')'); + if tp^.tt = nquot then + write(')') + end; + + nuplus, numinus, nnot: + begin + case tp^.tt of + numinus: + write('-'); + nnot: + write('!'); + nuplus: + end;(* case *) + flag := cprio[tp^.tt] >= cprio[tp^.texps^.tt]; + if flag then + write('('); + eexpr(tp^.texps); + if flag then + write(')'); + end; + + nin: + begin + usememb := true; + write('Member((unsigned)('); + eexpr(tp^.texpl); + write('), '); + dropset := true; (* no need to save set-expr *) + eexpr(tp^.texpr); + dropset := false; + tq := typeof(tp^.texpr); + if tq^.tt = nsetof then + write('.S'); + write(')') + end; + + nassign: + begin + tq := typeof(tp^.trhs); + if tq = typnods[tstring] then + begin + write(voidcast, 'strncpy('); + eexpr(tp^.tlhs); + write('.A, '); + eexpr(tp^.trhs); + write(', sizeof('); + eexpr(tp^.tlhs); + write('.A))') + end + else if tq = typnods[tboolean] then + begin + eexpr(tp^.tlhs); + write(' = '); + tq := tp^.trhs; + while tq^.tt = nuplus do + tq := tq^.texps; + if tq^.tt in [nin .. nor, nand, nnot] then + begin + write('('); + printid(defnams[dboolean]^.lid); + write(')('); + eexpr(tq); + write(')') + end + else + eexpr(tq) + end + else if tq = typnods[tnil] then + begin + eexpr(tp^.tlhs); + write(' = ('); + etypedef(typeof(tp^.tlhs)); + write(')NIL') + end + else begin + tq := typeof(tp^.tlhs); + if tq^.tt = nsetof then + begin + usescpy := true; + write('Setncpy('); + eselect(tp^.tlhs); + write('S, '); + dropset := true; + tq := typeof(tp^.trhs); + if tq = typnods[tset] then + eexpr(tp^.trhs) + else begin + eselect(tp^.trhs); + write('S') + end; + dropset := false; + write(', sizeof('); + eselect(tp^.tlhs); + write('S))') + end + else begin + eexpr(tp^.tlhs); + write(' = '); + eexpr(tp^.trhs) + end + end + end; + + ncall: + begin + tq := idup(tp^.tcall); + if (tq^.tt in [nfunc, nproc]) and + (tq^.tsubstmt <> nil) then + if tq^.tsubstmt^.tt = npredef then + epredef(tq, tp) + else + ecall(tp) + else + ecall(tp) + end; + + nselect: + begin + eselect(tp^.trecord); + eexpr(tp^.tfield) + end; + nindex: + begin + eselect(tp^.tvariable); + write('A['); + tq := tp^.toffset; + if arithexpr(tq) then + eexpr(tq) + else begin + write('(int)('); + eexpr(tq); + write(')') + end; + tq := typeof(tp^.tvariable); + if tq^.tt = narray then + if clower(tq^.taindx) <> 0 then + begin + write(' - '); + tq := typeof(tq^.taindx); + if tq^.tt = nsubrange then + if arithexpr(tq^.tlo) then + eexpr(tq^.tlo) + else begin + write('(int)('); + eexpr(tq^.tlo); + write(')') + end + else + fatal(etree) + end; + write(']') + end; + nderef: + begin + tq := typeof(tp^.texps); + if (tq^.tt = nfileof) or + ((tq^.tt = npredef) and (tq^.tdef = dtext)) then + begin + (* using a file-variable as pointer *) + eexpr(tp^.texps); + write('.buf') + end + else if doarrow = 0 then + begin + write('*'); + eexpr(tp^.texps) + end + else begin + eexpr(tp^.texps); + write('->'); + donearr := true + end + end; + nid: + begin + (* add pointer-dereference if this id is declared as a + var-parameter or as a procedure-parameter *) + tq := idup(tp); + if tq^.tt = nvarpar then + begin + if (doarrow = 0) or + (tq^.tattr = areference) then + begin + write('(*'); + printid(tp^.tsym^.lid); + write(')') + end + else begin + printid(tp^.tsym^.lid); + write('->'); + donearr := true + end + end + else if (tq^.tt = nconst) and conflag then + write(cvalof(tp):1) + else if tq^.tt in [nparproc, nparfunc] then + begin + write('(*'); + printid(tp^.tsym^.lid); + write(')') + end + else + printid(tp^.tsym^.lid); + end; + nchar: + printchr(tp^.tsym^.lchar); + ninteger: + write(tp^.tsym^.linum:1); + nreal: + printtok(tp^.tsym^.lfloat); + nstring: + printstr(tp^.tsym^.lstr); + nset: + if constset(tp^.texps) then + begin + (* save set expression for initialization *) + write('Conset[', setcnt:1, ']'); + setcnt := setcnt + 1; + tq := mknode(nset); + tq^.tnext := setlst; + setlst := tq; + tq^.texps := tp^.texps + end + else begin + increment; + flag := dropset; + (* if a set-constructor is used in an + expression involving + - * it will need to + be saved temporarily (by Saveset) but often + we can simply forget the set-value when we + have finished using it *) + if dropset then + dropset := false + else + write('Saveset('); + write('(Tmpset = Newset(), '); + tq := tp^.texps; + while tq <> nil do + begin + case tq^.tt of + nrange: + begin + usemksub := true; + write(voidcast, 'Mksubr('); + write('(unsigned)('); + eexpr(tq^.texpl); + write('), '); + write('(unsigned)('); + eexpr(tq^.texpr); + write('), Tmpset)') + end; + nin, neq, nne, nlt, nle, ngt, nge, + nor, nand, nmul, ndiv, nmod, nquot, + nplus, nminus, nnot, numinus, nuplus, + nindex, nselect, nderef, ncall, + ninteger, nchar, nid: + begin + useins := true; + write(voidcast, 'Insmem('); + write('(unsigned)('); + eexpr(tq); + write('), Tmpset)') + end + end;(* case *) + tq := tq^.tnext; + if tq <> nil then + begin + writeln(','); + indent + end + end; + write(', Tmpset)'); + if not flag then + begin + write(')'); + setused := true + end; + decrement + end; + nnil: + begin + tq := tp; + repeat + tq := tq^.tup + until tq^.tt in [neq, nne, ncall, nassign, npgm]; + if tq^.tt in [neq, nne] then + begin + if typeof(tq^.texpl) = typnods[tnil] then + tq := typeof(tq^.texpr) + else + tq := typeof(tq^.texpl); + if tq^.tt = nptr then + begin + write('('); + etypedef(tq); + write(')') + end + end; + write('NIL') + end; + end;(* case *) + 999: + end; (* eexpr *) + + (* Emit constant definitions. *) + procedure econst(tp : treeptr); + + var sp : symptr; + + begin + while tp <> nil do + begin + sp := tp^.tidl^.tsym; + if sp^.lid^.inref > 1 then + sp^.lid := mkrename('X', sp^.lid); + if tp^.tbind^.tt = nstring then + begin + (* string constants emitted as + static local variables *) + indent; + write(static, chartyp, tab1); + printid(sp^.lid); + write('[] = '); + eexpr(tp^.tbind); + writeln(';') + end + else begin + (* all other constants emitted as + preprocessor # defines *) + write(define); + printid(sp^.lid); + write(space); + eexpr(tp^.tbind); + writeln + end; + tp := tp^.tnext + end + end; (* econst *) + + (* Emit a typedef. *) + procedure etypedef; + + (* Workhorse for etypedef, this procedure also *) + (* renames all fields in record-unions when *) + (* necessary. *) + procedure etdef(uid : idptr; tp : treeptr); + + var i : integer; + tq : treeptr; + + (* Emit definition for an integer subrange *) + (* using data from worddefs set up during *) + (* initialization. *) + procedure etrange(tp : treeptr); + + label 999; + + var lo, hi : integer; + i : 1 .. maxmachdefs; + + begin + lo := clower(tp); + hi := cupper(tp); + (* scan CPU word definitions for a type + enclosing wanted range *) + for i := 1 to nmachdefs do + with machdefs[i] do + if (lo >= lolim) and (hi <= hilim) then + begin + (* found it, print type name *) + printtok(typstr); + goto 999 + end; + fatal(erange); + 999: + end; + + (* Print last component of identifier. *) + procedure printsuf(ip : idptr); + + var w : toknbuf; + i, j : toknidx; + + begin + gettokn(ip^.istr, w); + i := 1; + j := i; + while w[i] <> chr(null) do + begin + if w[i] = '.' then + j := i; + i := i + 1 + end; + if w[j] = '.' then + j := j + 1; + while w[j] <> chr(null) do + begin + write(w[j]); + j := j + 1 + end + end; + + begin (* etdef *) + case tp^.tt of + nid: + printid(tp^.tsym^.lid); + nptr: + begin + tq := typeof(tp^.tptrid); + if tq^.tt = nrecord then + begin + write('struct '); + printid(tq^.tuid) + end + else + printid(tp^.tptrid^.tsym^.lid); + write(' *'); + end; + nscalar: + begin + write('enum { '); + increment; + tp := tp^.tscalid; + + (* avoid bug in C-compiler: + enums are mixed in same namespace *) + if tp^.tsym^.lid^.inref > 1 then + tp^.tsym^.lid := + mkrename('E', tp^.tsym^.lid); + printid(tp^.tsym^.lid); + i := 1; + while tp^.tnext <> nil do + begin + if i >= 4 then + begin + writeln(','); + indent; + i := 1 + end + else begin + write(', '); + i := i + 1 + end; + tp := tp^.tnext; + if tp^.tsym^.lid^.inref > 1 then + tp^.tsym^.lid := + mkrename('E', tp^.tsym^.lid); + printid(tp^.tsym^.lid) + end; + decrement; + write(' } ') + end; + nsubrange: + begin + tq := typeof(tp^.tlo); + if tq = typnods[tinteger] then + etrange(tp) + else begin + if tq^.tup^.tt = ntype then + tq := tq^.tup^.tidl; + etdef(nil, tq) + end + end; + nfield: + begin + etdef(nil, tp^.tbind); + write(tab1); + tp := tp^.tidl; + if uid <> nil then + tp^.tsym^.lid := + mkconc('.', uid, tp^.tsym^.lid); + printsuf(tp^.tsym^.lid); + i := 1; + while tp^.tnext <> nil do + begin + if i >= 4 then + begin + writeln(','); + indent; + write(tab1); + i := 1 + end + else begin + write(', '); + i := i + 1 + end; + tp := tp^.tnext; + if uid <> nil then + tp^.tsym^.lid := + mkconc('.', uid, tp^.tsym^.lid); + printsuf(tp^.tsym^.lid); + end; + writeln(';'); + end; + nrecord: + begin + write('struct '); + if tp^.tuid = nil then + tp^.tuid := uid + else if uid = nil then + printid(tp^.tuid); + writeln(' {'); + increment; + if (tp^.tflist = nil) and + (tp^.tvlist = nil) then + begin + (* C doesn't allow empty structures *) + indent; + writeln(inttyp, tab1, 'dummy;') + end; + tq := tp^.tflist; + while tq <> nil do + begin + indent; + etdef(uid, tq); + tq := tq^.tnext + end; + if tp^.tvlist <> nil then + begin + indent; + writeln('union {'); + increment; + tq := tp^.tvlist; + while tq <> nil do + begin + if (tq^.tvrnt^.tflist <> nil) or + (tq^.tvrnt^.tvlist <> nil) then + begin + indent; + if uid = nil then + etdef(mkvrnt, + tq^.tvrnt) + else + etdef(mkconc('.', + uid, mkvrnt), + tq^.tvrnt); + writeln(';') + end; + tq := tq^.tnext + end; + decrement; + indent; + writeln('} U;'); + end; + decrement; + indent; + if tp^.tup^.tt = nvariant then + begin + write('} '); + printsuf(tp^.tuid) + end + else + write('}'); + end; + nconfarr: + begin + write('struct '); + printid(tp^.tcuid); + write(' { '); + etdef(nil, tp^.tcelem); + write(tab1, 'A[]; }') + end; + narray: + begin + write('struct { '); + etdef(nil, tp^.taelem); + write(tab1, 'A['); + tq := typeof(tp^.taindx); + if tq^.tt = nsubrange then + begin + if arithexpr(tq^.thi) then + begin + eexpr(tq^.thi); + if cvalof(tq^.tlo) <> 0 then + begin + write(' - '); + eexpr(tq^.tlo) + end + end + else begin + write('(int)('); + eexpr(tq^.thi); + if cvalof(tq^.tlo) <> 0 then + begin + write(') - (int)('); + eexpr(tq^.tlo) + end; + write(')') + end; + write(' + 1') + end + else + write(crange(tp^.taindx):1); + write(']; }') + end; + nfileof: + begin + writeln('struct {'); + indent; + writeln(tab1, 'FILE', tab1, '*fp;'); + indent; + writeln(tab1, filebits, tab1, 'eoln:1,'); + indent; + writeln(tab3, 'eof:1,'); + indent; + writeln(tab3, 'out:1,'); + indent; + writeln(tab3, 'init:1,'); + indent; + writeln(tab3, ':', filefill:1, ';'); + indent; + write(tab1); + etdef(nil, tp^.tof); + writeln(tab1, 'buf;'); + indent; + write('} ') + end; + nsetof: + write('struct { ', setwtyp, tab1, 'S[', + csetsize(tp):1, ']; }'); + npredef: + begin + case tp^.tobtyp of + tboolean: + printid(defnams[dboolean]^.lid); + tchar: + write(chartyp); + tinteger: + printid(defnams[dinteger]^.lid); + treal: + printid(defnams[dreal]^.lid); + tstring: + write(chartyp, ' *'); + ttext: + write('text'); + tnil, + tset, + terror: + fatal(etree); + tnone: + write(voidtyp); + end (* case *) + end; + nempty: + write(voidtyp); + end;(* case *) + end; (* etdef *) + begin + etdef(nil, tp) + end; (* etypedef *) + + (* Emit code for type declarations. *) + procedure etype(tp : treeptr); + + var sp : symptr; + + begin + while tp <> nil do + begin + (* if identifier used more than once we rename the type + to avoid typedef'ing an identifier twice *) + sp := tp^.tidl^.tsym; + if sp^.lid^.inref > 1 then + sp^.lid := mkrename('Y', sp^.lid); + indent; + write(typdef); + etypedef(tp^.tbind); + write(tab1); + printid(sp^.lid); + writeln(';'); + tp := tp^.tnext + end + end; + + (* Emit code for variable declarations. *) + procedure evar(tp : treeptr); + + label 555; + + var tq : treeptr; + i : integer; + + begin + while tp <> nil do + begin + indent; + case tp^.tt of + nvar, + nvalpar, + nvarpar: + begin + if tp^.tattr = aregister then + write(registr); + etypedef(tp^.tbind) + end; + nparproc, + nparfunc: + begin + if tp^.tt = nparproc then + write(voidtyp) + else + etypedef(tp^.tpartyp); + tq := tp^.tparid; + write(tab1, '(*'); + printid(tq^.tsym^.lid); + write(')()'); + goto 555 + end + end;(* case *) + write(tab1); + tq := tp^.tidl; + i := 1; + repeat + if tp^.tt = nvarpar then + write('*'); + printid(tq^.tsym^.lid); + tq := tq^.tnext; + if tq <> nil then + begin + if i >= 6 then + begin + i := 1; + writeln(','); + indent; + write(tab1) + end + else begin + i := i + 1; + write(', ') + end + + end + until tq = nil; + 555: + writeln(';'); + if tp^.tt = nvarpar then + if tp^.tbind^.tt = nconfarr then + begin + indent; + etypedef(tp^.tbind^.tindtyp); + write(tab1); + tq := tp^.tbind^.tcindx^.thi; + printid(tq^.tsym^.lid); + writeln(';') + end; + tp := tp^.tnext + end + end; (* evar *) + + (* Emit code for a statment. *) + procedure estmt(tp : treeptr); + + var tq : treeptr; + locid1, + locid2 : idptr; + stusd : boolean; + opc1, + opc2 : char; + + (* Emit typename for with-variable. *) + procedure ewithtype(tp : treeptr); + + var tq : treeptr; + + begin + tq := typeof(tp); + write('struct '); + printid(tq^.tuid) + end; + + (* Emit code for a case-choise. *) + procedure echoise(tp : treeptr); + + var tq : treeptr; + i : integer; + + begin + while tp <> nil do + begin + tq := tp^.tchocon; + i := 0; + indent; + while tq <> nil do + begin + write(' case '); + conflag := true; + eexpr(tq); + conflag := false; + write(':'); + i := i + 1; + tq := tq^.tnext; + if (tq = nil) or (i mod 4 = 0) then + begin + writeln; + if tq <> nil then + indent; + i := 0 + end + end; + increment; + if tp^.tchostmt^.tt = nbegin then + estmt(tp^.tchostmt^.tbegin) + else + estmt(tp^.tchostmt); + indent; + writeln('break ;'); + decrement; + tp := tp^.tnext; + if tp <> nil then + if tp^.tchocon = nil then + tp := nil + end + end; (* echoise *) + + (* Rename all accessible record-fields to include *) + (* pointer name. *) + procedure cenv(ip : idptr; dp : declptr); + + var tp : treeptr; + sp : symptr; + np : idptr; + h : hashtyp; + + begin + with dp^ do + for h := 0 to hashmax - 1 do + begin + sp := ddecl[h]; + while sp <> nil do + begin + if sp^.lt = lfield then + begin + np := sp^.lid; + tp := sp^.lsymdecl^.tup^.tup; + if (tp^.tup^.tt = nvariant) and + (tp^.tuid <> nil) then + np := mkconc('.', + tp^.tuid, np); + np := mkconc('>', ip, np); + sp^.lid := np + end; + sp := sp^.lnext + end + end + end; (* cenv *) + + (* Emit identifiers for push/pop of global ptrs. *) + procedure eglobid(tp : treeptr); + + var j : toknidx; + w : toknbuf; + + begin + gettokn(tp^.tsym^.lid^.istr, w); + j := 1; + if w[1] = '*' then + j := 2; + while w[j] <> chr(null) do + begin + write(w[j]); + j := j + 1 + end + end; + + begin (* estmt *) + while tp <> nil do + begin + case tp^.tt of + nbegin: + begin + if tp^.tup^.tt in [nbegin, nrepeat, + nproc, nfunc, npgm] then + indent; + writeln('{'); + increment; + estmt(tp^.tbegin); + decrement; + indent; + write('}'); + if tp^.tup^.tt <> nif then + writeln + end; + nrepeat: + begin + indent; + writeln('do {'); + increment; + estmt(tp^.treptstmt); + decrement; + indent; + write('} while (!('); + eexpr(tp^.treptxp); + writeln('));') + end; + nwhile: + begin + indent; + write('while ('); + increment; + eexpr(tp^.twhixp); + stusd := setused; + if tp^.twhistmt^.tt = nbegin then + begin + decrement; + write(') '); + estmt(tp^.twhistmt) + end + else begin + writeln(')'); + estmt(tp^.twhistmt); + decrement + end; + setused := stusd or setused + end; + nfor: + begin + indent; + if tp^.tincr then + begin + opc1 := '+'; (* increment variable *) + opc2 := '<' (* test for <= *) + end + else begin + opc1 := '-'; (* decrement variable *) + opc2 := '>'; (* test for >= *) + end; + if not lazyfor then + begin + locid1 := mkvariable('B'); + locid2 := mkvariable('B'); + writeln('{'); + increment; + indent; + tq := idup(tp^.tforid); + etypedef(tq^.tbind); + tq := typeof(tq^.tbind); + write(tab1); + printid(locid1); + write(' = '); + eexpr(tp^.tfrom); + writeln(','); + indent; + write(tab1); + printid(locid2); + write(' = '); + eexpr(tp^.tto); + writeln(';'); + writeln; + indent; + write('if ('); + if tq^.tt = nscalar then + begin + write('(int)('); + printid(locid1); + write(')') + end + else + printid(locid1); + write(' ', opc2, '= '); + if tq^.tt = nscalar then + begin + write('(int)('); + printid(locid2); + write(')') + end + else + printid(locid2); + writeln(')'); + increment; + indent; + tp^.tfrom := newid(locid1); + tp^.tfrom^.tup := tp + end; + write('for ('); + increment; + eexpr(tp^.tforid); + tq := typeof(tp^.tforid); + write(' = '); + eexpr(tp^.tfrom); + write('; '); + if lazyfor then + begin + if tq^.tt = nscalar then + begin + write('(int)('); + eexpr(tp^.tforid); + write(')') + end + else + eexpr(tp^.tforid); + write(' ', opc2, '= '); + if tq^.tt = nscalar then + begin + write('(int)('); + eexpr(tp^.tto); + write(')') + end + else + eexpr(tp^.tto) + end; + write('; '); + eexpr(tp^.tforid); + if tq^.tt = nscalar then + begin + write(' = ('); + eexpr(tq^.tup^.tidl); + write(')((int)('); + eexpr(tp^.tforid); + write(')', opc1, '1)') + end + else + write(opc1, opc1); + if not lazyfor then + begin + if tp^.tforstmt^.tt <> nbegin then + begin + (* create compund stmt *) + tq := mknode(nbegin); + tq^.tbegin := tp^.tforstmt; + tq^.tbegin^.tup := tq; + tp^.tforstmt := tq; + tq^.tup := tp + end; + (* find end of loop *) + tq := tp^.tforstmt^.tbegin; + while tq^.tnext <> nil do + tq := tq^.tnext; + (* add break stmt *) + tq^.tnext := mknode(nbreak); + tq := tq^.tnext; + tq^.tup := tp^.tforstmt; + tq^.tbrkid := tp^.tforid; + tq^.tbrkxp := newid(locid2); + tq^.tbrkxp^.tup := tq + end; + if tp^.tforstmt^.tt = nbegin then + begin + decrement; + write(') '); + estmt(tp^.tforstmt) + end + else begin + writeln(')'); + estmt(tp^.tforstmt); + decrement + end; + if not lazyfor then + begin + decrement; + decrement; + indent; + writeln('}') + end + end; + nif: + begin + indent; + write('if ('); + increment; + eexpr(tp^.tifxp); + stusd := setused; + setused := false; + if tp^.tthen^.tt = nbegin then + begin + decrement; + write(') '); + estmt(tp^.tthen); + if tp^.telse <> nil then + write(space) + else + writeln + end + else begin + writeln(')'); + estmt(tp^.tthen); + decrement; + if tp^.telse <> nil then + indent + end; + if tp^.telse <> nil then + begin + write('else'); + if tp^.telse^.tt = nbegin then + begin + write(space); + estmt(tp^.telse); + writeln + end + else begin + increment; + writeln; + estmt(tp^.telse); + decrement + end; + end; + setused := stusd or setused + end; + ncase: + begin + indent; + write('switch ('); + increment; + eexpr(tp^.tcasxp); + writeln(') {'); + decrement; + echoise(tp^.tcaslst); + indent; + writeln(' default:'); + increment; + if tp^.tcasother = nil then + begin + indent; + writeln('Caseerror(Line);') + end + else + estmt(tp^.tcasother); + decrement; + indent; + writeln('}') + end; + nwith: + begin + indent; + writeln('{'); + increment; + tq := tp^.twithvar; + while tq <> nil do + begin + indent; + write(registr); + ewithtype(tq^.texpw); + write(' *'); + locid1 := mkvariable('W'); + printid(locid1); + write(' = '); + eaddr(tq^.texpw); + writeln(';'); + cenv(locid1, tq^.tenv); + tq := tq^.tnext + end; + writeln; + if tp^.twithstmt^.tt = nbegin then + estmt(tp^.twithstmt^.tbegin) + else + estmt(tp^.twithstmt); + decrement; + indent; + writeln('}') + end; + ngoto: + begin + indent; + if islocal(tp^.tlabel) then + writeln('goto L', + tp^.tlabel^.tsym^.lno:1, ';') + else begin + tq := idup(tp^.tlabel); + writeln('longjmp(J[', (* LIB *) + tq^.tstat:1, '].jb, ', + tp^.tlabel^.tsym^.lno:1, ');') + end + end; + nlabstmt: + begin + decrement; + indent; + writeln('L', tp^.tlabno^.tsym^.lno:1, ':'); + increment; + estmt(tp^.tstmt) + end; + nassign: + begin + indent; + eexpr(tp); + writeln(';') + end; + ncall: + begin + indent; + tq := idup(tp^.tcall); + if (tq^.tt in [nfunc, nproc]) and + (tq^.tsubstmt <> nil) then + if tq^.tsubstmt^.tt = npredef then + epredef(tq, tp) + else begin + ecall(tp); + writeln(';') + end + else begin + ecall(tp); + writeln(';') + end + end; + npush: + begin + indent; + eglobid(tp^.ttmp); + write(' = '); + eglobid(tp^.tglob); + writeln(';'); + indent; + eglobid(tp^.tglob); + write(' = '); + if tp^.tloc^.tt = nid then + begin + tq := idup(tp^.tloc); + if tq^.tt in [nparproc, nparfunc] then + printid(tp^.tloc^.tsym^.lid) + else + eaddr(tp^.tloc) + end + else + eaddr(tp^.tloc); + writeln(';') + end; + npop: + begin + indent; + eglobid(tp^.tglob); + write(' = '); + eglobid(tp^.ttmp); + writeln(';') + end; + nbreak: + begin + indent; + write('if ('); + eexpr(tp^.tbrkid); + write(' == '); + eexpr(tp^.tbrkxp); + writeln(') break;') + end; + nempty: + if not (tp^.tup^.tt in [npgm, nproc, nfunc, + nchoise, nbegin, nrepeat]) then + begin + indent; + writeln(';') + end + end;(* case *) + if setused and + (tp^.tup^.tt in [npgm, nproc, nfunc, nrepeat, + nbegin, nchoise, nwith]) then + begin + indent; + writeln('Claimset();'); + setused := false + end; + tp := tp^.tnext + end + end; (* estmt *) + + (* Emit initialization for non-local gotos. *) + procedure elabel(tp : treeptr); + + var tq : treeptr; + i : integer; + + begin + i := 0; + tq := tp^.tsublab; + while tq <> nil do + begin + if tq^.tsym^.lgo then + i := i + 1; + tq := tq^.tnext + end; + if i =1 then + begin + tq := tp^.tsublab; + while not tq^.tsym^.lgo do + tq := tq^.tnext; + indent; + writeln('if (', + 'setjmp(J[', tp^.tstat:1, '].jb))'); (* LIB *) + writeln(tab1, 'goto L', tq^.tsym^.lno:1, ';') + end + else if i > 1 then + begin + indent; + writeln('switch (', + 'setjmp(J[', tp^.tstat:1, '].jb)) {'); (* LIB *) + indent; + writeln(' case 0:'); + indent; + writeln(tab1, 'break'); + tq := tp^.tsublab; + while tq <> nil do + begin + if tq^.tsym^.lgo then + begin + (* label used in non-local goto *) + indent; + writeln(' case ', + tq^.tsym^.lno:1, ':'); + indent; + writeln(tab1, 'goto L', + tq^.tsym^.lno:1, ';') + end; + tq := tq^.tnext + end; + indent; + writeln(' default:'); + indent; + writeln(tab1, 'Caseerror(Line)'); + indent; + writeln('}') + end + end; (* elabel *) + + (* Emit declaration for lower bound of conformant array. *) + procedure econf(tp : treeptr); + + var tq : treeptr; + + begin + while tp <> nil do + begin + if tp^.tt = nvarpar then + if tp^.tbind^.tt = nconfarr then + begin + indent; + etypedef(tp^.tbind^.tindtyp); + write(tab1); + tq := tp^.tbind^.tcindx^.tlo; + printid(tq^.tsym^.lid); + write(' = ('); + etypedef(tp^.tbind^.tindtyp); + writeln(')0;') + end; + tp := tp^.tnext + end + end; (* econf *) + + (* Emit code for subroutines. *) + procedure esubr(tp : treeptr); + + label 999; + + var tq, ti : treeptr; + + begin + while tp <> nil do + begin + (* emit nested subroutines *) + if tp^.tsubsub <> nil then + begin + (* emit forward declaration of this subroutine + in case of recursion *) + etypedef(tp^.tfuntyp); + write(space); + printid(tp^.tsubid^.tsym^.lid); + writeln('();'); + writeln; + esubr(tp^.tsubsub) + end; + (* emit this subroutine *) + if tp^.tsubstmt = nil then + begin + (* forward/external decl *) + if tp^.tsubid^.tsym^.lsymdecl^.tup = tp then + write(xtern); + etypedef(tp^.tfuntyp); + write(space); + printid(tp^.tsubid^.tsym^.lid); + writeln('();'); + goto 999 + end; + write(space); + etypedef(tp^.tfuntyp); + writeln; + printid(tp^.tsubid^.tsym^.lid); + write('('); + tq := tp^.tsubpar; + while tq <> nil do + begin + case tq^.tt of + nvarpar, + nvalpar: + begin + ti := tq^.tidl; + while ti <> nil do + begin + printid(ti^.tsym^.lid); + ti := ti^.tnext; + if ti <> nil then + write(', '); + end; + if tq^.tbind^.tt = nconfarr then + begin + (* add upper bound parameter *) + ti := tq^.tbind^.tcindx^.thi; + write(', '); + printid(ti^.tsym^.lid) + end; + end; + nparproc, + nparfunc: + begin + ti := tq^.tparid; + printid(ti^.tsym^.lid) + end + end;(* case *) + tq := tq^.tnext; + if tq <> nil then + write(', '); + end; + writeln(')'); + increment; + evar(tp^.tsubpar); + writeln('{'); + econf(tp^.tsubpar); + econst(tp^.tsubconst); + etype(tp^.tsubtype); + evar(tp^.tsubvar); + + if (tp^.tsubconst <> nil) or (tp^.tsubtype <> nil) or + (tp^.tsubvar <> nil) then + writeln; + elabel(tp); + estmt(tp^.tsubstmt); + if tp^.tt = nfunc then + begin + (* return value in the FIRST variable, + see renamf() above *) + indent; + write('return '); + printid(tp^.tsubvar^.tidl^.tsym^.lid); + writeln(';'); + end; + decrement; + writeln('}'); + 999: + writeln; + tp := tp^.tnext + end + end; (* esubr *) + + function use(d : predefs) : boolean; + + begin + use := defnams[d]^.lused + end; + + (* Emit code for main program. *) + procedure eprogram(tp : treeptr); + + (* Symbol that sp refers to is renamed if it has *) + (* been redefined in source program. *) + procedure capital(sp : symptr); + + var tb : toknbuf; + + begin + if sp^.lid^.inref > 1 then + begin + gettokn(sp^.lid^.istr, tb); + tb[1] := uppercase(tb[1]); + sp^.lid := saveid(tb) + end + end; + + procedure etextdef; + + var tq : treeptr; + + begin + write('typedef '); + tq := mknode(nfileof); + tq^.tof := typnods[tchar]; + etypedef(tq); + writeln(tab1, 'text;') + end; + + begin (* eprogram *) + if tp^.tsubid <> nil then + begin + (* program heading was seen *) + writeln('/', '*'); + write('** Code derived from program '); + printid(tp^.tsubid^.tsym^.lid); + writeln; + writeln('*', '/'); + writeln(xtern, voidtyp, tab1, 'exit();') + end; + if usecase or usesets or + use(dinput) or use(doutput) or + use(dwrite) or use(dwriteln) or use(dmessage) or + use(deof) or use(deoln) or use(dflush) or use(dpage) or + use(dread) or use(dreadln) or use(dclose) or + use(dreset) or use(drewrite) or use(dget) or use(dput) then + begin + writeln('/', '*'); + writeln('** Definitions for i/o'); + writeln('*', '/'); + writeln(include, '<stdio.h>') (* LIB *) + end; + if use(dinput) or use(doutput) or use(dtext) then + begin + etextdef; + if use(dinput) then + begin + if tp^.tsubid = nil then + write(xtern); + write('text', tab1); + printid(defnams[dinput]^.lid); + if tp^.tsubid <> nil then + write(' = { stdin, 0, 0 }'); + writeln(';') + end; + if use(doutput) then + begin + if tp^.tsubid = nil then + write(xtern); + write('text', tab1); + printid(defnams[doutput]^.lid); + if tp^.tsubid <> nil then + write(' = { stdout, 0, 0 }'); + writeln(';') + end + end; + if use(dinput) or use(dget) or use(dread) or use(dreadln) or + use(deof) or use(deoln) or use(dreset) or use(drewrite) then + begin + writeln(define, 'Fread(x, f) ', + 'fread((char *)&x, sizeof(x), 1, f)'); (* LIB *) + writeln(define, 'Get(f) Fread((f).buf, (f).fp)'); + writeln(define, 'Getx(f) (f).init = 1, ', + '(f).eoln = (((f).buf = ', + 'fgetc((f).fp)', (* LIB *) + ') == ', nlchr, ') ? (((f).buf = ', + spchr, '), 1) : 0'); + writeln(define, 'Getchr(f) (f).buf, Getx(f)') + end; + if use(dread) or use(dreadln) then + begin + writeln(static, 'FILE', tab1, '*Tmpfil;'); + writeln(static, 'long', tab1, 'Tmplng;'); + writeln(static, 'double', tab1, 'Tmpdbl;'); + writeln(define, 'Fscan(f) (f).init ? ', + 'ungetc((f).buf, (f).fp)', (* LIB *) + ' : 0, Tmpfil = (f).fp'); + writeln(define, 'Scan(p, a) ', + 'Scanck(fscanf(Tmpfil, p, a))'); (* LIB *) + writeln(voidtyp, tab1, 'Scanck();'); + if use(dreadln) then + writeln(voidtyp, tab1, 'Getl();'); + end; + if use(deoln) then + writeln(define, 'Eoln(f) ((f).eoln ? true : false)'); + if use(deof) then + writeln(define, 'Eof(f) ', + '((((f).init == 0) ? (Get(f)) : 0, ', + '((f).eof ? 1 : ', + 'feof((f).fp))) ? ', (* LIB *) + 'true : false)'); + if use(doutput) or use(dput) or + use(dwrite) or use(dwriteln) or + use(dreset) or use(drewrite) or use(dclose) then + begin + writeln(define, 'Fwrite(x, f) ', + 'fwrite((char *)&x, sizeof(x), 1, f)');(* LIB *) + writeln(define, 'Put(f) Fwrite((f).buf, (f).fp)'); + writeln(define, 'Putx(f) (f).eoln = ((f).buf == ', + nlchr, '), ', voidcast, + 'fputc((f).buf, (f).fp)'); (* LIB *) + writeln(define, 'Putchr(c, f) (f).buf = (c), Putx(f)'); + writeln(define, 'Putl(f, v) (f).eoln = v') + end; + if use(dreset) or use(drewrite) or use(dclose) then + writeln(define, 'Finish(f) ((f).out && !(f).eoln) ? ', + '(Putchr(', nlchr, ', f), 0) : 0, ', + 'rewind((f).fp)'); (* LIB *) + if use(dclose) then + begin + writeln(define, 'Close(f) (f).init = ', + '((f).init ? (', + 'fclose((f).fp), ', (* LIB *) + '0) : 0), (f).fp = NULL'); + writeln(define, 'Closex(f) (f).init = ', + '((f).init ? ', + '(Finish(f), ', + 'fclose((f).fp), ', (* LIB *) + '0) : 0), (f).fp = NULL') + end; + if use(dreset) then + begin + writeln(ifdef, 'READONLY'); + writeln(static, chartyp, tab1, 'Rmode[] = "r";'); + writeln(elsif); + writeln(static, chartyp, tab1, 'Rmode[] = "r+";'); + writeln(endif); + writeln(define, 'Reset(f, n) (f).init = ', + '(f).init ? rewind((f).fp) : ', (* LIB *) + '(((f).fp = Fopen(n, Rmode)), 1), ', + '(f).eof = (f).out = 0, Get(f)'); + writeln(define, 'Resetx(f, n) (f).init = ', + '(f).init ? (Finish(f)) : ', + '(((f).fp = Fopen(n, Rmode)), 1), ', + '(f).eof = (f).out = 0, Getx(f)'); + usefopn := true + end; + if use(drewrite) then + begin + writeln(ifdef, 'WRITEONLY'); + writeln(static, chartyp, tab1, 'Wmode[] = "w";'); + writeln(elsif); + writeln(static, chartyp, tab1, 'Wmode[] = "w+";'); + writeln(endif); + writeln(define, 'Rewrite(f, n) (f).init = ', + '(f).init ? rewind((f).fp) : ', (* LIB *) + '(((f).fp = Fopen(n, Wmode)), 1), ', + '(f).out = (f).eof = 1'); + writeln(define, 'Rewritex(f, n) (f).init = ', + '(f).init ? (Finish(f)) : ', + '(((f).fp = Fopen(n, Wmode)), 1), ', + '(f).out = (f).eof = (f).eoln = 1'); + usefopn := true + end; + if usefopn then + begin + writeln('FILE *Fopen();'); + writeln(define, 'MAXFILENAME 256') + end; + if usecase or usejmps then + begin + writeln('/', '*'); + writeln('** Definitions for case-statements'); + writeln('** and for non-local gotos'); + writeln('*', '/'); + writeln(define, 'Line __LINE__'); + writeln(voidtyp, tab1, 'Caseerror();') + end; + if usejmps then + begin + writeln(include, '<setjmp.h>'); (* LIB *) + writeln(static, 'struct Jb { jmp_buf', tab1, 'jb; } J[', + (maxlevel+1):1, '];') + end; + if use(dinteger) or use(dmaxint) or + use(dboolean) or use(dfalse) or use(dtrue) or + use(deof) or use(deoln) or use(dexp) or + use(dln) or use(dsqr) or use(dsin) or + use(dcos) or use(dtan) or use(darctan) or + use(dsqrt) or use(dreal) then + begin + writeln('/', '*'); + writeln('** Definitions for standard types'); + writeln('*', '/') + end; + if usecomp then + begin + writeln(xtern, inttyp, ' strncmp();'); (* LIB *) + writeln(define, + 'Cmpstr(x, y) ', + 'strncmp((x), (y), sizeof(x))') (* LIB *) + end; + if use(dboolean) or use(dfalse) or use(dtrue) or + use(deof) or use(deoln) or usesets then + begin + capital(defnams[dboolean]); + write(typdef, chartyp, tab1); + printid(defnams[dboolean]^.lid); + writeln(';'); + capital(defnams[dfalse]); + write(define); + printid(defnams[dfalse]^.lid); + write(' ('); + printid(defnams[dboolean]^.lid); + writeln(')0'); + capital(defnams[dtrue]); + write(define); + printid(defnams[dtrue]^.lid); + write(' ('); + printid(defnams[dboolean]^.lid); + writeln(')1'); + writeln(xtern, chartyp, tab1, '*Bools[];') + end; + capital(defnams[dinteger]); + if use(dinteger) then + begin + write(typdef, inttyp, tab1); + printid(defnams[dinteger]^.lid); + writeln(';') + end; + if use(dmaxint) then + writeln(define, 'maxint', tab1, maxint:1); + capital(defnams[dreal]); + if use(dreal) then + begin + write(typdef, realtyp, tab1); + printid(defnams[dreal]^.lid); + writeln(';') + end; + if use(dexp) then + writeln(xtern, doubletyp, ' exp();'); (* LIB *) + if use(dln) then + writeln(xtern, doubletyp, ' log();'); (* LIB *) + if use(dsqr) then + writeln(xtern, doubletyp, ' pow();'); (* LIB *) + if use(dsin) then + writeln(xtern, doubletyp, ' sin();'); (* LIB *) + if use(dcos) then + writeln(xtern, doubletyp, ' cos();'); (* LIB *) + if use(dtan) then + writeln(xtern, doubletyp, ' tan();'); (* LIB *) + if use(darctan) then + writeln(xtern, doubletyp, ' atan();'); (* LIB *) + if use(dsqrt) then + writeln(xtern, doubletyp, ' sqrt();'); (* LIB *) + if use(dabs) and use(dreal) then + writeln(xtern, doubletyp, ' fabs();'); (* LIB *) + if use(dhalt) then + writeln(xtern, voidtyp, ' abort();'); (* LIB *) + if use(dnew) or usenilp then + begin + writeln('/', '*'); + writeln('** Definitions for pointers'); + writeln('*', '/'); + end; + if use(dnew) then + begin + writeln(ifndef, 'Unionoffs'); + writeln(define, 'Unionoffs(p, m) ', + '(((long)(&(p)->m))-((long)(p)))'); (* CPU *) + writeln(endif) + end; + if usenilp then + writeln(define, 'NIL 0'); (* CPU *) + if use(dnew) then + writeln(xtern, chartyp, ' *malloc();'); (* LIB *) + if use(ddispose) then + writeln(xtern, voidtyp, ' free();'); (* LIB *) + if usesets then + begin + writeln('/', '*'); + writeln('** Definitions for set-operations'); + writeln('*', '/'); + writeln(define, 'Claimset() ', + voidcast, 'Currset(0, (', setptyp, ')0)'); + writeln(define, 'Newset() ', + 'Currset(1, (', setptyp, ')0)'); + writeln(define, 'Saveset(s) Currset(2, s)'); + writeln(define, 'setbits ', setbits:1); + writeln(typdef, wordtype, tab1, setwtyp, ';'); + writeln(typdef, setwtyp, ' *', tab1, setptyp, ';'); + printid(defnams[dboolean]^.lid); + writeln(tab1, 'Member(), Le(), Ge(), Eq(), Ne();'); + writeln(setptyp, tab1, 'Union(), Diff();'); + writeln(setptyp, tab1, 'Insmem(), Mksubr();'); + writeln(setptyp, tab1, 'Currset(), Inter();'); + writeln(static, setptyp, tab1, 'Tmpset;'); + writeln(xtern, setptyp, tab1, 'Conset[];'); + writeln(voidtyp, tab1, 'Setncpy();') + end; + writeln(xtern, chartyp, ' *strncpy();'); (* LIB *) + if use(dargc) or use(dargv) then + begin + writeln('/', '*'); + writeln('** Definitions for argv-operations'); + writeln('*', '/'); + writeln(inttyp, tab1, 'argc;'); (* OS *) + writeln(chartyp, tab1, '**argv;'); + writeln(' void'); + writeln('Argvgt(n, cp, l)'); + writeln(inttyp, tab1, 'n;'); + writeln(registr, inttyp, tab1, 'l;'); + writeln(registr, chartyp, tab1, '*cp;'); + writeln('{'); + writeln(tab1, registr, chartyp, tab1, '*sp;'); + writeln; + writeln(tab1, 'for (sp = argv[n]; l > 0 && *sp; l--)'); + writeln(tab2, '*cp++ = *sp++;'); + writeln(tab1, 'while (l-- > 0)'); + writeln(tab2, '*cp++ = ', spchr, ';'); + writeln('}'); + end; + if (tp^.tsubconst <> nil) or (tp^.tsubtype<> nil) or + (tp^.tsubvar <> nil) or (tp^.tsubsub <> nil) then + begin + writeln('/', '*'); + writeln('** Start of program definitions'); + writeln('*', '/'); + end; + econst(tp^.tsubconst); + etype(tp^.tsubtype); + evar(tp^.tsubvar); + if tp^.tsubsub <> nil then + writeln; + esubr(tp^.tsubsub); + if tp^.tsubid <> nil then + begin + (* program heading was seen *) + writeln('/', '*'); + writeln('** Start of program code'); + writeln('*', '/'); + if use(dargc) or use(dargv) then + begin + writeln('main(_ac, _av)'); (* OS *) + writeln(inttyp, tab1, '_ac;'); + writeln(chartyp, tab1, '*_av[];'); + writeln('{'); + writeln; + writeln(tab1, 'argc = _ac;'); + writeln(tab1, 'argv = _av;') + end + else begin + writeln('main()'); + writeln('{') + end; + increment; + elabel(tp); + estmt(tp^.tsubstmt); + indent; + writeln('exit(0);'); + decrement; + writeln('}'); + writeln('/', '*'); + writeln('** End of program code'); + writeln('*', '/') + end + end; (* eprogram *) + + (* Emit definitions for constant sets *) + procedure econset(tp : treeptr; len : integer); + + var i : integer; + + function size(tp : treeptr) : integer; + + var r, x : integer; + + begin + r := 0; + while tp <> nil do + begin + if tp^.tt = nrange then + x := cvalof(tp^.texpr) + else if tp^.tt = nempty then + x := 0 + else + x := cvalof(tp); + if x > r then + r := x; + tp := tp^.tnext + end; + size := csetwords(r+1) + end; + + (* Emit bits in a constant set *) + procedure ebits(tp : treeptr); + + type bitset = set of 0 .. setbits; + + var sets : array [ 0 .. maxsetrange ] of bitset; + s, m, n : integer; + + procedure eword(s : bitset); + + const bitshex = 4; (* nr of bits in a hex-digit *) + + var n, i : integer; + x : 0 .. setbits; + + begin + n := 0; + while n <= setbits do + n := n + bitshex; + n := n - bitshex; + while n >= 0 do + begin + (* compute 1 hexdigit *) + x := 0; + for i := 0 to bitshex - 1 do + if (n + i) in s then + case i of + 0: x := x + 1; + 1: x := x + 2; + 2: x := x + 4; + 3: x := x + 8 + end;(* case *) + (* print it *) + write(hexdig[x]); + n := n - bitshex + end + end; + + begin + s := size(tp); + for n := 0 to s - 1 do + sets[n] := []; + while tp <> nil do + begin + if tp^.tt = nrange then + for m := cvalof(tp^.texpl) to + cvalof(tp^.texpr) do + begin + n := m div (setbits+1); + sets[n] := sets[n] + + [m mod (setbits+1)] + end + else if tp^.tt <> nempty then + begin + m := cvalof(tp); + n := m div (setbits+1); + sets[n] := sets[n] + + [m mod (setbits+1)] + end; + tp := tp^.tnext + end; + write(tab1, s:1); + for n := 0 to s - 1 do + begin + write(','); + if n mod 6 = 0 then + writeln; + write(tab1, '0x'); + eword(sets[n]); + end; + writeln + end; + + begin + i := 0; + while tp <> nil do + begin + writeln(static, setwtyp, tab1, 'Q', i:1, '[] = {'); + ebits(tp^.texps); + writeln('};'); + i := i + 1; + tp := tp^.tnext + end; + writeln(static, setwtyp, tab1, '*Conset[] = {'); + for i := len - 1 downto 1 do + begin + write(tab1, 'Q', i:1, ','); + if i mod 6 = 5 then + writeln + end; + writeln(tab1, 'Q0'); + writeln('};'); + end; + +begin (* emit *) + indnt := 0; + varno := 0; + conflag := false; + setused := false; + dropset := false; + doarrow := 0; + eprogram(top); + if usebool then + writeln(chartyp, tab1, '*Bools[] = { "false", "true" };'); + if usescan then + begin + writeln; + writeln(static, voidtyp); + writeln('Scanck(n)'); + writeln(inttyp, tab1, 'n;'); + writeln('{'); + writeln(tab1, 'if (n != 1) {'); + writeln(tab2, voidcast, 'fprintf(stderr, "Bad input\n");'); + writeln(tab2, 'exit(1);'); + writeln(tab1, '}'); + writeln('}') + end; + if usegetl then + begin + writeln; + writeln(static, voidtyp); + writeln('Getl(f)'); + writeln(' text', tab1, '*f;'); + writeln('{'); + writeln(tab1, 'while (f->eoln == 0)'); + writeln(tab2, 'Getx(*f);'); + writeln(tab1, 'Getx(*f);'); + writeln('}') + end; + if usefopn then + begin + writeln; + writeln(static, 'FILE *'); + writeln('Fopen(n, m)'); + writeln(chartyp, tab1, '*n, *m;'); + writeln('{'); + writeln(tab1, 'FILE', tab2, '*f;'); + writeln(tab1, registr, chartyp, tab1, '*s;'); + writeln(tab1, static, chartyp, tab1, 'ch = ', + quote, 'A', quote, ';'); + writeln(tab1, static, chartyp, tab1, 'tmp[MAXFILENAME];'); + writeln(tab1, xtern , inttyp, tab1, 'unlink();'); (* OS *) + writeln; + writeln(tab1, 'if (n == NULL)'); + writeln(tab2, 'sprintf(tmp, ', tmpfilename, 'ch++);'); + writeln(tab1, 'else {'); + writeln(tab2, 'strncpy(tmp, n, sizeof(tmp));'); + writeln(tab2, 'for (s = &tmp[sizeof(tmp)-1]; *s == ', + spchr, ' || *s == ', nulchr, '; )'); + writeln(tab3, '*s-- = ', nulchr, ';'); + writeln(tab2, 'if (tmp[sizeof(tmp)-1]) {'); + writeln(tab3, voidcast, 'fprintf(stderr, "Too long filename ', + quote, '%s', quote, '\n", n);'); + writeln(tab3, 'exit(1);'); + writeln(tab2, '}'); + writeln(tab1, '}'); + writeln(tab1, 's = tmp;'); + writeln(tab1, 'if ((f = fopen(s, m)) == NULL) {'); + writeln(tab2, voidcast, + 'fprintf(stderr, "Cannot open: %s\n", s);'); + writeln(tab2, 'exit(1);'); + writeln(tab1, '}'); + writeln(tab1, 'if (n == NULL)'); + writeln(tab2, 'unlink(tmp);'); (* OS *) + writeln(tab1, 'return (f);'); + writeln('}'); + writeln(xtern, inttyp, tab1, 'rewind();') + end; + if setcnt > 0 then + econset(setlst, setcnt); + if useunion then + begin + writeln; + writeln(static, setptyp); + writeln('Union(p1, p2)'); + writeln(tab1, registr, setptyp, tab1, 'p1, p2;'); + writeln('{'); + writeln(tab1, registr, inttyp, tab2, 'i, j, k;'); + writeln(tab1, registr, setptyp, tab2, 'sp = Newset(),'); + writeln(tab4, 'p3 = sp;'); + writeln; + writeln(tab1, 'j = *p1;'); + writeln(tab1, '*p3 = j;'); + writeln(tab1, 'if (j > *p2)'); + writeln(tab2, 'j = *p2;'); + writeln(tab1, 'else'); + writeln(tab2, '*p3 = *p2;'); + writeln(tab1, 'k = *p1 - *p2;'); + writeln(tab1, 'p1++, p2++, p3++;'); + writeln(tab1, 'for (i = 0; i < j; i++)'); + writeln(tab2, '*p3++ = (*p1++ | *p2++);'); + writeln(tab1, 'while (k > 0) {'); + writeln(tab2, '*p3++ = *p1++;'); + writeln(tab2, 'k--;'); + writeln(tab1, '}'); + writeln(tab1, 'while (k < 0) {'); + writeln(tab2, '*p3++ = *p2++;'); + writeln(tab2, 'k++;'); + writeln(tab1, '}'); + writeln(tab1, 'return (Saveset(sp));'); + writeln('}') + end; + if usediff then + begin + writeln; + writeln(static, setptyp); + writeln('Diff(p1, p2)'); + writeln(tab1, registr, setptyp, tab1, 'p1, p2;'); + writeln('{'); + writeln(tab1, registr, inttyp, tab2, 'i, j, k;'); + writeln(tab1, registr, setptyp, tab2, 'sp = Newset(),'); + writeln(tab4, 'p3 = sp;'); + writeln; + writeln(tab1, 'j = *p1;'); + writeln(tab1, '*p3 = j;'); + writeln(tab1, 'if (j > *p2)'); + writeln(tab2, 'j = *p2;'); + writeln(tab1, 'k = *p1 - *p2;'); + writeln(tab1, 'p1++, p2++, p3++;'); + writeln(tab1, 'for (i = 0; i < j; i++)'); + writeln(tab2, '*p3++ = (*p1++ & ~ (*p2++));'); + writeln(tab1, 'while (k > 0) {'); + writeln(tab2, '*p3++ = *p1++;'); + writeln(tab2, 'k--;'); + writeln(tab1, '}'); + writeln(tab1, 'return (Saveset(sp));'); + writeln('}') + end; + if useintr then + begin + writeln; + writeln(static, setptyp); + writeln('Inter(p1, p2)'); + writeln(tab1, registr, setptyp, tab1, 'p1, p2;'); + writeln('{'); + writeln(tab1, registr, inttyp, tab2, 'i, j, k;'); + writeln(tab1, registr, setptyp, tab2, 'sp = Newset(),'); + writeln(tab4, 'p3 = sp;'); + writeln; + writeln(tab1, 'if ((j = *p1) > *p2)'); + writeln(tab2, 'j = *p2;'); + writeln(tab1, '*p3 = j;'); + writeln(tab1, 'p1++, p2++, p3++;'); + writeln(tab1, 'for (i = 0; i < j; i++)'); + writeln(tab2, '*p3++ = (*p1++ & *p2++);'); + writeln(tab1, 'return (Saveset(sp));'); + writeln('}') + end; + if usememb then + begin + writeln; + write(static); + printid(defnams[dboolean]^.lid); + writeln; + writeln('Member(m, sp)'); + writeln(tab1, registr, usigned, inttyp, tab1, 'm;'); + writeln(tab1, registr, setptyp, tab1, 'sp;'); + writeln('{'); + writeln(tab1, registr, usigned, inttyp, + tab1, 'i = m / (setbits+1) + 1;'); + writeln; + writeln(tab1, 'if ((i <= *sp) &&', + ' (sp[i] & (1 << (m % (setbits+1)))))'); + write(tab2, 'return ('); + printid(defnams[dtrue]^.lid); + writeln(');'); + write(tab1, 'return ('); + printid(defnams[dfalse]^.lid); + writeln(');'); + writeln('}') + end; + if useseq or usesne then + begin + writeln; + write(static); + printid(defnams[dboolean]^.lid); + writeln; + writeln('Eq(p1, p2)'); + writeln(tab1, registr, setptyp, tab1, 'p1, p2;'); + writeln('{'); + writeln(tab1, registr, inttyp, tab1, 'i, j;'); + writeln; + writeln(tab1, 'i = *p1++;'); + writeln(tab1, 'j = *p2++;'); + writeln(tab1, 'while (i != 0 && j != 0) {'); + writeln(tab2, 'if (*p1++ != *p2++)'); + write(tab3, 'return ('); + printid(defnams[dfalse]^.lid); + writeln(');'); + writeln(tab2, 'i--, j--;'); + writeln(tab1, '}'); + writeln(tab1, 'while (i != 0) {'); + writeln(tab2, 'if (*p1++ != 0)'); + write(tab3, 'return ('); + printid(defnams[dfalse]^.lid); + writeln(');'); + writeln(tab2, 'i--;'); + writeln(tab1, '}'); + writeln(tab1, 'while (j != 0) {'); + writeln(tab2, 'if (*p2++ != 0)'); + write(tab3, 'return ('); + printid(defnams[dfalse]^.lid); + writeln(');'); + writeln(tab2, 'j--;'); + writeln(tab1, '}'); + write(tab1, 'return ('); + printid(defnams[dtrue]^.lid); + writeln(');'); + writeln('}') + end; + if usesne then + begin + writeln; + write(static); + printid(defnams[dboolean]^.lid); + writeln; + writeln('Ne(p1, p2)'); + writeln(tab1, registr, setptyp, tab1, 'p1, p2;'); + writeln('{'); + write(tab1, 'return (!Eq(p1, p2));'); + writeln('}') + end; + if usesle then + begin + writeln; + write(static); + printid(defnams[dboolean]^.lid); + writeln; + writeln('Le(p1, p2)'); + writeln(tab1, registr, setptyp, tab1, 'p1, p2;'); + writeln('{'); + writeln(tab1, registr, inttyp, tab1, 'i, j;'); + writeln; + writeln(tab1, 'i = *p1++;'); + writeln(tab1, 'j = *p2++;'); + writeln(tab1, 'while (i != 0 && j != 0) {'); + writeln(tab2, 'if ((*p1++ & ~ *p2++) != 0)'); + write(tab3, 'return ('); + printid(defnams[dfalse]^.lid); + writeln(');'); + writeln(tab2, 'i--, j--;'); + writeln(tab1, '}'); + writeln(tab1, 'while (i != 0) {'); + writeln(tab2, 'if (*p1++ != 0)'); + write(tab3, 'return ('); + printid(defnams[dfalse]^.lid); + writeln(');'); + writeln(tab2, 'i--;'); + writeln(tab1, '}'); + write(tab1, 'return ('); + printid(defnams[dtrue]^.lid); + writeln(');'); + writeln('}') + end; + if usesge then + begin + writeln; + write(static); + printid(defnams[dboolean]^.lid); + writeln; + writeln('Ge(p1, p2)'); + writeln(tab1, registr, setptyp, tab1, 'p1, p2;'); + writeln('{'); + writeln(tab1, registr, inttyp, tab1, 'i, j;'); + writeln; + writeln(tab1, 'i = *p1++;'); + writeln(tab1, 'j = *p2++;'); + writeln(tab1, 'while (i != 0 && j != 0) {'); + writeln(tab2, 'if ((*p2++ & ~ *p1++) != 0)'); + writeln(tab3, 'return (false);'); + writeln(tab2, 'i--, j--;'); + writeln(tab1, '}'); + writeln(tab1, 'while (j != 0) {'); + writeln(tab2, 'if (*p2++ != 0)'); + write(tab3, 'return ('); + printid(defnams[dfalse]^.lid); + writeln(');'); + writeln(tab2, 'j--;'); + writeln(tab1, '}'); + write(tab1, 'return ('); + printid(defnams[dtrue]^.lid); + writeln(');'); + writeln('}') + end; + if usemksub then + begin + writeln; + writeln(static, setptyp); + writeln('Mksubr(lo, hi, sp)'); + writeln(tab1, registr, usigned, inttyp, tab1, 'lo, hi;'); + writeln(tab1, registr, setptyp, tab1, 'sp;'); + writeln('{'); + writeln(tab1, registr, inttyp, tab1, 'i, k;'); + writeln; + writeln(tab1, 'if (hi < lo)'); + writeln(tab2, 'return (sp);'); + writeln(tab1, 'i = hi / (setbits+1) + 1;'); + writeln(tab1, 'for (k = *sp + 1; k <= i; k++)'); + writeln(tab2, 'sp[k] = 0;'); + writeln(tab1, 'if (*sp < i)'); + writeln(tab2, '*sp = i;'); + writeln(tab1, 'for (k = lo; k <= hi; k++)'); + writeln(tab2, 'sp[k / (setbits+1) + 1] |= ', + '(1 << (k % (setbits+1)));'); + writeln(tab1, 'return (sp);'); + writeln('}') + end; + if useins then + begin + writeln; + writeln(static, setptyp); + writeln('Insmem(m, sp)'); + writeln(tab1, registr, usigned, inttyp, tab1, 'm;'); + writeln(tab1, registr, setptyp, tab1, 'sp;'); + writeln('{'); + writeln(tab1, registr, inttyp, tab1, 'i,'); + writeln(tab3, tab1, 'j = m / (setbits+1) + 1;'); + writeln; + writeln(tab1, 'if (*sp < j)'); + writeln(tab2, 'for (i = *sp + 1, *sp = j; i <= *sp; i++)'); + writeln(tab3, 'sp[i] = 0;'); + writeln(tab1, 'sp[j] |= (1 << (m % (setbits+1)));'); + writeln(tab1, 'return (sp);'); + writeln('}') + end; + if usesets then + begin + writeln; + writeln(ifndef, 'SETSPACE'); + writeln(define, 'SETSPACE 256'); + writeln(endif); + writeln(static, setptyp); + writeln('Currset(n,sp)'); + writeln(tab1, inttyp, tab1, 'n;'); + writeln(tab1, setptyp, tab1, 'sp;'); + writeln('{'); + writeln(tab1, static, setwtyp, tab1, 'Space[SETSPACE];'); + writeln(tab1, static, setptyp, tab1, 'Top = Space;'); + writeln; + writeln(tab1, 'switch (n) {'); + writeln(tab1, ' case 0:'); + writeln(tab2, 'Top = Space;'); + writeln(tab2, 'return (0);'); + writeln(tab1, ' case 1:'); + writeln(tab2, 'if (&Space[SETSPACE] - Top <= ', + maxsetrange:1, ') {'); + writeln(tab3, + voidcast, 'fprintf(stderr, "Set-space exhausted\n");'); + writeln(tab3, 'exit(1);'); + writeln(tab2, '}'); + writeln(tab2, '*Top = 0;'); + writeln(tab2, 'return (Top);'); + writeln(tab1, ' case 2:'); + writeln(tab2, 'if (Top <= &sp[*sp])'); + writeln(tab3, 'Top = &sp[*sp + 1];'); + writeln(tab2, 'return (sp);'); + writeln(tab1, '}'); + writeln(tab1, '/', '* NOTREACHED *', '/'); + writeln('}') + end; + if usescpy then + begin + writeln; + writeln(static, voidtyp); + writeln('Setncpy(S1, S2, N)'); + writeln(tab1, registr, setptyp, tab1, 'S1, S2;'); + writeln(tab1, registr, usigned, inttyp, tab1, 'N;'); + writeln('{'); + writeln(tab1, registr, usigned, inttyp, tab1, 'm;'); + writeln; + writeln(tab1, 'N /= sizeof(', setwtyp, ');'); + writeln(tab1, '*S1++ = --N;'); + writeln(tab1, 'm = *S2++;'); + writeln(tab1, 'while (m != 0 && N != 0) {'); + writeln(tab2, '*S1++ = *S2++;'); + writeln(tab2, '--N;'); + writeln(tab2, '--m;'); + writeln(tab1, '}'); + writeln(tab1, 'while (N-- != 0)'); + writeln(tab2, '*S1++ = 0;'); + writeln('}') + end; + if usecase then + begin + writeln; + writeln(static, voidtyp); + writeln('Caseerror(n)'); + writeln(tab1, inttyp, tab1, 'n;'); + writeln('{'); + writeln(tab1, voidcast, + 'fprintf(stderr, "Missing case limb: line %d\n", n);'); + writeln(tab1, 'exit(1);'); + writeln('}') + end; + if usemax then + begin + writeln; + writeln(static, inttyp); + writeln('Max(m, n)'); + writeln(tab1, inttyp, tab1, 'm, n;'); + writeln('{'); + writeln(tab1, 'if (m > n)'); + writeln(tab2, 'return (m);'); + writeln(tab1, 'return (n);'); + writeln('}') + end; + if use(dtrunc) then + begin + writeln(static, inttyp); + writeln('Trunc(f)'); + printid(defnams[dreal]^.lid); + writeln(tab1, 'f;'); + writeln('{'); + writeln(tab1, 'return f;'); + writeln('}') + end; + if use(dround) then + begin + writeln(static, inttyp); + writeln('Round(f)'); + printid(defnams[dreal]^.lid); + writeln(tab1, 'f;'); + writeln('{'); + writeln(tab1, xtern, doubletyp, ' floor();'); (* LIB *) + writeln(tab1, + 'return floor(', dblcast, '(0.5+f));'); (* LIB *) + writeln('}') + end +end; (* emit *) + +(* Initialize all global structures used in translator. *) +procedure initialize; + +var s : hashtyp; + t : pretyps; + d : predefs; + + (* Define names in ctable. *) + procedure defname(cn : cnames; str : keyword); + + label 999; + + var w : toknbuf; + i : toknidx; + + begin + unpack(str, w, 1); + for i := 1 to keywordlen do + if w[i] = space then + begin + w[i] := chr(null); + goto 999 + end; + w[keywordlen+1] := chr(null); + 999: + ctable[cn] := saveid(w) + end; + + (* Define predefined identifiers. *) + procedure defid(nt : treetyp; did : predefs; str : keyword); + + label 999; + + var w : toknbuf; + i : toknidx; + tp, tq, + tv : treeptr; + + begin + for i := 1 to keywordlen do + if str[i] = space then + begin + w[i] := chr(null); + goto 999 + end + else + w[i] := str[i]; + w[keywordlen+1] := chr(null); + 999: + tp := newid(saveid(w)); + defnams[did] := tp^.tsym; + if nt in [ntype, nfunc, nproc] then + begin + (* predefined types, procedures and functions + are marked with a particular node *) + tv := mknode(npredef); + tv^.tdef := did; + tv^.tobtyp := tnone + end + else + tv := nil; (* predefined constants and variables will + eventually be bound to something *) + case nt of + nscalar: + begin + tv := mknode(nscalar); + tv^.tscalid := nil; + tq := mknode(ntype); + tq^.tbind := tv; + tq^.tidl := tp; + tp := tq + end; + nconst, + ntype, + nfield, + nvar: + begin + tq := mknode(nt); + tq^.tbind := tv; + tq^.tidl := tp; + tq^.tattr := anone; + tp := tq + end; + nfunc, + nproc: + begin + tq := mknode(nt); + tq^.tsubid := tp; + tq^.tsubstmt := tv; + tq^.tfuntyp := nil; + tq^.tsubpar := nil; + tq^.tsublab := nil; + tq^.tsubconst := nil; + tq^.tsubtype := nil; + tq^.tsubvar := nil; + tq^.tsubsub := nil; + tq^.tscope := nil; + tq^.tstat := 0; + tp := tq + end; + nid: + end;(* case *) + deftab[did] := tp + end; (* defid *) + + (* Define keywords. *) + procedure defkey(s : symtyp; w : keyword); + + var i : 1 .. keywordlen; + + begin + for i := 1 to keywordlen do + if w[i] = space then + w[i] := chr(null); + (* relies on symtyp being sorted *) + with keytab[ord(s)] do + begin + wrd := w; + sym := s + end; + end; + + procedure fixinit(i : strindx); + + var t : toknbuf; + + begin + gettokn(i, t); + t[1] := 'i'; + puttokn(i, t); + end; + + (* Add a cpu word type description. *) + (* Parameters lo and hi gives the range of a machine- *) + (* dependant integer type. Parameter str gives the corres- *) + (* ponding C-language type-name. *) + procedure defmach(lo, hi : integer; str : machdefstr); + + label 999; + + var i : toknidx; + w : toknbuf; + + begin + unpack(str, w, 1); + if w[machdeflen] <> space then + error(ebadmach); + for i := machdeflen - 1 downto 1 do + if w[i] <> space then + begin + w[i+1] := chr(null); + goto 999 + end; + error(ebadmach); + 999: + if nmachdefs >= maxmachdefs then + error(emanymachs); + nmachdefs := nmachdefs + 1; + with machdefs[nmachdefs] do + begin + lolim := lo; + hilim := hi; + typstr := savestr(w) + end + end; + + procedure initstrstore; + + var i : strbcnt; + + begin + for i := 1 to maxblkcnt do + strstor[i] := nil; + new(strstor[0]); + strstor[0]^[0] := chr(null); + strfree := 1; + strleft := maxstrblk + end; + +begin (* initialize *) + lineno := 1; + colno := 0; + + initstrstore; + + setlst := nil; + setcnt := 0; + hexdig := '0123456789ABCDEF'; + + symtab := nil; + statlvl := 0; + maxlevel := -1; + enterscope(nil); + varno:= 0; + + usenilp := false; + + usesets := false; + useunion := false; + usediff := false; + usemksub := false; + useintr := false; + usesge := false; + usesle := false; + usesne := false; + useseq := false; + usememb := false; + useins := false; + usescpy := false; + usefopn := false; + usescan := false; + usegetl := false; + + usecase := false; + usejmps := false; + + usebool := false; + + usecomp := false; + usemax := false; + + for s := 0 to hashmax do + idtab[s] := nil; + for d := dabs to dztring do + begin + deftab[d] := nil; + defnams[d] := nil + end; + + (* Pascal keywords *) + defkey(sand, 'and '); + defkey(sarray, 'array '); + defkey(sbegin, 'begin '); + defkey(scase, 'case '); + defkey(sconst, 'const '); + defkey(sdiv, 'div '); + defkey(sdo, 'do '); + defkey(sdownto, 'downto '); + defkey(selse, 'else '); + defkey(send, 'end '); + defkey(sextern, externsym); (* non-standard *) + defkey(sfile, 'file '); + defkey(sfor, 'for '); + defkey(sforward,'forward '); + defkey(sfunc, 'function '); + defkey(sgoto, 'goto '); + defkey(sif, 'if '); + defkey(sinn, 'in '); + defkey(slabel, 'label '); + defkey(smod, 'mod '); + defkey(snil, 'nil '); + defkey(snot, 'not '); + defkey(sof, 'of '); + defkey(sor, 'or '); + defkey(sother, othersym); (* non-standard *) + defkey(spacked, 'packed '); + defkey(sproc, 'procedure '); + defkey(spgm, 'program '); + defkey(srecord, 'record '); + defkey(srepeat, 'repeat '); + defkey(sset, 'set '); + defkey(sthen, 'then '); + defkey(sto, 'to '); + defkey(stype, 'type '); + defkey(suntil, 'until '); + defkey(svar, 'var '); + defkey(swhile, 'while '); + defkey(swith, 'with '); + defkey(seof, dummysym); (* dummy entry *) + + (* C language operator priorities *) + cprio[nformat] := 0; + cprio[nrange] := 0; + cprio[nin] := 0; + cprio[nset] := 0; + cprio[nassign] := 0; + cprio[nor] := 1; + cprio[nand] := 2; + cprio[neq] := 3; + cprio[nne] := 3; + cprio[nlt] := 3; + cprio[nle] := 3; + cprio[ngt] := 3; + cprio[nge] := 3; + cprio[nplus] := 4; + cprio[nminus] := 4; + cprio[nmul] := 5; + cprio[ndiv] := 5; + cprio[nmod] := 5; + cprio[nquot] := 5; + cprio[nnot] := 6; + cprio[numinus] := 6; + cprio[nuplus] := 7; + cprio[nindex] := 7; + cprio[nselect] := 7; + cprio[nderef] := 7; + cprio[ncall] := 7; + cprio[nid] := 7; + cprio[nchar] := 7; + cprio[ninteger] := 7; + cprio[nreal] := 7; + cprio[nstring] := 7; + cprio[nnil] := 7; + + (* Pascal language operator priorities *) + pprio[nassign] := 0; + pprio[nformat] := 0; + pprio[nrange] := 1; + pprio[nin] := 1; + pprio[neq] := 1; + pprio[nne] := 1; + pprio[nlt] := 1; + pprio[nle] := 1; + pprio[ngt] := 1; + pprio[nge] := 1; + pprio[nor] := 2; + pprio[nplus] := 2; + pprio[nminus] := 2; + pprio[nand] := 3; + pprio[nmul] := 3; + pprio[ndiv] := 3; + pprio[nmod] := 3; + pprio[nquot] := 3; + pprio[nnot] := 4; + pprio[numinus] := 4; + pprio[nuplus] := 5; + pprio[nset] := 6; + pprio[nindex] := 6; + pprio[nselect] := 6; + pprio[nderef] := 6; + pprio[ncall] := 6; + pprio[nid] := 6; + pprio[nchar] := 6; + pprio[ninteger] := 6; + pprio[nreal] := 6; + pprio[nstring] := 6; + pprio[nnil] := 6; + + (* table of C keywords/functions (which Pascal doesn't know about) *) + defname(cabort, 'abort '); (* OS *) + defname(cbreak, 'break '); + defname(ccontinue, 'continue '); + defname(cdefine, 'define '); + defname(cdefault, 'default '); + defname(cdouble, 'double '); + defname(cedata, 'edata '); (* OS *) + defname(cenum, 'enum '); + defname(cetext, 'etext '); (* OS *) + defname(cextern, 'extern '); + defname(cfclose, 'fclose '); (* LIB *) + defname(cfflush, 'fflush '); (* LIB *) + defname(cfgetc, 'fgetc '); (* LIB *) + defname(cfloat, 'float '); + defname(cfloor, 'floor '); (* OS *) + defname(cfprintf, 'fprintf '); (* LIB *) + defname(cfputc, 'fputc '); (* LIB *) + defname(cfread, 'fread '); (* LIB *) + defname(cfscanf, 'fscanf '); (* LIB *) + defname(cfwrite, 'fwrite '); (* LIB *) + defname(cgetc, 'getc '); (* OS *) + defname(cgetpid, 'getpid '); (* OS *) + defname(cint, 'int '); + defname(cinclude, 'include '); + defname(clong, 'long '); + defname(clog, 'log '); (* OS *) + defname(cmain, 'main '); + defname(cmalloc, 'malloc '); (* LIB *) + defname(cprintf, 'printf '); (* LIB *) + defname(cpower, 'pow '); (* OS *) + defname(cputc, 'putc '); (* LIB *) + defname(cread, 'read '); (* OS *) + defname(creturn, 'return '); + defname(cregister, 'register '); + defname(crewind, 'rewind '); (* LIB *) + defname(cscanf, 'scanf '); (* LIB *) + defname(csetbits, 'setbits '); + defname(csetword, 'setword '); + defname(csetptr, 'setptr '); + defname(cshort, 'short '); + defname(csigned, 'signed '); + defname(csizeof, 'sizeof '); + defname(csprintf, 'sprintf '); (* LIB *) + defname(cstatic, 'static '); + defname(cstdin, 'stdin '); (* LIB *) + defname(cstdout, 'stdout '); (* LIB *) + defname(cstderr, 'stderr '); (* LIB *) + defname(cstrncmp, 'strncmp '); (* OS *) + defname(cstrncpy, 'strncpy '); (* OS *) + defname(cstruct, 'struct '); + defname(cswitch, 'switch '); + defname(ctypedef, 'typedef '); + defname(cundef, 'undef '); + defname(cungetc, 'ungetc '); (* LIB *) + defname(cunion, 'union '); + defname(cunlink, 'unlink '); (* OS *) + defname(cunsigned, 'unsigned '); + defname(cwrite, 'write '); (* OS *) + + (* create predefined identifiers *) + defid(nfunc, dabs, 'abs '); + defid(nfunc, darctan, 'arctan '); + defid(nvar, dargc, 'argc '); (* OS *) + defid(nproc, dargv, 'argv '); (* OS *) + defid(nscalar, dboolean, 'boolean '); + defid(ntype, dchar, 'char '); + defid(nfunc, dchr, 'chr '); + defid(nproc, dclose, 'close '); (* OS *) + defid(nfunc, dcos, 'cos '); + defid(nproc, ddispose, 'dispose '); + defid(nid, dfalse, 'false '); + defid(nfunc, deof, 'eof '); + defid(nfunc, deoln, 'eoln '); + defid(nproc, dexit, 'exit '); (* OS *) + defid(nfunc, dexp, 'exp '); + defid(nproc, dflush, 'flush '); (* OS *) + defid(nproc, dget, 'get '); + defid(nproc, dhalt, 'halt '); (* OS *) + defid(nvar, dinput, 'input '); + defid(ntype, dinteger, 'integer '); + defid(nfunc, dln, 'ln '); + defid(nconst, dmaxint, 'maxint '); + defid(nproc, dmessage, 'message '); (* OS *) + defid(nproc, dnew, 'new '); + defid(nfunc, dodd, 'odd '); + defid(nfunc, dord, 'ord '); + defid(nvar, doutput, 'output '); + defid(nproc, dpack, 'pack '); + defid(nproc, dpage, 'page '); + defid(nfunc, dpred, 'pred '); + defid(nproc, dput, 'put '); + defid(nproc, dread, 'read '); + defid(nproc, dreadln, 'readln '); + defid(ntype, dreal, 'real '); + defid(nproc, dreset, 'reset '); + defid(nproc, drewrite, 'rewrite '); + defid(nfunc, dround, 'round '); + defid(nfunc, dsin, 'sin '); + defid(nfunc, dsqr, 'sqr '); + defid(nfunc, dsqrt, 'sqrt '); + defid(nfunc, dsucc, 'succ '); + defid(ntype, dtext, 'text '); + defid(nid, dtrue, 'true '); + defid(nfunc, dtrunc, 'trunc '); + defid(nfunc, dtan, 'tan '); + defid(nproc, dunpack, 'unpack '); + defid(nproc, dwrite, 'write '); + defid(nproc, dwriteln, 'writeln '); + + defid(nfield, dzinit, '$nit '); (* for internal use *) + defid(ntype, dztring, '$ztring '); + + (* bind constants and variables *) + deftab[dboolean]^.tbind^.tscalid := deftab[dfalse]; + deftab[dfalse]^.tnext := deftab[dtrue]; + currsym.st := sinteger; + currsym.vint := maxint; + deftab[dmaxint]^.tbind := mklit; + deftab[dargc]^.tbind := deftab[dinteger]^.tbind; + deftab[dinput]^.tbind := deftab[dtext]^.tbind; + deftab[doutput]^.tbind := deftab[dtext]^.tbind; + + for t := tnone to terror do + begin + (* for predefined types: set up pointers to "npredef" nodes + describing type, fill in constant identifying type *) + case t of + tboolean: + typnods[t] := deftab[dboolean]; (* scalar type *) + tchar: + typnods[t] := deftab[dchar]^.tbind; + tinteger: + typnods[t] := deftab[dinteger]^.tbind; + treal: + typnods[t] := deftab[dreal]^.tbind; + ttext: + typnods[t] := deftab[dtext]^.tbind; + tstring: + typnods[t] := deftab[dztring]^.tbind; + tnil, + tset, + tpoly, + tnone: + typnods[t] := mknode(npredef); + terror: + (* no op *) + end;(* case *) + if t in [tchar, tinteger, treal, ttext, tnone, tpoly, + tstring, tnil, tset] then + typnods[t]^.tobtyp := t + end; + + (* fix name and type of field "init" *) + fixinit(defnams[dzinit]^.lid^.istr); + deftab[dzinit]^.tbind := deftab[dinteger]^.tbind; + + for d := dabs to dztring do + linkup(nil, deftab[d]); + + deftab[dchr]^.tfuntyp := typnods[tchar]; + + deftab[deof]^.tfuntyp := typnods[tboolean]; + deftab[deoln]^.tfuntyp := typnods[tboolean]; + deftab[dodd]^.tfuntyp := typnods[tboolean]; + + deftab[dord]^.tfuntyp := typnods[tinteger]; + deftab[dround]^.tfuntyp := typnods[tinteger]; + deftab[dtrunc]^.tfuntyp := typnods[tinteger]; + + deftab[darctan]^.tfuntyp := typnods[treal]; + deftab[dcos]^.tfuntyp := typnods[treal]; + deftab[dsin]^.tfuntyp := typnods[treal]; + deftab[dtan]^.tfuntyp := typnods[treal]; + deftab[dsqrt]^.tfuntyp := typnods[treal]; + deftab[dexp]^.tfuntyp := typnods[treal]; + deftab[dln]^.tfuntyp := typnods[treal]; + + deftab[dsqr]^.tfuntyp := typnods[tpoly]; + deftab[dabs]^.tfuntyp := typnods[tpoly]; + deftab[dpred]^.tfuntyp := typnods[tpoly]; + deftab[dsucc]^.tfuntyp := typnods[tpoly]; + + deftab[dargv]^.tfuntyp := typnods[tnone]; + deftab[ddispose]^.tfuntyp := typnods[tnone]; + deftab[dexit]^.tfuntyp := typnods[tnone]; + deftab[dget]^.tfuntyp := typnods[tnone]; + deftab[dhalt]^.tfuntyp := typnods[tnone]; + deftab[dnew]^.tfuntyp := typnods[tnone]; + deftab[dpack]^.tfuntyp := typnods[tnone]; + deftab[dput]^.tfuntyp := typnods[tnone]; + deftab[dread]^.tfuntyp := typnods[tnone]; + deftab[dreadln]^.tfuntyp := typnods[tnone]; + deftab[dreset]^.tfuntyp := typnods[tnone]; + deftab[drewrite]^.tfuntyp := typnods[tnone]; + deftab[dwrite]^.tfuntyp := typnods[tnone]; + deftab[dwriteln]^.tfuntyp := typnods[tnone]; + deftab[dmessage]^.tfuntyp := typnods[tnone]; + deftab[dunpack]^.tfuntyp := typnods[tnone]; + + (* set up definitions for integer subranges *) + nmachdefs := 0; + defmach(0, 255, 'unsigned char '); (* CPU *) + defmach(-128, 127, 'char '); (* CPU *) + defmach(0, 65535, 'unsigned short '); (* CPU *) + defmach(-32768, 32767, 'short '); (* CPU *) + defmach(-2147483647, 2147483647, 'long '); (* CPU *) +{ defmach(0, 4294967295, 'unsigned long ');}(* CPU *) +end; (* initialize *) + +procedure exit(i : integer); external; (* OS *) + +(* Action to take when an error is detected. *) +procedure error; + +begin + prtmsg(m); + exit(1); (* OS *) + goto 9999 +end; + +(* Action to take when a fatal error is detected. *) +procedure fatal; + +begin + prtmsg(m); + halt (* OS *) + (* goto 9999 *) +end; + + +begin (* program *) + initialize; + if echo then + writeln('# ifdef PASCAL'); + parse; + if echo then + writeln('# else'); + lineno := 0; lastline := 0; + transform; + emit; + if echo then + writeln('# endif'); +9999: + (* the very *) +end. + diff --git a/MultiSource/Benchmarks/MallocBench/p2c/LICENSE.TXT b/MultiSource/Benchmarks/MallocBench/p2c/LICENSE.TXT new file mode 100644 index 00000000..a92f0f7f --- /dev/null +++ b/MultiSource/Benchmarks/MallocBench/p2c/LICENSE.TXT @@ -0,0 +1,10 @@ +p2c - Part of the Malloc Benchmark Suite +------------------------------------------------------------------------------- +All files are licensed under the LLVM license with the following additions: + +These files are licensed to you under the GNU General Public License (any +version). Redistribution must follow the additional restrictions required by +the GPL. + +Please see individiual files for additional copyright information. + diff --git a/MultiSource/Benchmarks/MallocBench/p2c/Makefile b/MultiSource/Benchmarks/MallocBench/p2c/Makefile new file mode 100644 index 00000000..9bd7a176 --- /dev/null +++ b/MultiSource/Benchmarks/MallocBench/p2c/Makefile @@ -0,0 +1,5 @@ +LEVEL = ../../../../../.. +PROG = p2c +RUN_OPTIONS = -v +STDIN_FILENAME = $(SourceDir)/INPUT/mf.p +include ../../../Makefile.multisrc diff --git a/MultiSource/Benchmarks/MallocBench/p2c/citmods.c b/MultiSource/Benchmarks/MallocBench/p2c/citmods.c new file mode 100644 index 00000000..b13604e2 --- /dev/null +++ b/MultiSource/Benchmarks/MallocBench/p2c/citmods.c @@ -0,0 +1,1153 @@ +/* "p2c", a Pascal to C translator. + Copyright (C) 1989, 1990, 1991 Free Software Foundation. + Author's address: daveg@csvax.caltech.edu; 256-80 Caltech/Pasadena CA 91125. + +This program is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation (any version). + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; see the file COPYING. If not, write to +the Free Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ + + + +#define PROTO_CITMODS_C +#include "trans.h" + + + +/* The following functions define special translations for several + * HP Pascal modules developed locally at Caltech. For non-Caltech + * readers this file will serve mainly as a body of examples. + * + * The FuncMacro mechanism (introduced after this file was written) + * provides a simpler method for cases where the function translates + * into some fixed C equivalent. + */ + + + + +/* NEWASM functions */ + + +/* na_fillbyte: equivalent to memset, though convert_size is used to + * generalize the size a bit: na_fillbyte(a, 0, 80) where a is an array + * of integers (4 bytes in HP Pascal) will be translated to + * memset(a, 0, 20 * sizeof(int)). + */ + +Static Stmt *proc_na_fillbyte(ex) +Expr *ex; +{ + ex->args[0] = gentle_cast(ex->args[0], tp_anyptr); + ex->args[2] = convert_size(argbasetype(ex->args[0]), ex->args[2], "NA_FILLBYTE"); + return makestmt_call(makeexpr_bicall_3("memset", tp_void, + ex->args[0], + makeexpr_arglong(ex->args[1], 0), + makeexpr_arglong(ex->args[2], (size_t_long != 0)))); +} + + + +/* This function fills with a 32-bit pattern. If all four bytes of the + * pattern are equal, memset is used, otherwise the na_fill call is + * left unchanged. + */ + +Static Stmt *proc_na_fill(ex) +Expr *ex; +{ + unsigned long ul; + Symbol *sym; + + ex->args[0] = gentle_cast(ex->args[0], tp_anyptr); + ex->args[2] = convert_size(argbasetype(ex->args[0]), ex->args[2], "NA_FILL"); + if (!strcmp(((Meaning *)ex->val.i)->sym->name, "NA_FILLP")) { + sym = findsymbol("NA_FILL"); + if (sym->mbase) + ex->val.i = (long)sym->mbase; + } + if (isliteralconst(ex->args[1], NULL) != 2) + return makestmt_call(ex); + ul = ex->args[1]->val.i; + if ((((ul >> 16) ^ ul) & 0xffff) || /* all four bytes must be the same */ + (((ul >> 8) ^ ul) & 0xff)) + return makestmt_call(ex); + ex->args[1]->val.i &= 0xff; + return makestmt_call(makeexpr_bicall_3("memset", tp_void, + ex->args[0], + makeexpr_arglong(ex->args[1], 0), + makeexpr_arglong(ex->args[2], (size_t_long != 0)))); +} + + + +Static Stmt *proc_na_move(ex) +Expr *ex; +{ + ex->args[0] = gentle_cast(ex->args[0], tp_anyptr); /* source */ + ex->args[1] = gentle_cast(ex->args[1], tp_anyptr); /* dest */ + ex->args[2] = convert_size(choosetype(argbasetype(ex->args[0]), + argbasetype(ex->args[1])), ex->args[2], "NA_MOVE"); + return makestmt_call(makeexpr_bicall_3("memmove", tp_void, + ex->args[1], + ex->args[0], + makeexpr_arglong(ex->args[2], (size_t_long != 0)))); +} + + + +/* This just generalizes the size and leaves the function call alone, + * except that na_exchp (a version using pointer args) is transformed + * to na_exch (a version using VAR args, equivalent in C). + */ + +Static Stmt *proc_na_exch(ex) +Expr *ex; +{ + Symbol *sym; + + ex->args[0] = gentle_cast(ex->args[0], tp_anyptr); + ex->args[1] = gentle_cast(ex->args[1], tp_anyptr); + ex->args[2] = convert_size(choosetype(argbasetype(ex->args[0]), + argbasetype(ex->args[1])), ex->args[2], "NA_EXCH"); + if (!strcmp(((Meaning *)ex->val.i)->sym->name, "NA_EXCHP")) { + sym = findsymbol("NA_EXCH"); + if (sym->mbase) + ex->val.i = (long)sym->mbase; + } + return makestmt_call(ex); +} + + + +Static Expr *func_na_comp(ex) +Expr *ex; +{ + ex->args[0] = gentle_cast(ex->args[0], tp_anyptr); + ex->args[1] = gentle_cast(ex->args[1], tp_anyptr); + ex->args[2] = convert_size(choosetype(argbasetype(ex->args[0]), + argbasetype(ex->args[1])), ex->args[2], "NA_COMP"); + return makeexpr_bicall_3("memcmp", tp_int, + ex->args[0], + ex->args[1], + makeexpr_arglong(ex->args[2], (size_t_long != 0))); +} + + + +Static Expr *func_na_scaneq(ex) +Expr *ex; +{ + Symbol *sym; + + ex->args[0] = gentle_cast(ex->args[0], tp_anyptr); + ex->args[2] = convert_size(argbasetype(ex->args[0]), ex->args[2], "NA_SCANEQ"); + if (!strcmp(((Meaning *)ex->val.i)->sym->name, "NA_SCANEQP")) { + sym = findsymbol("NA_SCANEQ"); + if (sym->mbase) + ex->val.i = (long)sym->mbase; + } + return ex; +} + + + +Static Expr *func_na_scanne(ex) +Expr *ex; +{ + Symbol *sym; + + ex->args[0] = gentle_cast(ex->args[0], tp_anyptr); + ex->args[2] = convert_size(argbasetype(ex->args[0]), ex->args[2], "NA_SCANNE"); + if (!strcmp(((Meaning *)ex->val.i)->sym->name, "NA_SCANNEP")) { + sym = findsymbol("NA_SCANNE"); + if (sym->mbase) + ex->val.i = (long)sym->mbase; + } + return ex; +} + + + +Static Stmt *proc_na_new(ex) +Expr *ex; +{ + Expr *vex, *ex2, *sz = NULL; + Stmt *sp; + + vex = makeexpr_hat(eatcasts(ex->args[0]), 0); + ex2 = ex->args[1]; + if (vex->val.type->kind == TK_POINTER) + ex2 = convert_size(vex->val.type->basetype, ex2, "NA_NEW"); + if (alloczeronil) + sz = copyexpr(ex2); + ex2 = makeexpr_bicall_1(mallocname, tp_anyptr, ex2); + sp = makestmt_assign(copyexpr(vex), ex2); + if (malloccheck) { + sp = makestmt_seq(sp, makestmt_if(makeexpr_rel(EK_EQ, copyexpr(vex), makeexpr_nil()), + makestmt_call(makeexpr_bicall_1(name_ESCAPE, tp_int, + makeexpr_long(-2))), + NULL)); + } + if (sz && !isconstantexpr(sz)) { + if (alloczeronil == 2) + note("Called NA_NEW with variable argument [500]"); + sp = makestmt_if(makeexpr_rel(EK_NE, sz, makeexpr_long(0)), + sp, + makestmt_assign(vex, makeexpr_nil())); + } else + freeexpr(vex); + return sp; +} + + + +Static Stmt *proc_na_dispose(ex) +Expr *ex; +{ + Stmt *sp; + Expr *vex; + + vex = makeexpr_hat(eatcasts(ex->args[0]), 0); + sp = makestmt_call(makeexpr_bicall_1(freename, tp_void, copyexpr(vex))); + if (alloczeronil) { + sp = makestmt_if(makeexpr_rel(EK_NE, vex, makeexpr_nil()), + sp, NULL); + } else + freeexpr(vex); + return sp; +} + + + +/* These functions provide functionality similar to alloca; we just warn + * about them here since alloca would not have been portable enough for + * our purposes anyway. + */ + +Static Stmt *proc_na_alloc(ex) +Expr *ex; +{ + Expr *ex2; + + note("Call to NA_ALLOC [501]"); + ex->args[0] = eatcasts(ex->args[0]); + ex2 = ex->args[0]; + if (ex2->val.type->kind == TK_POINTER && + ex2->val.type->basetype->kind == TK_POINTER) + ex->args[1] = convert_size(ex2->val.type->basetype->basetype, + ex->args[1], "NA_ALLOC"); + return makestmt_call(ex); +} + + + +Static Stmt *proc_na_outeralloc(ex) +Expr *ex; +{ + note("Call to NA_OUTERALLOC [502]"); + return makestmt_call(ex); +} + + + +Static Stmt *proc_na_free(ex) +Expr *ex; +{ + note("Call to NA_FREE [503]"); + return makestmt_call(ex); +} + + + + +Static Expr *func_na_memavail(ex) +Expr *ex; +{ + freeexpr(ex); + return makeexpr_bicall_0("memavail", tp_integer); +} + + + + +/* A simple collection of bitwise operations. */ + +Static Expr *func_na_and(ex) +Expr *ex; +{ + Expr *ex0, *ex1; + + ex0 = makeexpr_unlongcast(ex->args[0]); + ex1 = makeexpr_unlongcast(ex->args[1]); + return makeexpr_bin(EK_BAND, tp_integer, ex0, ex1); +} + + + +Static Expr *func_na_bic(ex) +Expr *ex; +{ + Expr *ex0, *ex1; + + ex0 = makeexpr_unlongcast(ex->args[0]); + ex1 = makeexpr_unlongcast(ex->args[1]); + return makeexpr_bin(EK_BAND, tp_integer, + ex0, + makeexpr_un(EK_BNOT, ex1->val.type, ex1)); +} + + + +Static Expr *func_na_or(ex) +Expr *ex; +{ + Expr *ex0, *ex1; + + ex0 = makeexpr_unlongcast(ex->args[0]); + ex1 = makeexpr_unlongcast(ex->args[1]); + return makeexpr_bin(EK_BOR, tp_integer, ex0, ex1); +} + + + +Static Expr *func_na_xor(ex) +Expr *ex; +{ + Expr *ex0, *ex1; + + ex0 = makeexpr_unlongcast(ex->args[0]); + ex1 = makeexpr_unlongcast(ex->args[1]); + return makeexpr_bin(EK_BXOR, tp_integer, ex0, ex1); +} + + + +Static Expr *func_na_not(ex) +Expr *ex; +{ + ex = makeexpr_unlongcast(grabarg(ex, 0)); + return makeexpr_un(EK_BNOT, ex->val.type, ex); +} + + + +Static Expr *func_na_mask(ex) +Expr *ex; +{ + Expr *ex0, *ex1; + + ex0 = makeexpr_unlongcast(ex->args[0]); + ex1 = makeexpr_unlongcast(ex->args[1]); + ex = makeexpr_bin(EK_BAND, tp_integer, ex0, ex1); + return makeexpr_rel(EK_NE, ex, makeexpr_long(0)); +} + + + +Static int check0_31(ex) +Expr *ex; +{ + if (isliteralconst(ex, NULL) == 2) + return (ex->val.i >= 0 && ex->val.i <= 31); + else + return (assumebits != 0); +} + + + +/* This function is defined to test a bit of an integer, returning false + * if the bit number is out of range. It is only safe to use C bitwise + * ops if we can prove the bit number is always in range, or if the + * user has asked us to assume that it is. Lacking flow analysis, + * we settle for checking constants only. + */ + +Static Expr *func_na_test(ex) +Expr *ex; +{ + Expr *ex1; + int longness; + + if (!check0_31(ex->args[0])) + return ex; + ex1 = makeexpr_unlongcast(ex->args[1]); + longness = (exprlongness(ex1) != 0); + return makeexpr_rel(EK_NE, + makeexpr_bin(EK_BAND, tp_integer, + ex1, + makeexpr_bin(EK_LSH, tp_integer, + makeexpr_longcast(makeexpr_long(1), longness), + makeexpr_unlongcast(ex->args[0]))), + makeexpr_long(0)); +} + + + +Static Stmt *proc_na_set(ex) +Expr *ex; +{ + Stmt *sp; + Expr *vex; + Meaning *tvar; + + if (!check0_31(ex->args[0])) + return makestmt_call(ex); + if (!nosideeffects(ex->args[1], 1)) { + tvar = makestmttempvar(ex->args[1]->val.type, name_TEMP); + sp = makestmt_assign(makeexpr_var(tvar), ex->args[1]); + vex = makeexpr_hat(makeexpr_var(tvar), 0); + } else { + sp = NULL; + vex = makeexpr_hat(ex->args[1], 0); + } + sp = makestmt_seq(sp, + makestmt_assign(vex, + makeexpr_bin(EK_BOR, tp_integer, + copyexpr(vex), + makeexpr_bin(EK_LSH, tp_integer, + makeexpr_longcast(makeexpr_long(1), 1), + makeexpr_unlongcast(ex->args[0]))))); + return sp; +} + + + +Static Stmt *proc_na_clear(ex) +Expr *ex; +{ + Stmt *sp; + Expr *vex; + Meaning *tvar; + + if (!check0_31(ex->args[0])) + return makestmt_call(ex); + if (!nosideeffects(ex->args[1], 1)) { + tvar = makestmttempvar(ex->args[1]->val.type, name_TEMP); + sp = makestmt_assign(makeexpr_var(tvar), ex->args[1]); + vex = makeexpr_hat(makeexpr_var(tvar), 0); + } else { + sp = NULL; + vex = makeexpr_hat(ex->args[1], 0); + } + sp = makestmt_seq(sp, + makestmt_assign(vex, + makeexpr_bin(EK_BAND, tp_integer, + copyexpr(vex), + makeexpr_un(EK_BNOT, tp_integer, + makeexpr_bin(EK_LSH, tp_integer, + makeexpr_longcast(makeexpr_long(1), 1), + makeexpr_unlongcast(ex->args[0])))))); + return sp; +} + + + +Static Expr *func_na_po2(ex) +Expr *ex; +{ + if (!check0_31(ex->args[0])) + return ex; + return makeexpr_bin(EK_LSH, tp_integer, + makeexpr_longcast(makeexpr_long(1), 1), + makeexpr_unlongcast(grabarg(ex, 0))); +} + + + +Static Expr *func_na_lobits(ex) +Expr *ex; +{ + if (!check0_31(ex->args[0])) + return ex; + return makeexpr_un(EK_BNOT, tp_integer, + makeexpr_bin(EK_LSH, tp_integer, + makeexpr_longcast(makeexpr_long(-1), 1), + makeexpr_unlongcast(grabarg(ex, 0)))); +} + + + +Static Expr *func_na_hibits(ex) +Expr *ex; +{ + if (!check0_31(ex->args[0])) + return ex; + return makeexpr_bin(EK_LSH, tp_integer, + makeexpr_longcast(makeexpr_long(-1), 1), + makeexpr_minus(makeexpr_long(32), + makeexpr_unlongcast(grabarg(ex, 0)))); +} + + + +/* This function does an arithmetic shift left, or right for negative shift + * count. We translate into a C shift only if we are confident of the + * sign of the shift count. + */ + +Static Expr *func_na_asl(ex) +Expr *ex; +{ + Expr *ex2; + + ex2 = makeexpr_unlongcast(copyexpr(ex->args[0])); + if (expr_is_neg(ex2)) { + if (signedshift == 0 || signedshift == 2) + return ex; + if (possiblesigns(ex2) & 4) { + if (assumesigns) + note("Assuming count for NA_ASL is negative [504]"); + else + return ex; + } + if (signedshift != 1) + note("Assuming >> is an arithmetic shift [505]"); + return makeexpr_bin(EK_RSH, tp_integer, + grabarg(ex, 1), makeexpr_neg(ex2)); + } else { + if (possiblesigns(ex2) & 1) { + if (assumesigns) + note("Assuming count for NA_ASL is positive [504]"); + else + return ex; + } + return makeexpr_bin(EK_LSH, tp_integer, grabarg(ex, 1), ex2); + } +} + + + +Static Expr *func_na_lsl(ex) +Expr *ex; +{ + Expr *ex2; + + ex2 = makeexpr_unlongcast(copyexpr(ex->args[0])); + if (expr_is_neg(ex2)) { + if (possiblesigns(ex2) & 4) { + if (assumesigns) + note("Assuming count for NA_LSL is negative [506]"); + else + return ex; + } + return makeexpr_bin(EK_RSH, tp_integer, + force_unsigned(grabarg(ex, 1)), + makeexpr_neg(ex2)); + } else { + if (possiblesigns(ex2) & 1) { + if (assumesigns) + note("Assuming count for NA_LSL is positive [506]"); + else + return ex; + } + return makeexpr_bin(EK_LSH, tp_integer, grabarg(ex, 1), ex2); + } +} + + + +/* These bit-field operations were generalized slightly on the way to C; + * they used to perform D &= S and now perform D = S1 & S2. + */ + +Static Stmt *proc_na_bfand(ex) +Expr *ex; +{ + Stmt *sp; + Meaning *tvar; + + if (!nosideeffects(ex->args[2], 1)) { + tvar = makestmttempvar(ex->args[2]->val.type, name_TEMP); + sp = makestmt_assign(makeexpr_var(tvar), ex->args[2]); + ex->args[2] = makeexpr_var(tvar); + } else + sp = NULL; + insertarg(&ex, 1, copyexpr(ex->args[2])); + return makestmt_seq(sp, makestmt_call(ex)); +} + + + +Static Stmt *proc_na_bfbic(ex) +Expr *ex; +{ + return proc_na_bfand(ex); +} + + + +Static Stmt *proc_na_bfor(ex) +Expr *ex; +{ + return proc_na_bfand(ex); +} + + + +Static Stmt *proc_na_bfxor(ex) +Expr *ex; +{ + return proc_na_bfand(ex); +} + + + +Static Expr *func_imin(ex) +Expr *ex; +{ + return makeexpr_bicall_2("P_imin2", tp_integer, + ex->args[0], ex->args[1]); +} + + + +Static Expr *func_imax(ex) +Expr *ex; +{ + return makeexpr_bicall_2("P_imax2", tp_integer, + ex->args[0], ex->args[1]); +} + + + +/* Unsigned non-overflowing arithmetic functions in Pascal; we translate + * into plain arithmetic in C and assume C doesn't check for overflow. + * (A valid assumption in the case when this was used.) + */ + +Static Expr *func_na_add(ex) +Expr *ex; +{ + return makeexpr_plus(makeexpr_unlongcast(ex->args[0]), + makeexpr_unlongcast(ex->args[1])); +} + + + +Static Expr *func_na_sub(ex) +Expr *ex; +{ + return makeexpr_minus(makeexpr_unlongcast(ex->args[0]), + makeexpr_unlongcast(ex->args[1])); +} + + + +extern Stmt *proc_exit(); /* from funcs.c */ + +Static Stmt *proc_return() +{ + return proc_exit(); +} + + + +Static Expr *func_charupper(ex) +Expr *ex; +{ + return makeexpr_bicall_1("toupper", tp_char, + grabarg(ex, 0)); +} + + + +Static Expr *func_charlower(ex) +Expr *ex; +{ + return makeexpr_bicall_1("tolower", tp_char, + grabarg(ex, 0)); +} + + + +/* Convert an integer to its string representation. We produce a sprintf + * into a temporary variable; the temporary will probably be eliminated + * as the surrounding code is translated. + */ + +Static Expr *func_strint(ex) +Expr *ex; +{ + Expr *ex2; + + ex2 = makeexpr_forcelongness(ex->args[1]); + return makeexpr_bicall_3("sprintf", ex->val.type, + ex->args[0], + makeexpr_string((exprlongness(ex2) > 0) ? "%ld" : "%d"), + ex2); +} + + + +Static Expr *func_strint2(ex) +Expr *ex; +{ + Expr *ex2, *len, *fmt; + + if (checkconst(ex->args[2], 0) || checkconst(ex->args[2], 1)) + return func_strint(ex); + if (expr_is_neg(ex->args[2])) { + if (possiblesigns(ex->args[2]) & 4) { + if (assumesigns) + note("Assuming width for STRINT2 is negative [507]"); + else + return ex; + } + ex2 = makeexpr_forcelongness(ex->args[1]); + fmt = makeexpr_string((exprlongness(ex2) > 0) ? "%0*ld" : "%0*d"); + len = makeexpr_neg(makeexpr_longcast(ex->args[2], 0)); + } else { + if (possiblesigns(ex->args[2]) & 1) { + if (assumesigns) + note("Assuming width for STRINT2 is positive [507]"); + else + return ex; + } + ex2 = makeexpr_forcelongness(ex->args[1]); + fmt = makeexpr_string((exprlongness(ex2) > 0) ? "%*ld" : "%*d"); + len = makeexpr_longcast(ex->args[2], 0); + } + ex = makeexpr_bicall_4("sprintf", ex->val.type, + ex->args[0], fmt, len, ex2); + return cleansprintf(ex); +} + + + +Static Expr *func_strhex(ex) +Expr *ex; +{ + Expr *ex2, *ex3; + Value val; + + if (isliteralconst(ex->args[2], &val) == 2) { + ex2 = makeexpr_forcelongness(ex->args[1]); + if (val.i < 1 || val.i > 8) { + ex = makeexpr_bicall_3("sprintf", ex->val.type, + ex->args[0], + makeexpr_string((exprlongness(ex2) > 0) ? "%lX" : "%X"), + ex2); + } else { + if (val.i < 8) { + ex3 = makeexpr_long((1 << (val.i*4)) - 1); + insertarg(&ex3, 0, makeexpr_name("%#lx", tp_integer)); + ex2 = makeexpr_bin(EK_BAND, ex2->val.type, ex2, ex3); + } + ex = makeexpr_bicall_3("sprintf", ex->val.type, + ex->args[0], + makeexpr_string(format_d((exprlongness(ex2) > 0) ? "%%.%ldlX" : + "%%.%ldX", + val.i)), + ex2); + } + } + return ex; +} + + + +Static Expr *func_strreal(ex) +Expr *ex; +{ + return makeexpr_bicall_3("sprintf", ex->val.type, + ex->args[0], + makeexpr_string("%g"), + ex->args[1]); +} + + + +Static Expr *func_strchar(ex) +Expr *ex; +{ + return makeexpr_bicall_3("sprintf", ex->val.type, + ex->args[0], + makeexpr_string("%c"), + ex->args[1]); +} + + + +Static Expr *func_strreadint(ex) +Expr *ex; +{ + return makeexpr_bicall_3("strtol", tp_integer, + grabarg(ex, 0), + makeexpr_nil(), + makeexpr_long(0)); +} + + + +Static Expr *func_strreadreal(ex) +Expr *ex; +{ + return makeexpr_bicall_1("atof", tp_longreal, + grabarg(ex, 0)); +} + + + +Static Stmt *proc_strappendc(ex) +Expr *ex; +{ + Expr *ex2; + + ex2 = makeexpr_hat(ex->args[0], 0); + return makestmt_assign(ex2, makeexpr_concat(copyexpr(ex2), ex->args[1], 0)); +} + + + +/* Check if a string begins with a given prefix; this is easy if the + * prefix is known at compile-time. + */ + +Static Expr *func_strbegins(ex) +Expr *ex; +{ + Expr *ex1, *ex2; + + ex1 = ex->args[0]; + ex2 = ex->args[1]; + if (ex2->kind == EK_CONST) { + if (ex2->val.i == 1) { + return makeexpr_rel(EK_EQ, + makeexpr_hat(ex1, 0), + makeexpr_char(ex2->val.s[0])); + } else { + return makeexpr_rel(EK_EQ, + makeexpr_bicall_3("strncmp", tp_int, + ex1, + ex2, + makeexpr_arglong(makeexpr_long(ex2->val.i), (size_t_long != 0))), + makeexpr_long(0)); + } + } + return ex; +} + + + +Static Expr *func_strcontains(ex) +Expr *ex; +{ + return makeexpr_rel(EK_NE, + makeexpr_bicall_2("strpbrk", tp_strptr, + ex->args[0], + ex->args[1]), + makeexpr_nil()); +} + + + +/* Extract a substring of a string. If arguments are out-of-range, extract + * an empty or shorter substring. Here, the length=infinity and constant + * starting index cases are handled specially. + */ + +Static Expr *func_strsub(ex) +Expr *ex; +{ + if (isliteralconst(ex->args[3], NULL) == 2 && + ex->args[3]->val.i >= stringceiling) { + return makeexpr_bicall_3("sprintf", ex->val.type, + ex->args[0], + makeexpr_string("%s"), + bumpstring(ex->args[1], + makeexpr_unlongcast(ex->args[2]), 1)); + } + if (checkconst(ex->args[2], 1)) { + return makeexpr_addr(makeexpr_substring(ex->args[0], ex->args[1], + ex->args[2], ex->args[3])); + } + ex->args[2] = makeexpr_arglong(ex->args[2], 0); + ex->args[3] = makeexpr_arglong(ex->args[3], 0); + return ex; +} + + + +Static Expr *func_strpart(ex) +Expr *ex; +{ + return func_strsub(ex); /* all the special cases match */ +} + + + +Static Expr *func_strequal(ex) +Expr *ex; +{ + if (!*strcicmpname) + return ex; + return makeexpr_rel(EK_EQ, + makeexpr_bicall_2(strcicmpname, tp_int, + ex->args[0], ex->args[1]), + makeexpr_long(0)); +} + + + +Static Expr *func_strcmp(ex) +Expr *ex; +{ + return makeexpr_bicall_2("strcmp", tp_int, ex->args[0], ex->args[1]); +} + + + +Static Expr *func_strljust(ex) +Expr *ex; +{ + return makeexpr_bicall_4("sprintf", ex->val.type, + ex->args[0], + makeexpr_string("%-*s"), + makeexpr_longcast(ex->args[2], 0), + ex->args[1]); +} + + + +Static Expr *func_strrjust(ex) +Expr *ex; +{ + return makeexpr_bicall_4("sprintf", ex->val.type, + ex->args[0], + makeexpr_string("%*s"), + makeexpr_longcast(ex->args[2], 0), + ex->args[1]); +} + + + + +/* The procedure strnew(p,s) is converted into an assignment p = strdup(s). */ + +Static Stmt *proc_strnew(ex) +Expr *ex; +{ + return makestmt_assign(makeexpr_hat(ex->args[0], 0), + makeexpr_bicall_1("strdup", ex->args[1]->val.type, + ex->args[1])); +} + + + +/* These procedures are also changed to functions returning a result. */ + +Static Stmt *proc_strlist_add(ex) +Expr *ex; +{ + return makestmt_assign(makeexpr_hat(ex->args[1], 0), + makeexpr_bicall_2("strlist_add", ex->args[0]->val.type->basetype, + ex->args[0], + ex->args[2])); +} + + + +Static Stmt *proc_strlist_append(ex) +Expr *ex; +{ + return makestmt_assign(makeexpr_hat(ex->args[1], 0), + makeexpr_bicall_2("strlist_append", ex->args[0]->val.type->basetype, + ex->args[0], + ex->args[2])); +} + + + +Static Stmt *proc_strlist_insert(ex) +Expr *ex; +{ + return makestmt_assign(makeexpr_hat(ex->args[1], 0), + makeexpr_bicall_2("strlist_insert", ex->args[0]->val.type->basetype, + ex->args[0], + ex->args[2])); +} + + + + + + + + + +/* NEWCI functions */ + + +Static Stmt *proc_fixfname(ex) +Expr *ex; +{ + if (ex->args[1]->kind == EK_CONST) + lwc(ex->args[1]->val.s); /* Unix uses lower-case suffixes */ + return makestmt_call(ex); +} + + +Static Stmt *proc_forcefname(ex) +Expr *ex; +{ + return proc_fixfname(ex); +} + + +/* In Pascal these were variables of type pointer-to-text; we translate + * them as, e.g., &stdin. Note that even though &stdin is not legal in + * many systems, in the common usage of writeln(stdin^) the & will + * cancel out in a later stage of the translation. + */ + +Static Expr *func_stdin() +{ + return makeexpr_addr(makeexpr_var(mp_input)); +} + + +Static Expr *func_stdout() +{ + return makeexpr_addr(makeexpr_var(mp_output)); +} + + +Static Expr *func_stderr() +{ + return makeexpr_addr(makeexpr_var(mp_stderr)); +} + + + + + + + + +/* MYLIB functions */ + + +Static Stmt *proc_m_color(ex) +Expr *ex; +{ + int i; + long val; + + if (ex->kind == EK_PLUS) { + for (i = 0; i < ex->nargs; i++) { + if (isconstexpr(ex->args[i], &val)) { + if (val > 0 && (val & 15) == 0) { + note("M_COLOR called with suspicious argument [508]"); + } + } + } + } else if (ex->kind == EK_CONST) { + if (ex->val.i >= 16 && ex->val.i < 255) { /* accept true colors and m_trans */ + note("M_COLOR called with suspicious argument [508]"); + } + } + return makestmt_call(ex); +} + + + + + + + +void citmods(name, defn) +char *name; +int defn; +{ + if (!strcmp(name, "NEWASM")) { + makestandardproc("na_fillbyte", proc_na_fillbyte); + makestandardproc("na_fill", proc_na_fill); + makestandardproc("na_fillp", proc_na_fill); + makestandardproc("na_move", proc_na_move); + makestandardproc("na_movep", proc_na_move); + makestandardproc("na_exch", proc_na_exch); + makestandardproc("na_exchp", proc_na_exch); + makestandardfunc("na_comp", func_na_comp); + makestandardfunc("na_compp", func_na_comp); + makestandardfunc("na_scaneq", func_na_scaneq); + makestandardfunc("na_scaneqp", func_na_scaneq); + makestandardfunc("na_scanne", func_na_scanne); + makestandardfunc("na_scannep", func_na_scanne); + makestandardproc("na_new", proc_na_new); + makestandardproc("na_dispose", proc_na_dispose); + makestandardproc("na_alloc", proc_na_alloc); + makestandardproc("na_outeralloc", proc_na_outeralloc); + makestandardproc("na_free", proc_na_free); + makestandardfunc("na_memavail", func_na_memavail); + makestandardfunc("na_and", func_na_and); + makestandardfunc("na_bic", func_na_bic); + makestandardfunc("na_or", func_na_or); + makestandardfunc("na_xor", func_na_xor); + makestandardfunc("na_not", func_na_not); + makestandardfunc("na_mask", func_na_mask); + makestandardfunc("na_test", func_na_test); + makestandardproc("na_set", proc_na_set); + makestandardproc("na_clear", proc_na_clear); + makestandardfunc("na_po2", func_na_po2); + makestandardfunc("na_hibits", func_na_hibits); + makestandardfunc("na_lobits", func_na_lobits); + makestandardfunc("na_asl", func_na_asl); + makestandardfunc("na_lsl", func_na_lsl); + makestandardproc("na_bfand", proc_na_bfand); + makestandardproc("na_bfbic", proc_na_bfbic); + makestandardproc("na_bfor", proc_na_bfor); + makestandardproc("na_bfxor", proc_na_bfxor); + makestandardfunc("imin", func_imin); + makestandardfunc("imax", func_imax); + makestandardfunc("na_add", func_na_add); + makestandardfunc("na_sub", func_na_sub); + makestandardproc("return", proc_return); + makestandardfunc("charupper", func_charupper); + makestandardfunc("charlower", func_charlower); + makestandardfunc("strint", func_strint); + makestandardfunc("strint2", func_strint2); + makestandardfunc("strhex", func_strhex); + makestandardfunc("strreal", func_strreal); + makestandardfunc("strchar", func_strchar); + makestandardfunc("strreadint", func_strreadint); + makestandardfunc("strreadreal", func_strreadreal); + makestandardproc("strappendc", proc_strappendc); + makestandardfunc("strbegins", func_strbegins); + makestandardfunc("strcontains", func_strcontains); + makestandardfunc("strsub", func_strsub); + makestandardfunc("strpart", func_strpart); + makestandardfunc("strequal", func_strequal); + makestandardfunc("strcmp", func_strcmp); + makestandardfunc("strljust", func_strljust); + makestandardfunc("strrjust", func_strrjust); + makestandardproc("strnew", proc_strnew); + makestandardproc("strlist_add", proc_strlist_add); + makestandardproc("strlist_append", proc_strlist_append); + makestandardproc("strlist_insert", proc_strlist_insert); + } else if (!strcmp(name, "NEWCI")) { + makestandardproc("fixfname", proc_fixfname); + makestandardproc("forcefname", proc_forcefname); + makestandardfunc("stdin", func_stdin); + makestandardfunc("stdout", func_stdout); + makestandardfunc("stderr", func_stderr); + } else if (!strcmp(name, "MYLIB")) { + makestandardproc("m_color", proc_m_color); + } +} + + + + +/* End. */ + + + diff --git a/MultiSource/Benchmarks/MallocBench/p2c/comment.c b/MultiSource/Benchmarks/MallocBench/p2c/comment.c new file mode 100644 index 00000000..8cc2d456 --- /dev/null +++ b/MultiSource/Benchmarks/MallocBench/p2c/comment.c @@ -0,0 +1,466 @@ +/* "p2c", a Pascal to C translator. + Copyright (C) 1989, 1990, 1991 Free Software Foundation. + Author's address: daveg@csvax.caltech.edu; 256-80 Caltech/Pasadena CA 91125. + +This program is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation (any version). + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; see the file COPYING. If not, write to +the Free Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ + + + +#define PROTO_COMMENT_C +#include "trans.h" + + + +Static int cmttablesize; +Static uchar *cmttable; + +Static int grabbed_comment; + + + + +/* Special comment forms: + + \001\001\001... Blank line(s), one \001 char per blank line + \002text... Additional line for previous comment + \003text... Additional comment line, absolutely indented + \004text... Note or warning line, unindented + +*/ + + + + +void setup_comment() +{ + curcomments = NULL; + cmttablesize = 200; + cmttable = ALLOC(cmttablesize, uchar, misc); + grabbed_comment = 0; +} + + + + + +int commentlen(cmt) +Strlist *cmt; +{ + if (cmt) + if (*(cmt->s)) + return strlen(cmt->s) + 4; + else + return 5; + else + return 0; +} + + +int commentvisible(cmt) +Strlist *cmt; +{ + return (cmt && + getcommentkind(cmt) != CMT_DONE && + ((eatcomments != 1 && eatcomments != 2) || + isembedcomment(cmt))); +} + + + + + + +/* If preceding statement's POST comments include blank lines, + steal all comments after longest stretch of blank lines as + PRE comments for the next statement. */ + +void steal_comments(olds, news, always) +long olds, news; +int always; +{ + Strlist *cmt, *cmtfirst = NULL, *cmtblank = NULL; + int len, longest; + + for (cmt = curcomments; cmt; cmt = cmt->next) { + if ((cmt->value & CMT_MASK) == olds && + getcommentkind(cmt) == CMT_POST) { + if (!cmtfirst) + cmtfirst = cmt; + } else { + cmtfirst = NULL; + } + } + if (cmtfirst) { + if (!always) { + longest = 0; + for (cmt = cmtfirst; cmt; cmt = cmt->next) { + if (cmt->s[0] == '\001') { /* blank line(s) */ + len = strlen(cmt->s); + if (len > longest) { + longest = len; + cmtblank = cmt; + } + } + } + if (longest > 0) { + if (blankafter) + cmtfirst = cmtblank->next; + else + cmtfirst = cmtblank; + } else if (commentafter == 1) + cmtfirst = NULL; + } + changecomments(cmtfirst, CMT_POST, olds, CMT_PRE, news); + } +} + + + +Strlist *fixbeginendcomment(cmt) +Strlist *cmt; +{ + char *cp, *cp2; + + if (!cmt) + return NULL; + cp = cmt->s; + while (isspace(*cp)) + cp++; + if (!strcincmp(cp, "procedure ", 10)) { /* remove "PROCEDURE" keyword */ + strcpy(cp, cp+10); + } else if (!strcincmp(cp, "function ", 9)) { + strcpy(cp, cp+9); + } + while (isspace(*cp)) + cp++; + if (!*cp) + return NULL; + if (getcommentkind(cmt) == CMT_ONBEGIN) { + cp2 = curctx->sym->name; + while (*cp2) { + if (toupper(*cp2++) != toupper(*cp++)) + break; + } + while (isspace(*cp)) + cp++; + if (!*cp2 && !*cp) + return NULL; /* eliminate function-begin comment */ + } + return cmt; +} + + + + +Static void attach_mark(sp) +Stmt *sp; +{ + long serial; + + while (sp) { + serial = sp->serial; + if (serial >= 0 && serial < cmttablesize) { + cmttable[serial]++; + if (sp->kind == SK_IF && serial+1 < cmttablesize) + cmttable[serial+1]++; /* the "else" branch */ + } + attach_mark(sp->stm1); + attach_mark(sp->stm2); + sp = sp->next; + } +} + + + +void attach_comments(sbase) +Stmt *sbase; +{ + Strlist *cmt; + long serial, i, j; + int kind; + + if (spitorphancomments) + return; + if (serialcount >= cmttablesize) { + cmttablesize = serialcount + 100; + cmttable = REALLOC(cmttable, cmttablesize, uchar); + } + for (i = 0; i < cmttablesize; i++) + cmttable[i] = 0; + attach_mark(sbase); + for (cmt = curcomments; cmt; cmt = cmt->next) { + serial = cmt->value & CMT_MASK; + kind = getcommentkind(cmt); + if (serial < 0 || serial >= cmttablesize || cmttable[serial]) + continue; + i = 0; + j = 0; + do { + if (commentafter == 1) { + j++; + if (j % 3 == 0) + i++; + } else if (commentafter == 0) { + i++; + if (i % 3 == 0) + j++; + } else { + i++; + j++; + } + if (serial+i < cmttablesize && cmttable[serial+i]) { + setcommentkind(cmt, CMT_PRE); + cmt->value += i; + break; + } + if (serial-j > 0 && cmttable[serial-j]) { + setcommentkind(cmt, CMT_POST); + cmt->value -= j; + break; + } + } while (serial+i < cmttablesize || serial-j > 0); + } +} + + + + +void setcommentkind(cmt, kind) +Strlist *cmt; +int kind; +{ + cmt->value = (cmt->value & CMT_MASK) | (kind << CMT_SHIFT); +} + + + +void commentline(kind) +int kind; +{ + char *cp; + Strlist *sl; + + if (grabbed_comment) { + grabbed_comment = 0; + return; + } + if (blockkind == TOK_IMPORT || skipping_module) + return; + if (eatcomments == 1) + return; + for (cp = curtokbuf; (cp = my_strchr(cp, '*')) != NULL; ) { + if (*++cp == '/') { + cp[-1] = '%'; + note("Changed \"* /\" to \"% /\" in comment [140]"); + } + } + sl = strlist_append(&curcomments, curtokbuf); + sl->value = curserial; + setcommentkind(sl, kind); +} + + + +void addnote(msg, serial) +char *msg; +long serial; +{ + int len1, len2, xextra, extra; + int defer = (notephase > 0 && spitcomments == 0); + Strlist *sl, *base = NULL, **pbase = (defer) ? &curcomments : &base; + char *prefix; + + if (defer && (outf != stdout || !quietmode)) + printf("%s, line %d: %s\n", infname, inf_lnum, msg); + else if (outf != stdout) + printf("%s, line %d/%d: %s\n", infname, inf_lnum, outf_lnum, msg); + if (verbose) + fprintf(logf, "%s, %d/%d: %s\n", infname, inf_lnum, outf_lnum, msg); + if (notephase == 2 || regression) + prefix = format_s("\004 p2c: %s:", infname); + else + prefix = format_sd("\004 p2c: %s, line %d:", infname, inf_lnum); + len1 = strlen(prefix); + len2 = strlen(msg) + 2; + if (len1 + len2 < linewidth-4) { + msg = format_ss("%s %s ", prefix, msg); + } else { + extra = xextra = 0; + while (len2 - extra > linewidth-6) { + while (extra < len2 && !isspace(msg[extra])) + extra++; + xextra = extra; + while (extra < len2 && isspace(msg[extra])) + extra++; + } + prefix = format_sds("%s %.*s", prefix, xextra, msg); + msg += extra; + sl = strlist_append(pbase, prefix); + sl->value = serial; + setcommentkind(sl, CMT_POST); + msg = format_s("\003 * %s ", msg); + } + sl = strlist_append(pbase, msg); + sl->value = serial; + setcommentkind(sl, CMT_POST); + outputmode++; + outcomments(base); + outputmode--; +} + + + + + +/* Grab a comment off the end of the current line */ +Strlist *grabcomment(kind) +int kind; +{ + char *cp, *cp2; + Strlist *cmt, *savecmt; + + if (grabbed_comment || spitcomments == 1) + return NULL; + cp = inbufptr; + while (isspace(*cp)) + cp++; + if (*cp == ';' || *cp == ',' || *cp == '.') + cp++; + while (isspace(*cp)) + cp++; + cp2 = curtokbuf; + if (*cp == '{') { + cp++; + while (*cp && *cp != '}') + *cp2++ = *cp++; + if (!*cp) + return NULL; + cp++; + } else if (*cp == '(' && cp[1] == '*') { + cp += 2; + while (*cp && (*cp != '*' || cp[1] != ')')) + *cp2++ = *cp++; + if (!*cp) + return NULL; + cp += 2; + } else + return NULL; + while (isspace(*cp)) + cp++; + if (*cp) + return NULL; + *cp2 = 0; + savecmt = curcomments; + curcomments = NULL; + commentline(kind); + cmt = curcomments; + curcomments = savecmt; + grabbed_comment = 1; + if (cmtdebug > 1) + fprintf(outf, "Grabbed comment [%d] \"%s\"\n", cmt->value & CMT_MASK, cmt->s); + return cmt; +} + + + +int matchcomment(cmt, kind, stamp) +Strlist *cmt; +int kind, stamp; +{ + if (spitcomments == 1 && (cmt->value & CMT_MASK) != 10000 && + *cmt->s != '\001' && (kind >= 0 || stamp >= 0)) + return 0; + if (!cmt || getcommentkind(cmt) == CMT_DONE) + return 0; + if (stamp >= 0 && (cmt->value & CMT_MASK) != stamp) + return 0; + if (kind >= 0) { + if (kind & CMT_NOT) { + if (getcommentkind(cmt) == kind - CMT_NOT) + return 0; + } else { + if (getcommentkind(cmt) != kind) + return 0; + } + } + return 1; +} + + + +Strlist *findcomment(cmt, kind, stamp) +Strlist *cmt; +int kind, stamp; +{ + while (cmt && !matchcomment(cmt, kind, stamp)) + cmt = cmt->next; + if (cmt && cmtdebug > 1) + fprintf(outf, "Found comment [%d] \"%s\"\n", cmt->value & CMT_MASK, cmt->s); + return cmt; +} + + + +Strlist *extractcomment(cmt, kind, stamp) +Strlist **cmt; +int kind, stamp; +{ + Strlist *base, **last, *sl; + + last = &base; + while ((sl = *cmt)) { + if (matchcomment(sl, kind, stamp)) { + if (cmtdebug > 1) + fprintf(outf, "Extracted comment [%d] \"%s\"\n", + sl->value & CMT_MASK, sl->s); + *cmt = sl->next; + *last = sl; + last = &sl->next; + } else + cmt = &sl->next; + } + *last = NULL; + return base; +} + + +void changecomments(cmt, okind, ostamp, kind, stamp) +Strlist *cmt; +int okind, ostamp, kind, stamp; +{ + while (cmt) { + if (matchcomment(cmt, okind, ostamp)) { + if (cmtdebug > 1) + fprintf(outf, "Changed comment [%s:%d] \"%s\" ", + CMT_NAMES[getcommentkind(cmt)], + cmt->value & CMT_MASK, cmt->s); + if (kind >= 0) + setcommentkind(cmt, kind); + if (stamp >= 0) + cmt->value = (cmt->value & ~CMT_MASK) | stamp; + if (cmtdebug > 1) + fprintf(outf, " to [%s:%d]\n", + CMT_NAMES[getcommentkind(cmt)], cmt->value & CMT_MASK); + } + cmt = cmt->next; + } +} + + + + + + +/* End. */ + diff --git a/MultiSource/Benchmarks/MallocBench/p2c/decl.c b/MultiSource/Benchmarks/MallocBench/p2c/decl.c new file mode 100644 index 00000000..8769a395 --- /dev/null +++ b/MultiSource/Benchmarks/MallocBench/p2c/decl.c @@ -0,0 +1,5444 @@ +/* "p2c", a Pascal to C translator. + Copyright (C) 1989, 1990, 1991 Free Software Foundation. + Author's address: daveg@csvax.caltech.edu; 256-80 Caltech/Pasadena CA 91125. + +This program is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation (any version). + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; see the file COPYING. If not, write to +the Free Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ + + + +#define PROTO_DECL_C +#include "trans.h" + + + +#define MAXIMPORTS 100 + + + +Static struct ptrdesc { + struct ptrdesc *next; + Symbol *sym; + Type *tp; +} *ptrbase; + +Static struct ctxstack { + struct ctxstack *next; + Meaning *ctx, *ctxlast; + struct tempvarlist *tempvars; + int tempvarcount, importmark; +} *ctxtop; + +Static struct tempvarlist { + struct tempvarlist *next; + Meaning *tvar; + int active; +} *tempvars, *stmttempvars; + +Static int tempvarcount; + +Static int stringtypecachesize; +Static Type **stringtypecache; + +Static Meaning *importlist[MAXIMPORTS]; +Static int firstimport; + +Static Type *tp_special_anyptr; + +Static int wasaliased; +Static int deferallptrs; +Static int anydeferredptrs; +Static int silentalreadydef; +Static int nonloclabelcount; + +Static Strlist *varstructdecllist; + + + + +Static Meaning *findstandardmeaning(kind, name) +enum meaningkind kind; +char *name; +{ + Meaning *mp; + Symbol *sym; + + sym = findsymbol(fixpascalname(name)); + for (mp = sym->mbase; mp && mp->ctx != curctx; mp = mp->snext) ; + if (mp) { + if (mp->kind == kind) + mp->refcount = 1; + else + mp = NULL; + } + return mp; +} + + +Static Meaning *makestandardmeaning(kind, name) +enum meaningkind kind; +char *name; +{ + Meaning *mp; + Symbol *sym; + + sym = findsymbol(fixpascalname(name)); + for (mp = sym->mbase; mp && mp->ctx != curctx; mp = mp->snext) ; + if (!mp) { + mp = addmeaning(sym, kind); + strchange(&mp->name, name); + if (debug < 4) + mp->dumped = partialdump; /* prevent irrelevant dumping */ + } else { + mp->kind = kind; + } + mp->refcount = 1; + return mp; +} + + +Static Type *makestandardtype(kind, mp) +enum typekind kind; +Meaning *mp; +{ + Type *tp; + + tp = maketype(kind); + tp->meaning = mp; + if (mp) + mp->type = tp; + return tp; +} + + + + +Static Stmt *nullspecialproc(mp) +Meaning *mp; +{ + warning(format_s("Procedure %s not yet supported [118]", mp->name)); + if (curtok == TOK_LPAR) + skipparens(); + return NULL; +} + +Meaning *makespecialproc(name, handler) +char *name; +Stmt *(*handler)(); +{ + Meaning *mp; + + if (!handler) + handler = nullspecialproc; + mp = makestandardmeaning(MK_SPECIAL, name); + mp->handler = (Expr *(*)())handler; + return mp; +} + + + +Static Stmt *nullstandardproc(ex) +Expr *ex; +{ + warning(format_s("Procedure %s not yet supported [118]", ((Meaning *)ex->val.i)->name)); + return makestmt_call(ex); +} + +Meaning *makestandardproc(name, handler) +char *name; +Stmt *(*handler)(); +{ + Meaning *mp; + + if (!handler) + handler = nullstandardproc; + mp = findstandardmeaning(MK_FUNCTION, name); + if (mp) { + mp->handler = (Expr *(*)())handler; + if (mp->isfunction) { + warning(format_s("Procedure %s was declared as a function [119]", name)); + mp->isfunction = 0; + } + } else if (debug > 0) + warning(format_s("Procedure %s was never declared [120]", name)); + return mp; +} + + + +Static Expr *nullspecialfunc(mp) +Meaning *mp; +{ + warning(format_s("Function %s not yet supported [121]", mp->name)); + if (curtok == TOK_LPAR) + skipparens(); + return makeexpr_long(0); +} + +Meaning *makespecialfunc(name, handler) +char *name; +Expr *(*handler)(); +{ + Meaning *mp; + + if (!handler) + handler = nullspecialfunc; + mp = makestandardmeaning(MK_SPECIAL, name); + mp->isfunction = 1; + mp->handler = handler; + return mp; +} + + + +Static Expr *nullstandardfunc(ex) +Expr *ex; +{ + warning(format_s("Function %s not yet supported [121]", ((Meaning *)ex->val.i)->name)); + return ex; +} + +Meaning *makestandardfunc(name, handler) +char *name; +Expr *(*handler)(); +{ + Meaning *mp; + + if (!handler) + handler = nullstandardfunc; + mp = findstandardmeaning(MK_FUNCTION, name); + if (mp) { + mp->handler = handler; + if (!mp->isfunction) { + warning(format_s("Function %s was declared as a procedure [122]", name)); + mp->isfunction = 1; + } + } else if (debug > 0) + warning(format_s("Function %s was never declared [123]", name)); + return mp; +} + + + + +Static Expr *nullspecialvar(mp) +Meaning *mp; +{ + warning(format_s("Variable %s not yet supported [124]", mp->name)); + if (curtok == TOK_LPAR || curtok == TOK_LBR) + skipparens(); + return makeexpr_var(mp); +} + +Meaning *makespecialvar(name, handler) +char *name; +Expr *(*handler)(); +{ + Meaning *mp; + + if (!handler) + handler = nullspecialvar; + mp = makestandardmeaning(MK_SPVAR, name); + mp->handler = handler; + return mp; +} + + + + + +void setup_decl() +{ + Meaning *mp, *mp2, *mp_turbo_shortint; + Symbol *sym; + Type *tp; + int i; + + numimports = 0; + firstimport = 0; + permimports = NULL; + stringceiling = stringceiling | 1; /* round up to odd */ + stringtypecachesize = (stringceiling + 1) >> 1; + stringtypecache = ALLOC(stringtypecachesize, Type *, misc); + curctxlast = NULL; + curctx = NULL; /* the meta-ctx has no parent ctx */ + curctx = nullctx = makestandardmeaning(MK_MODULE, "SYSTEM"); + strlist_add(&permimports, "SYSTEM")->value = (long)nullctx; + ptrbase = NULL; + tempvars = NULL; + stmttempvars = NULL; + tempvarcount = 0; + deferallptrs = 0; + silentalreadydef = 0; + varstructdecllist = NULL; + nonloclabelcount = -1; + for (i = 0; i < stringtypecachesize; i++) + stringtypecache[i] = NULL; + + tp_integer = makestandardtype(TK_INTEGER, makestandardmeaning(MK_TYPE, + (integer16) ? "LONGINT" : "INTEGER")); + tp_integer->smin = makeexpr_long(MININT); /* "long" */ + tp_integer->smax = makeexpr_long(MAXINT); + + if (sizeof_int >= 32) { + tp_int = tp_integer; /* "int" */ + } else { + tp_int = makestandardtype(TK_INTEGER, + (integer16 > 1) ? makestandardmeaning(MK_TYPE, "INTEGER") + : NULL); + tp_int->smin = makeexpr_long(min_sshort); + tp_int->smax = makeexpr_long(max_sshort); + } + mp = makestandardmeaning(MK_TYPE, "C_INT"); + mp->type = tp_int; + if (!tp_int->meaning) + tp_int->meaning = mp; + + mp_unsigned = makestandardmeaning(MK_TYPE, "UNSIGNED"); + tp_unsigned = makestandardtype(TK_INTEGER, mp_unsigned); + tp_unsigned->smin = makeexpr_long(0); /* "unsigned long" */ + tp_unsigned->smax = makeexpr_long(MAXINT); + + if (sizeof_int >= 32) { + tp_uint = tp_unsigned; /* "unsigned int" */ + mp_uint = mp_unsigned; + } else { + mp_uint = makestandardmeaning(MK_TYPE, "C_UINT"); + tp_uint = makestandardtype(TK_INTEGER, mp_uint); + tp_uint->smin = makeexpr_long(0); + tp_uint->smax = makeexpr_long(MAXINT); + } + + tp_sint = makestandardtype(TK_INTEGER, NULL); + tp_sint->smin = copyexpr(tp_int->smin); /* "signed int" */ + tp_sint->smax = copyexpr(tp_int->smax); + + tp_char = makestandardtype(TK_CHAR, makestandardmeaning(MK_TYPE, "CHAR")); + if (unsignedchar == 0) { + tp_char->smin = makeexpr_long(-128); /* "char" */ + tp_char->smax = makeexpr_long(127); + } else { + tp_char->smin = makeexpr_long(0); + tp_char->smax = makeexpr_long(255); + } + + tp_charptr = makestandardtype(TK_POINTER, NULL); /* "unsigned char *" */ + tp_charptr->basetype = tp_char; + tp_char->pointertype = tp_charptr; + + mp_schar = makestandardmeaning(MK_TYPE, "SCHAR"); /* "signed char" */ + tp_schar = makestandardtype(TK_CHAR, mp_schar); + tp_schar->smin = makeexpr_long(-128); + tp_schar->smax = makeexpr_long(127); + + mp_uchar = makestandardmeaning(MK_TYPE, "UCHAR"); /* "unsigned char" */ + tp_uchar = makestandardtype(TK_CHAR, mp_uchar); + tp_uchar->smin = makeexpr_long(0); + tp_uchar->smax = makeexpr_long(255); + + tp_boolean = makestandardtype(TK_BOOLEAN, makestandardmeaning(MK_TYPE, "BOOLEAN")); + tp_boolean->smin = makeexpr_long(0); /* "boolean" */ + tp_boolean->smax = makeexpr_long(1); + + sym = findsymbol("Boolean"); + sym->flags |= SSYNONYM; + strlist_append(&sym->symbolnames, "===")->value = (long)tp_boolean->meaning->sym; + + tp_real = makestandardtype(TK_REAL, makestandardmeaning(MK_TYPE, "REAL")); + /* "float" or "double" */ + mp = makestandardmeaning(MK_TYPE, "LONGREAL"); + if (doublereals) + mp->type = tp_longreal = tp_real; + else + tp_longreal = makestandardtype(TK_REAL, mp); + + tp_void = makestandardtype(TK_VOID, NULL); /* "void" */ + + mp = makestandardmeaning(MK_TYPE, "SINGLE"); + if (doublereals) + makestandardtype(TK_REAL, mp); + else + mp->type = tp_real; + makestandardmeaning(MK_TYPE, "SHORTREAL")->type = mp->type; + mp = makestandardmeaning(MK_TYPE, "DOUBLE"); + mp->type = tp_longreal; + mp = makestandardmeaning(MK_TYPE, "EXTENDED"); + mp->type = tp_longreal; /* good enough */ + mp = makestandardmeaning(MK_TYPE, "QUADRUPLE"); + mp->type = tp_longreal; /* good enough */ + + tp_sshort = makestandardtype(TK_SUBR, makestandardmeaning(MK_TYPE, + (integer16 == 1) ? "INTEGER" : "SWORD")); + tp_sshort->basetype = tp_integer; /* "short" */ + tp_sshort->smin = makeexpr_long(min_sshort); + tp_sshort->smax = makeexpr_long(max_sshort); + + if (integer16) { + if (integer16 != 2) { + mp = makestandardmeaning(MK_TYPE, "SWORD"); + mp->type = tp_sshort; + } + } else { + mp = makestandardmeaning(MK_TYPE, "LONGINT"); + mp->type = tp_integer; + } + + tp_ushort = makestandardtype(TK_SUBR, makestandardmeaning(MK_TYPE, modula2 ? "UWORD" : "WORD")); + tp_ushort->basetype = tp_integer; /* "unsigned short" */ + tp_ushort->smin = makeexpr_long(0); + tp_ushort->smax = makeexpr_long(max_ushort); + + mp = makestandardmeaning(MK_TYPE, "CARDINAL"); + mp->type = (integer16) ? tp_ushort : tp_unsigned; + mp = makestandardmeaning(MK_TYPE, "LONGCARD"); + mp->type = tp_unsigned; + + if (modula2) { + mp = makestandardmeaning(MK_TYPE, "WORD"); + mp->type = tp_integer; + } else { + makestandardmeaning(MK_TYPE, "UWORD")->type = tp_ushort; + } + + tp_sbyte = makestandardtype(TK_SUBR, NULL); /* "signed char" */ + tp_sbyte->basetype = tp_integer; + tp_sbyte->smin = makeexpr_long(min_schar); + tp_sbyte->smax = makeexpr_long(max_schar); + + mp_turbo_shortint = (which_lang == LANG_TURBO) ? makestandardmeaning(MK_TYPE, "SHORTINT") : NULL; + mp = makestandardmeaning(MK_TYPE, "SBYTE"); + if (needsignedbyte || signedchars == 1 || hassignedchar) { + mp->type = tp_sbyte; + if (mp_turbo_shortint) + mp_turbo_shortint->type = tp_sbyte; + tp_sbyte->meaning = mp_turbo_shortint ? mp_turbo_shortint : mp; + } else { + mp->type = tp_sshort; + if (mp_turbo_shortint) + mp_turbo_shortint->type = tp_sshort; + } + + tp_ubyte = makestandardtype(TK_SUBR, makestandardmeaning(MK_TYPE, "BYTE")); + tp_ubyte->basetype = tp_integer; /* "unsigned char" */ + tp_ubyte->smin = makeexpr_long(0); + tp_ubyte->smax = makeexpr_long(max_uchar); + + if (signedchars == 1) + tp_abyte = tp_sbyte; /* "char" */ + else if (signedchars == 0) + tp_abyte = tp_ubyte; + else { + tp_abyte = makestandardtype(TK_SUBR, NULL); + tp_abyte->basetype = tp_integer; + tp_abyte->smin = makeexpr_long(0); + tp_abyte->smax = makeexpr_long(max_schar); + } + + mp = makestandardmeaning(MK_TYPE, "POINTER"); + mp2 = makestandardmeaning(MK_TYPE, "ANYPTR"); + tp_anyptr = makestandardtype(TK_POINTER, (which_lang == LANG_HP) ? mp2 : mp); + ((which_lang == LANG_HP) ? mp : mp2)->type = tp_anyptr; + tp_anyptr->basetype = tp_void; /* "void *" */ + tp_void->pointertype = tp_anyptr; + + if (useAnyptrMacros == 1) { + tp_special_anyptr = makestandardtype(TK_SUBR, NULL); + tp_special_anyptr->basetype = tp_integer; + tp_special_anyptr->smin = makeexpr_long(0); + tp_special_anyptr->smax = makeexpr_long(max_schar); + } else + tp_special_anyptr = NULL; + + tp_proc = maketype(TK_PROCPTR); + tp_proc->basetype = maketype(TK_FUNCTION); + tp_proc->basetype->basetype = tp_void; + tp_proc->escale = 1; /* saved "hasstaticlinks" */ + + tp_str255 = makestandardtype(TK_STRING, NULL); /* "Char []" */ + tp_str255->basetype = tp_char; + tp_str255->indextype = makestandardtype(TK_SUBR, NULL); + tp_str255->indextype->basetype = tp_integer; + tp_str255->indextype->smin = makeexpr_long(0); + tp_str255->indextype->smax = makeexpr_long(stringceiling); + + tp_strptr = makestandardtype(TK_POINTER, NULL); /* "Char *" */ + tp_str255->pointertype = tp_strptr; + tp_strptr->basetype = tp_str255; + + mp_string = makestandardmeaning(MK_TYPE, "STRING"); + tp = makestandardtype(TK_STRING, mp_string); + tp->basetype = tp_char; + tp->indextype = tp_str255->indextype; + + tp_smallset = maketype(TK_SMALLSET); + tp_smallset->basetype = tp_integer; + tp_smallset->indextype = tp_boolean; + + tp_text = makestandardtype(TK_POINTER, makestandardmeaning(MK_TYPE, "TEXT")); + tp_text->basetype = makestandardtype(TK_FILE, NULL); /* "FILE *" */ + tp_text->basetype->basetype = tp_char; + tp_text->basetype->pointertype = tp_text; + + tp_bigtext = makestandardtype(TK_BIGFILE, makestandardmeaning(MK_TYPE, "BIGTEXT")); + tp_bigtext->basetype = tp_char; + tp_bigtext->meaning->name = stralloc("_TEXT"); + tp_bigtext->meaning->wasdeclared = 1; + + tp_jmp_buf = makestandardtype(TK_SPECIAL, NULL); + + mp = makestandardmeaning(MK_TYPE, "INTERACTIVE"); + mp->type = tp_text; + + mp = makestandardmeaning(MK_TYPE, "BITSET"); + mp->type = makesettype(makesubrangetype(tp_integer, makeexpr_long(0), + makeexpr_long(setbits-1))); + mp->type->meaning = mp; + + mp = makestandardmeaning(MK_TYPE, "INTSET"); + mp->type = makesettype(makesubrangetype(tp_integer, makeexpr_long(0), + makeexpr_long(defaultsetsize-1))); + mp->type->meaning = mp; + + mp_input = makestandardmeaning(MK_VAR, "INPUT"); + mp_input->type = tp_text; + mp_input->name = stralloc("stdin"); + ex_input = makeexpr_var(mp_input); + + mp_output = makestandardmeaning(MK_VAR, "OUTPUT"); + mp_output->type = tp_text; + mp_output->name = stralloc("stdout"); + ex_output = makeexpr_var(mp_output); + + mp_stderr = makestandardmeaning(MK_VAR, "STDERR"); + mp_stderr->type = tp_text; + mp_stderr->name = stralloc("stderr"); + + mp_escapecode = makestandardmeaning(MK_VAR, "ESCAPECODE"); + mp_escapecode->type = tp_sshort; + mp_escapecode->name = stralloc(name_ESCAPECODE); + + mp_ioresult = makestandardmeaning(MK_VAR, "IORESULT"); + mp_ioresult->type = tp_integer; + mp_ioresult->name = stralloc(name_IORESULT); + + mp_false = makestandardmeaning(MK_CONST, "FALSE"); + mp_false->type = mp_false->val.type = tp_boolean; + mp_false->val.i = 0; + + mp_true = makestandardmeaning(MK_CONST, "TRUE"); + mp_true->type = mp_true->val.type = tp_boolean; + mp_true->val.i = 1; + + mp_maxint = makestandardmeaning(MK_CONST, "MAXINT"); + mp_maxint->type = mp_maxint->val.type = tp_integer; + mp_maxint->val.i = MAXINT; + mp_maxint->name = stralloc((integer16) ? "SHORT_MAX" : + (sizeof_int >= 32) ? "INT_MAX" : "LONG_MAX"); + + mp = makestandardmeaning(MK_CONST, "MAXLONGINT"); + mp->type = mp->val.type = tp_integer; + mp->val.i = MAXINT; + mp->name = stralloc("LONG_MAX"); + + mp_minint = makestandardmeaning(MK_CONST, "MININT"); + mp_minint->type = mp_minint->val.type = tp_integer; + mp_minint->val.i = MININT; + mp_minint->name = stralloc((integer16) ? "SHORT_MIN" : + (sizeof_int >= 32) ? "INT_MIN" : "LONG_MIN"); + + mp = makestandardmeaning(MK_CONST, "MAXCHAR"); + mp->type = mp->val.type = tp_char; + mp->val.i = 127; + mp->name = stralloc("CHAR_MAX"); + + mp = makestandardmeaning(MK_CONST, "MINCHAR"); + mp->type = mp->val.type = tp_char; + mp->val.i = 0; + mp->anyvarflag = 1; + + mp = makestandardmeaning(MK_CONST, "BELL"); + mp->type = mp->val.type = tp_char; + mp->val.i = 7; + mp->anyvarflag = 1; + + mp = makestandardmeaning(MK_CONST, "TAB"); + mp->type = mp->val.type = tp_char; + mp->val.i = 9; + mp->anyvarflag = 1; + + mp_str_hp = mp_str_turbo = NULL; + mp_val_modula = mp_val_turbo = NULL; + mp_blockread_ucsd = mp_blockread_turbo = NULL; + mp_blockwrite_ucsd = mp_blockwrite_turbo = NULL; + mp_dec_dec = mp_dec_turbo = NULL; +} + + + +/* This makes sure that if A imports B and then C, C's interface is not + parsed in the environment of B */ +int push_imports() +{ + int mark = firstimport; + Meaning *mp; + + while (firstimport < numimports) { + if (!strlist_cifind(permimports, importlist[firstimport]->sym->name)) { + for (mp = importlist[firstimport]->cbase; mp; mp = mp->cnext) + mp->isactive = 0; + } + firstimport++; + } + return mark; +} + + + +void pop_imports(mark) +int mark; +{ + Meaning *mp; + + while (firstimport > mark) { + firstimport--; + for (mp = importlist[firstimport]->cbase; mp; mp = mp->cnext) + mp->isactive = 1; + } +} + + + +void import_ctx(ctx) +Meaning *ctx; +{ + Meaning *mp; + int i; + + for (i = firstimport; i < numimports && importlist[i] != ctx; i++) ; + if (i >= numimports) { + if (numimports == MAXIMPORTS) + error(format_d("Maximum of %d simultaneous imports exceeded", MAXIMPORTS)); + importlist[numimports++] = ctx; + } + for (mp = ctx->cbase; mp; mp = mp->cnext) { + if (mp->exported) + mp->isactive = 1; + } +} + + + +void perm_import(ctx) +Meaning *ctx; +{ + Meaning *mp; + + /* Import permanently, as in Turbo's "system" unit */ + for (mp = ctx->cbase; mp; mp = mp->cnext) { + if (mp->exported) + mp->isactive = 1; + } +} + + + +void unimport(mark) +int mark; +{ + Meaning *mp; + + while (numimports > mark) { + numimports--; + if (!strlist_cifind(permimports, importlist[numimports]->sym->name)) { + for (mp = importlist[numimports]->cbase; mp; mp = mp->cnext) + mp->isactive = 0; + } + } +} + + + + +void activatemeaning(mp) +Meaning *mp; +{ + Meaning *mp2; + + if (debug>1) fprintf(outf, "Reviving %s\n", curctxlast->name); + mp->isactive = 1; + if (mp->sym->mbase != mp) { /* move to front of symbol list */ + mp2 = mp->sym->mbase; + for (;;) { + if (!mp2) { + /* Not on symbol list: must be a special kludge meaning */ + return; + } + if (mp2->snext == mp) + break; + mp2 = mp2->snext; + } + mp2->snext = mp->snext; + mp->snext = mp->sym->mbase; + mp->sym->mbase = mp; + } +} + + + +void pushctx(ctx) +Meaning *ctx; +{ + struct ctxstack *top; + + top = ALLOC(1, struct ctxstack, ctxstacks); + top->ctx = curctx; + top->ctxlast = curctxlast; + top->tempvars = tempvars; + top->tempvarcount = tempvarcount; + top->importmark = numimports; + top->next = ctxtop; + ctxtop = top; + curctx = ctx; + curctxlast = ctx->cbase; + if (curctxlast) { + activatemeaning(curctxlast); + while (curctxlast->cnext) { + curctxlast = curctxlast->cnext; + activatemeaning(curctxlast); + } + } + tempvars = NULL; + tempvarcount = 0; + if (blockkind != TOK_IMPORT && blockkind != TOK_EXPORT) + progress(); +} + + + +void popctx() +{ + struct ctxstack *top; + struct tempvarlist *tv; + Meaning *mp; + + if (!strlist_cifind(permimports, curctx->sym->name)) { + for (mp = curctx->cbase; mp; mp = mp->cnext) { + if (debug>1) fprintf(outf, "Hiding %s\n", mp->name); + mp->isactive = 0; + } + } + top = ctxtop; + ctxtop = top->next; + curctx = top->ctx; + curctxlast = top->ctxlast; + while (tempvars) { + tv = tempvars->next; + FREE(tempvars); + tempvars = tv; + } + tempvars = top->tempvars; + tempvarcount = top->tempvarcount; + unimport(top->importmark); + FREE(top); + if (blockkind != TOK_IMPORT && blockkind != TOK_EXPORT) + progress(); +} + + + +void forget_ctx(ctx, all) +Meaning *ctx; +int all; +{ + register Meaning *mp, **mpprev, *mp2, **mpp2; + + if (ctx->kind == MK_FUNCTION && ctx->isfunction && ctx->cbase) + mpprev = &ctx->cbase->cnext; /* Skip return-value variable */ + else + mpprev = &ctx->cbase; + while ((mp = *mpprev) != NULL) { + if (all || + (mp->kind != MK_PARAM && + mp->kind != MK_VARPARAM)) { + *mpprev = mp->cnext; + mpp2 = &mp->sym->mbase; + while ((mp2 = *mpp2) != NULL && mp2 != mp) + mpp2 = &mp2->snext; + if (mp2) + *mpp2 = mp2->snext; + if (mp->kind == MK_CONST) + free_value(&mp->val); + freeexpr(mp->constdefn); + if (mp->cbase) + forget_ctx(mp, 1); + if (mp->kind == MK_FUNCTION && mp->val.i) + free_stmt((Stmt *)mp->val.i); + strlist_empty(&mp->comments); + if (mp->name) + FREE(mp->name); + if (mp->othername) + FREE(mp->othername); + FREE(mp); + } else + mpprev = &mp->cnext; + } +} + + + + +void handle_nameof() +{ + Strlist *sl, *sl2; + Symbol *sp; + char *cp; + + for (sl = nameoflist; sl; sl = sl->next) { + cp = my_strchr(sl->s, '.'); + if (cp) { + sp = findsymbol(fixpascalname(cp + 1)); + sl2 = strlist_add(&sp->symbolnames, + format_ds("%.*s", (int)(cp - sl->s), sl->s)); + } else { + sp = findsymbol(fixpascalname(sl->s)); + sl2 = strlist_add(&sp->symbolnames, ""); + } + sl2->value = sl->value; + if (debug > 0) + fprintf(outf, "symbol %s gets \"%s\" -> \"%s\"\n", + sp->name, sl2->s, sl2->value); + } + strlist_empty(&nameoflist); +} + + + +Static void initmeaning(mp) +Meaning *mp; +{ +/* mp->serial = curserial = ++serialcount; */ + mp->cbase = NULL; + mp->xnext = NULL; + mp->othername = NULL; + mp->type = NULL; + mp->dtype = NULL; + mp->needvarstruct = 0; + mp->varstructflag = 0; + mp->wasdeclared = 0; + mp->isforward = 0; + mp->isfunction = 0; + mp->istemporary = 0; + mp->volatilequal = 0; + mp->constqual = 0; + mp->warnifused = (warnnames > 0); + mp->constdefn = NULL; + mp->val.i = 0; + mp->val.s = NULL; + mp->val.type = NULL; + mp->refcount = 1; + mp->anyvarflag = 0; + mp->isactive = 1; + mp->exported = 0; + mp->handler = NULL; + mp->dumped = 0; + mp->isreturn = 0; + mp->fakeparam = 0; + mp->namedfile = 0; + mp->bufferedfile = 0; + mp->comments = NULL; +} + + + +int issafename(sp, isglobal, isdefine) +Symbol *sp; +int isglobal, isdefine; +{ + if (isdefine && curctx->kind != MK_FUNCTION) { + if (sp->flags & FWDPARAM) + return 0; + } + if ((sp->flags & AVOIDNAME) || + (isdefine && (sp->flags & AVOIDFIELD)) || + (isglobal && (sp->flags & AVOIDGLOB))) + return 0; + else + return 1; +} + + + +static Meaning *enum_tname; + +void setupmeaning(mp, sym, kind, namekind) +Meaning *mp; +Symbol *sym; +enum meaningkind kind, namekind; +{ + char *name, *symfmt, *editfmt, *cp, *cp2; + int altnum, isglobal, isdefine; + Symbol *sym2; + Strlist *sl; + + if (!sym) + sym = findsymbol("Spam"); /* reduce crashes due to internal errors */ + if (sym->mbase && sym->mbase->ctx == curctx && + curctx != NULL && !silentalreadydef) + alreadydef(sym); + mp->sym = sym; + mp->snext = sym->mbase; + sym->mbase = mp; + if (sym == curtoksym) { + sym->kwtok = TOK_NONE; + sym->flags &= ~KWPOSS; + } + mp->ctx = curctx; + mp->kind = kind; + if (pascalcasesens && curctx && curctx->sym && kind != MK_SYNONYM && + strlist_cifind(permimports, curctx->sym->name)) { /* a built-in name */ + Meaning *mp2; + if (islower(sym->name[0])) + sym2 = findsymbol(strupper(sym->name)); + else + sym2 = findsymbol(strlower(sym->name)); + mp2 = addmeaning(sym2, MK_SYNONYM); + mp2->xnext = mp; + } + if (kind == MK_VAR) { + sl = strlist_find(varmacros, sym->name); + if (sl) { + kind = namekind = MK_VARMAC; + mp->constdefn = (Expr *)sl->value; + strlist_delete(&varmacros, sl); + } + } + if (kind == MK_FUNCTION || kind == MK_SPECIAL) { + sl = strlist_find(funcmacros, sym->name); + if (sl) { + mp->constdefn = (Expr *)sl->value; + strlist_delete(&funcmacros, sl); + } + } + if (kind == MK_VAR || kind == MK_VARREF || kind == MK_VARMAC || + kind == MK_TYPE || kind == MK_CONST || kind == MK_FUNCTION) { + mp->exported = (blockkind == TOK_IMPORT || blockkind == TOK_EXPORT); + if (blockkind == TOK_IMPORT) + mp->wasdeclared = 1; /* suppress future declaration */ + } else + mp->exported = 0; + if (sym == curtoksym) + name = curtokcase; + else + name = sym->name; + isdefine = (namekind == MK_CONST || (namekind == MK_VARIANT && !useenum)); + isglobal = (!curctx || + curctx->kind != MK_FUNCTION || + namekind == MK_FUNCTION || + namekind == MK_TYPE || + namekind == MK_VARIANT || + isdefine) && + (curctx != nullctx); + mp->refcount = isglobal ? 1 : 0; /* make sure globals don't disappear */ + if (namekind == MK_SYNONYM) + return; + if (!mp->exported || !*exportsymbol) + symfmt = ""; + else if (*export_symbol && my_strchr(name, '_')) + symfmt = export_symbol; + else + symfmt = exportsymbol; + wasaliased = 0; + if (*externalias && !my_strchr(externalias, '%')) { + register int i; + name = format_s("%s", externalias); + i = numparams; + while (--i >= 0 && strcmp(rctable[i].name, "ALIAS")) ; + if (i < 0 || !undooption(i, "")) + *externalias = 0; + wasaliased = 1; + } else if (sym->symbolnames) { + if (curctx) { + if (debug > 2) + fprintf(outf, "checking for \"%s\" of %s\n", curctx->name, sym->name); + sl = strlist_cifind(sym->symbolnames, curctx->sym->name); + if (sl) { + if (debug > 2) + fprintf(outf, "found \"%s\"\n", sl->value); + name = (char *)sl->value; + wasaliased = 1; + } + } + if (!wasaliased) { + if (debug > 2) + fprintf(outf, "checking for \"\" of %s\n", sym->name); + sl = strlist_find(sym->symbolnames, ""); + if (sl) { + if (debug > 2) + fprintf(outf, "found \"%s\"\n", sl->value); + name = (char *)sl->value; + wasaliased = 1; + } + } + } + if (!*symfmt || wasaliased) + symfmt = "%s"; + altnum = -1; + do { + altnum++; + cp = format_ss(symfmt, name, curctx ? curctx->name : ""); + switch (namekind) { + + case MK_CONST: + editfmt = constformat; + break; + + case MK_MODULE: + editfmt = moduleformat; + break; + + case MK_FUNCTION: + editfmt = functionformat; + break; + + case MK_VAR: + case MK_VARPARAM: + case MK_VARREF: + case MK_VARMAC: + case MK_SPVAR: + editfmt = varformat; + break; + + case MK_TYPE: + editfmt = typeformat; + break; + + case MK_VARIANT: /* A true kludge! */ + editfmt = enumformat; + if (!*editfmt) + editfmt = useenum ? varformat : constformat; + break; + + default: + editfmt = ""; + } + if (!*editfmt) + editfmt = symbolformat; + if (*editfmt) + if (editfmt == enumformat) + cp = format_ss(editfmt, cp, + enum_tname ? enum_tname->name : "ENUM"); + else + cp = format_ss(editfmt, cp, + curctx ? curctx->name : ""); + if (dollar_idents == 2) { + for (cp2 = cp; *cp2; cp2++) + if (*cp2 == '$' || *cp2 == '%') + *cp2 = '_'; + } + sym2 = findsymbol(findaltname(cp, altnum)); + } while (!issafename(sym2, isglobal, isdefine) && + namekind != MK_MODULE && !wasaliased); + mp->name = stralloc(sym2->name); + if (sym2->flags & WARNNAME) + note(format_s("A symbol named %s was defined [100]", mp->name)); + if (isglobal) { + switch (namekind) { /* prevent further name conflicts */ + + case MK_CONST: + case MK_VARIANT: + case MK_TYPE: + sym2->flags |= AVOIDNAME; + break; + + case MK_VAR: + case MK_VARREF: + case MK_FUNCTION: + sym2->flags |= AVOIDGLOB; + break; + + default: + /* name is completely local */ + break; + } + } + if (debug > 4) + fprintf(outf, "Created meaning %s\n", mp->name); +} + + + +Meaning *addmeaningas(sym, kind, namekind) +Symbol *sym; +enum meaningkind kind, namekind; +{ + Meaning *mp; + + mp = ALLOC(1, Meaning, meanings); + initmeaning(mp); + setupmeaning(mp, sym, kind, namekind); + mp->cnext = NULL; + if (curctx) { + if (curctxlast) + curctxlast->cnext = mp; + else + curctx->cbase = mp; + curctxlast = mp; + } + return mp; +} + + + +Meaning *addmeaning(sym, kind) +Symbol *sym; +enum meaningkind kind; +{ + return addmeaningas(sym, kind, kind); +} + + + +Meaning *addmeaningafter(mpprev, sym, kind) +Meaning *mpprev; +Symbol *sym; +enum meaningkind kind; +{ + Meaning *mp; + + if (!mpprev->cnext && mpprev->ctx == curctx) + return addmeaning(sym, kind); + mp = ALLOC(1, Meaning, meanings); + initmeaning(mp); + setupmeaning(mp, sym, kind, kind); + mp->ctx = mpprev->ctx; + mp->cnext = mpprev->cnext; + mpprev->cnext = mp; + return mp; +} + + +void unaddmeaning(mp) +Meaning *mp; +{ + Meaning *prev; + + prev = mp->ctx; + while (prev && prev != mp) + prev = prev->cnext; + if (prev) + prev->cnext = mp->cnext; + else + mp->ctx = mp->cnext; + if (!mp->cnext && mp->ctx == curctx) + curctxlast = prev; +} + + +void readdmeaning(mp) +Meaning *mp; +{ + mp->cnext = NULL; + if (curctx) { + if (curctxlast) + curctxlast->cnext = mp; + else + curctx->cbase = mp; + curctxlast = mp; + } +} + + +Meaning *addfield(sym, flast, rectype, tname) +Symbol *sym; +Meaning ***flast; +Type *rectype; +Meaning *tname; +{ + Meaning *mp; + int altnum; + Symbol *sym2; + Strlist *sl; + char *name, *name2; + + mp = ALLOC(1, Meaning, meanings); + initmeaning(mp); + mp->sym = sym; + if (sym) { + mp->snext = sym->fbase; + sym->fbase = mp; + if (sym == curtoksym) + name2 = curtokcase; + else + name2 = sym->name; + name = name2; + if (tname) + sl = strlist_find(fieldmacros, + format_ss("%s.%s", tname->sym->name, sym->name)); + else + sl = NULL; + if (sl) { + mp->constdefn = (Expr *)sl->value; + strlist_delete(&fieldmacros, sl); + altnum = 0; + } else { + altnum = -1; + do { + altnum++; + if (*fieldformat) + name = format_ss(fieldformat, name2, + tname && tname->name ? tname->name + : "FIELD"); + sym2 = findsymbol(findaltname(name, altnum)); + } while (!issafename(sym2, 0, 0) || + ((sym2->flags & AVOIDFIELD) && !reusefieldnames)); + sym2->flags |= AVOIDFIELD; + } + mp->kind = MK_FIELD; + mp->name = stralloc(findaltname(name, altnum)); + } else { + mp->name = stralloc("(variant)"); + mp->kind = MK_VARIANT; + } + mp->cnext = NULL; + **flast = mp; + *flast = &(mp->cnext); + mp->ctx = NULL; + mp->rectype = rectype; + mp->val.i = 0; + return mp; +} + + + + + +int isfiletype(type, big) +Type *type; +int big; /* 0=TK_FILE, 1=TK_BIGFILE, -1=either */ +{ + return ((type->kind == TK_POINTER && + type->basetype->kind == TK_FILE && big != 1) || + (type->kind == TK_BIGFILE && big != 0)); +} + + +Meaning *isfilevar(ex) +Expr *ex; +{ + Meaning *mp; + + if (ex->kind == EK_VAR) { + mp = (Meaning *)ex->val.i; + if (mp->kind == MK_VAR) + return mp; + } else if (ex->kind == EK_DOT) { + mp = (Meaning *)ex->val.i; + if (mp && mp->kind == MK_FIELD) + return mp; + } + return NULL; +} + + +Type *filebasetype(type) +Type *type; +{ + if (type->kind == TK_BIGFILE) + return type->basetype; + else + return type->basetype->basetype; +} + + +Expr *filebasename(ex) +Expr *ex; +{ + if (ex->val.type->kind == TK_BIGFILE) + return makeexpr_dotq(ex, "f", ex->val.type); + else + return ex; +} + + +Expr *filenamepart(ex) +Expr *ex; +{ + Meaning *mp; + + if (ex->val.type->kind == TK_BIGFILE) + return makeexpr_dotq(copyexpr(ex), "name", tp_str255); + else if ((mp = isfilevar(ex)) && mp->namedfile) + return makeexpr_name(format_s(name_FNVAR, mp->name), tp_str255); + else + return NULL; +} + + +int fileisbuffered(ex, maybe) +Expr *ex; +int maybe; +{ + Meaning *mp; + + return (ex->val.type->kind == TK_BIGFILE || + ((mp = isfilevar(ex)) && (maybe || mp->bufferedfile))); +} + + + +Type *findbasetype_(type, flags) +Type *type; +int flags; +{ + long smin, smax; + static Type typename; + + for (;;) { + if (type->preserved && (type->kind != TK_POINTER) && + !(flags & ODECL_NOPRES)) + return type; + switch (type->kind) { + + case TK_POINTER: + if (type->smin) /* unresolved forward */ + return type; + if (type->basetype == tp_void) { /* ANYPTR */ + if (tp_special_anyptr) + return tp_special_anyptr; /* write "Anyptr" */ + if (!voidstar) + return tp_abyte; /* write "char *", not "void *" */ + } + switch (type->basetype->kind) { + + case TK_ARRAY: /* use basetype's basetype: */ + case TK_STRING: /* ^array[5] of array[3] of integer */ + case TK_SET: /* => int (*a)[3]; */ + if (stararrays == 1 || + !(flags & ODECL_FREEARRAY) || + type->basetype->structdefd) { + type = type->basetype->basetype; + flags &= ~ODECL_CHARSTAR; + continue; + } + break; + + default: + break; + } + if (type->preserved && !(flags & ODECL_NOPRES)) + return type; + if (type->fbase && type->fbase->wasdeclared && + (flags & ODECL_DECL)) { + typename.meaning = type->fbase; + typename.preserved = 1; + return &typename; + } + break; + + case TK_FUNCTION: + case TK_STRING: + case TK_SET: + case TK_SMALLSET: + case TK_SMALLARRAY: + if (!type->basetype) + return type; + break; + + case TK_ARRAY: + if (type->meaning && type->meaning->kind == MK_TYPE && + type->meaning->wasdeclared) + return type; + if (type->fbase && type->fbase->wasdeclared && + (flags & ODECL_DECL)) { + typename.meaning = type->fbase; + typename.preserved = 1; + return &typename; + } + break; + + case TK_FILE: + return tp_text->basetype; + + case TK_PROCPTR: + return tp_proc; + + case TK_CPROCPTR: + type = type->basetype->basetype; + continue; + + case TK_ENUM: + if (useenum) + return type; + else if (!enumbyte || + type->smax->kind != EK_CONST || + type->smax->val.i > 255) + return tp_sshort; + else if (type->smax->val.i > 127) + return tp_ubyte; + else + return tp_abyte; + + case TK_BOOLEAN: + if (*name_BOOLEAN) + return type; + else + return tp_ubyte; + + case TK_SUBR: + if (type == tp_abyte || type == tp_ubyte || type == tp_sbyte || + type == tp_ushort || type == tp_sshort) { + return type; + } else if ((type->basetype->kind == TK_ENUM && useenum) || + type->basetype->kind == TK_BOOLEAN && *name_BOOLEAN) { + return type->basetype; + } else { + if (ord_range(type, &smin, &smax)) { + if (squeezesubr != 0) { + if (smin >= 0 && smax <= max_schar) + return tp_abyte; + else if (smin >= 0 && smax <= max_uchar) + return tp_ubyte; + else if (smin >= min_schar && smax <= max_schar && + (signedchars == 1 || hassignedchar)) + return tp_sbyte; + else if (smin >= min_sshort && smax <= max_sshort) + return tp_sshort; + else if (smin >= 0 && smax <= max_ushort) + return tp_ushort; + else + return tp_integer; + } else { + if (smin >= min_sshort && smax <= max_sshort) + return tp_sshort; + else + return tp_integer; + } + } else + return tp_integer; + } + + case TK_CHAR: + if (type == tp_schar && + (signedchars != 1 && !hassignedchar)) { + return tp_sshort; + } + return type; + + default: + return type; + } + type = type->basetype; + } +} + + +Type *findbasetype(type, flags) +Type *type; +int flags; +{ + if (debug>1) { + fprintf(outf, "findbasetype("); + dumptypename(type, 1); + fprintf(outf, ",%d) = ", flags); + type = findbasetype_(type, flags); + dumptypename(type, 1); + fprintf(outf, "\n"); + return type; + } + return findbasetype_(type, flags); +} + + + +Expr *arraysize(tp, incskipped) +Type *tp; +int incskipped; +{ + Expr *ex, *minv, *maxv; + int denom; + + ord_range_expr(tp->indextype, &minv, &maxv); + if (maxv->kind == EK_VAR && maxv->val.i == (long)mp_maxint && + !exprdependsvar(minv, mp_maxint)) { + return NULL; + } else { + ex = makeexpr_plus(makeexpr_minus(copyexpr(maxv), + copyexpr(minv)), + makeexpr_long(1)); + if (tp->smin && !incskipped) { + ex = makeexpr_minus(ex, copyexpr(tp->smin)); + } + if (tp->smax) { + denom = (tp->basetype == tp_sshort) ? 16 : 8; + denom >>= tp->escale; + ex = makeexpr_div(makeexpr_plus(ex, makeexpr_long(denom-1)), + makeexpr_long(denom)); + } + return ex; + } +} + + + +Type *promote_type(tp) +Type *tp; +{ + Type *tp2; + + if (tp->kind == TK_ENUM) { + if (promote_enums == 0 || + (promote_enums < 0 && + (useenum))) + return tp; + } + if (tp->kind == TK_ENUM || + tp->kind == TK_SUBR || + tp->kind == TK_INTEGER || + tp->kind == TK_CHAR || + tp->kind == TK_BOOLEAN) { + tp2 = findbasetype(tp, ODECL_NOPRES); + if (tp2 == tp_ushort && sizeof_int == 16) + return tp_uint; + else if (tp2 == tp_sbyte || tp2 == tp_ubyte || + tp2 == tp_abyte || tp2 == tp_char || + tp2 == tp_sshort || tp2 == tp_ushort || + tp2 == tp_boolean || tp2->kind == TK_ENUM) { + return tp_int; + } + } + if (tp == tp_real) + return tp_longreal; + return tp; +} + + +Type *promote_type_bin(t1, t2) +Type *t1, *t2; +{ + t1 = promote_type(t1); + t2 = promote_type(t2); + if (t1 == tp_longreal || t2 == tp_longreal) + return tp_longreal; + if (t1 == tp_unsigned || t2 == tp_unsigned) + return tp_unsigned; + if (t1 == tp_integer || t2 == tp_integer) { + if ((t1 == tp_uint || t2 == tp_uint) && + sizeof_int > 0 && + sizeof_int < (sizeof_long > 0 ? sizeof_long : 32)) + return tp_uint; + return tp_integer; + } + if (t1 == tp_uint || t2 == tp_uint) + return tp_uint; + return t1; +} + + + +#if 0 +void predeclare_varstruct(mp) +Meaning *mp; +{ + if (mp->ctx && + mp->ctx->kind == MK_FUNCTION && + mp->ctx->varstructflag && + (usePPMacros != 0 || prototypes != 0) && + !strlist_find(varstructdecllist, mp->ctx->name)) { + output("struct "); + output(format_s(name_LOC, mp->ctx->name)); + output(" ;\n"); + strlist_insert(&varstructdecllist, mp->ctx->name); + } +} +#endif + + +Static void declare_args(type, isheader, isforward) +Type *type; +int isheader, isforward; +{ + Meaning *mp = type->fbase; + Type *tp; + int firstflag = 0; + int usePP, dopromote, proto, showtypes, shownames; + int staticlink; + char *name; + +#if 1 /* This seems to work better! */ + isforward = !isheader; +#endif + usePP = (isforward && usePPMacros != 0); + dopromote = (promoteargs == 1 || + (promoteargs < 0 && (usePP || !fullprototyping))); + if (ansiC == 1 && blockkind != TOK_EXPORT) + usePP = 0; + if (usePP) + proto = (prototypes) ? prototypes : 1; + else + proto = (isforward || fullprototyping) ? prototypes : 0; + showtypes = (proto > 0); + shownames = (proto == 1 || isheader); + staticlink = (type->issigned || + (type->meaning && + type->meaning->ctx->kind == MK_FUNCTION && + type->meaning->ctx->varstructflag)); + if (mp || staticlink) { + if (usePP) + output(" PP("); + else if (spacefuncs) + output(" "); + output("("); + if (showtypes || shownames) { + firstflag = 0; + while (mp) { + if (firstflag++) + if (spacecommas) + output(",\002 "); + else + output(",\002"); + name = (mp->othername && isheader) ? mp->othername : mp->name; + tp = (mp->othername) ? mp->rectype : mp->type; + if (!showtypes) { + output(name); + } else { + output(storageclassname(varstorageclass(mp))); + if (!shownames || (isforward && *name == '_')) { + out_type(tp, 1); + } else { + if (dopromote) + tp = promote_type(tp); + outbasetype(tp, ODECL_CHARSTAR|ODECL_FREEARRAY); + output(" "); + outdeclarator(tp, name, + ODECL_CHARSTAR|ODECL_FREEARRAY); + } + } + if (isheader) + mp->wasdeclared = showtypes; + if (mp->type == tp_strptr && mp->anyvarflag) { /* VAR STRING parameter */ + if (spacecommas) + output(",\002 "); + else + output(",\002"); + if (showtypes) { + if (useAnyptrMacros == 1 || useconsts == 2) + output("Const "); + else if (ansiC > 0) + output("const "); + output("int"); + } + if (shownames) { + if (showtypes) + output(" "); + output(format_s(name_STRMAX, mp->name)); + } + } + mp = mp->xnext; + } + if (staticlink) { /* sub-procedure with static link */ + if (firstflag++) + if (spacecommas) + output(",\002 "); + else + output(",\002"); + if (type->issigned) { + if (showtypes) + if (tp_special_anyptr) + output("Anyptr "); + else if (voidstar) + output("void *"); + else + output("char *"); + if (shownames) + output("_link"); + } else { + mp = type->meaning->ctx; + if (showtypes) { + output("struct "); + output(format_s(name_LOC, mp->name)); + output(" *"); + } + if (shownames) { + output(format_s(name_LINK, mp->name)); + } + } + } + } + output(")"); + if (usePP) + output(")"); + } else { + if (usePP) + output(" PV()"); + else { + if (spacefuncs) + output(" "); + if (void_args) + output("(void)"); + else + output("()"); + } + } +} + + + +void outdeclarator(type, name, flags) +Type *type; +char *name; +int flags; +{ + int i, depth, anyptrs, anyarrays; + Expr *dimen[30]; + Expr *ex, *maxv; + Type *tp, *functype, *basetype; + Expr funcdummy; /* yow */ + + anyptrs = 0; + anyarrays = 0; + functype = NULL; + basetype = findbasetype(type, flags); + for (depth = 0, tp = type; tp && tp != basetype; tp = tp->basetype) { + switch (tp->kind) { + + case TK_POINTER: + if (tp->basetype) { + switch (tp->basetype->kind) { + + case TK_VOID: + if (tp->basetype == tp_void && + tp_special_anyptr) { + tp = tp_special_anyptr; + continue; + } + break; + + case TK_ARRAY: /* ptr to array of x => ptr to x */ + case TK_STRING: /* or => array of x */ + case TK_SET: + if (stararrays == 1 || + !(flags & ODECL_FREEARRAY) || + (tp->basetype->structdefd && + stararrays != 2)) { + tp = tp->basetype; + flags &= ~ODECL_CHARSTAR; + } else { + continue; + } + break; + + default: + break; + } + } + dimen[depth++] = NULL; + anyptrs++; + if (tp->kind == TK_POINTER && + tp->fbase && tp->fbase->wasdeclared) + break; + continue; + + case TK_ARRAY: + flags &= ~ODECL_CHARSTAR; + if (tp->meaning && tp->meaning->kind == MK_TYPE && + tp->meaning->wasdeclared) + break; + if (tp->structdefd) { /* conformant array */ + if (!variablearrays && + !(tp->basetype->kind == TK_ARRAY && + tp->basetype->structdefd)) /* avoid mult. notes */ + note("Conformant array code may not work in all compilers [101]"); + } + ex = arraysize(tp, 1); + if (!ex) + ex = makeexpr_name("", tp_integer); + dimen[depth++] = ex; + anyarrays++; + if (tp->fbase && tp->fbase->wasdeclared) + break; + continue; + + case TK_SET: + ord_range_expr(tp->indextype, NULL, &maxv); + maxv = enum_to_int(copyexpr(maxv)); + if (ord_type(maxv->val.type)->kind == TK_CHAR) + maxv->val.type = tp_integer; + dimen[depth++] = makeexpr_plus(makeexpr_div(maxv, makeexpr_setbits()), + makeexpr_long(2)); + break; + + case TK_STRING: + if ((flags & ODECL_CHARSTAR) && stararrays == 1) { + dimen[depth++] = NULL; + } else { + ord_range_expr(tp->indextype, NULL, &maxv); + dimen[depth++] = makeexpr_plus(copyexpr(maxv), makeexpr_long(1)); + } + continue; + + case TK_FILE: + break; + + case TK_CPROCPTR: + dimen[depth++] = NULL; + anyptrs++; + if (procptrprototypes) + continue; + dimen[depth++] = &funcdummy; + break; + + case TK_FUNCTION: + dimen[depth++] = &funcdummy; + if (!functype) + functype = tp; + continue; + + default: + break; + } + break; + } + if (!*name && depth && (spaceexprs > 0 || + (spaceexprs != 0 && !dimen[depth-1]))) + output(" "); /* spacing for abstract declarator */ + if ((flags & ODECL_FUNCTION) && anyptrs) + output(" "); + if (anyarrays > 1 && !(flags & ODECL_FUNCTION)) + output("\003"); + for (i = depth; --i >= 0; ) { + if (!dimen[i]) + output("*"); + if (i > 0 && + ((dimen[i] && !dimen[i-1]) || + (dimen[i-1] && !dimen[i] && extraparens > 0))) + output("("); + } + if (flags & ODECL_FUNCTION) + output("\n"); + if (anyarrays > 1 && (flags & ODECL_FUNCTION)) + output("\003"); + output(name); + for (i = 0; i < depth; i++) { + if (i > 0 && + ((dimen[i] && !dimen[i-1]) || + (dimen[i-1] && !dimen[i] && extraparens > 0))) + output(")"); + if (dimen[i]) { + if (dimen[i] == &funcdummy) { + if (lookback(1) == ')') + output("\002"); + if (functype) + declare_args(functype, (flags & ODECL_HEADER) != 0, + (flags & ODECL_FORWARD) != 0); + else if (spacefuncs) + output(" ()"); + else + output("()"); + } else { + if (lookback(1) == ']') + output("\002"); + output("["); + if (!(flags & ODECL_FREEARRAY) || stararrays == 0 || i > 0) + out_expr(dimen[i]); + freeexpr(dimen[i]); + output("]"); + } + } + } + if (anyarrays > 1) + output("\004"); +} + + + + + + +/* Find out if types t1 and t2 will work out to be the same C type, + for purposes of type-casting */ + +Type *canonicaltype(type) +Type *type; +{ + if (type->kind == TK_SUBR || type->kind == TK_ENUM || + type->kind == TK_PROCPTR) + type = findbasetype(type, 0); + if (type == tp_char) + return tp_ubyte; + if (type->kind == TK_POINTER) { + if (type->smin) + return type; + else if (type->basetype->kind == TK_ARRAY || + type->basetype->kind == TK_STRING || + type->basetype->kind == TK_SET) + return makepointertype(canonicaltype(type->basetype->basetype)); + else if (type->basetype == tp_void) + return (voidstar) ? tp_anyptr : makepointertype(tp_abyte); + else if (type->basetype->kind == TK_FILE) + return tp_text; + else + return makepointertype(canonicaltype(type->basetype)); + } + return type; +} + + +int identicaltypes(t1, t2) +Type *t1, *t2; +{ + if (t1 == t2) + return 1; + if (t1->kind == t2->kind) { + if (t1->kind == TK_SUBR) + return (identicaltypes(t1->basetype, t2->basetype) && + exprsame(t1->smin, t2->smin, 2) && + exprsame(t1->smax, t2->smax, 2)); + if (t1->kind == TK_SET || + t1->kind == TK_SMALLSET) + return (exprsame(t1->indextype->smax, + t2->indextype->smax, 2)); + if (t1->kind == TK_ARRAY || + t1->kind == TK_STRING || + t1->kind == TK_SMALLARRAY) + return (identicaltypes(t1->basetype, t2->basetype) && + identicaltypes(t1->indextype, t2->indextype) && + t1->structdefd == t2->structdefd && + ((!t1->smin && !t2->smin) || + (t1->smin && t2->smin && + exprsame(t1->smin, t2->smin, 2))) && + ((!t1->smax && !t2->smax) || + (t1->smax && t2->smax && + exprsame(t1->smax, t2->smax, 2) && + t1->escale == t2->escale && + t1->issigned == t2->issigned))); + } + return 0; +} + + +int similartypes(t1, t2) +Type *t1, *t2; +{ + if (debug > 3) { fprintf(outf, "similartypes("); dumptypename(t1,1); fprintf(outf, ","); dumptypename(t2,1); fprintf(outf, ") = %d\n", identicaltypes(t1, t2)); } + if (identicaltypes(t1, t2)) + return 1; + t1 = canonicaltype(t1); + t2 = canonicaltype(t2); + return (t1 == t2); +} + + + + + +Static int checkstructconst(mp) +Meaning *mp; +{ + return (mp->kind == MK_VAR && + mp->constdefn && + mp->constdefn->kind == EK_CONST && + (mp->constdefn->val.type->kind == TK_ARRAY || + mp->constdefn->val.type->kind == TK_RECORD)); +} + + +Static int mixable(mp1, mp2, args, flags) +Meaning *mp1, *mp2; +int args, flags; +{ + Type *tp1 = mp1->type, *tp2 = mp2->type; + + if (mixvars == 0) + return 0; + if (mp1->kind == MK_FIELD && + (mp1->val.i || mp2->val.i) && mixfields == 0) + return 0; + if (checkstructconst(mp1) || checkstructconst(mp2)) + return 0; + if (mp1->comments) { + if (findcomment(mp1->comments, CMT_NOT | CMT_PRE, -1)) + return 0; + } + if (mp2->comments) { + if (findcomment(mp2->comments, CMT_PRE, -1)) + return 0; + } + if ((mp1->constdefn && (mp1->kind == MK_VAR || mp1->kind == MK_VARREF)) || + (mp2->constdefn && (mp2->kind == MK_VAR || mp2->kind == MK_VARREF))) { + if (mixinits == 0) + return 0; + if (mixinits != 1 && + (!mp1->constdefn || !mp2->constdefn)) + return 0; + } + if (args) { + if (mp1->kind == MK_PARAM && mp1->othername) + tp1 = mp1->rectype; + if (mp2->kind == MK_PARAM && mp2->othername) + tp2 = mp2->rectype; + } + if (tp1 == tp2) + return 1; + switch (mixtypes) { + case 0: + return 0; + case 1: + return (findbasetype(tp1, flags) == findbasetype(tp2, flags)); + default: + if (findbasetype(tp1, flags) != findbasetype(tp2, flags)) + return 0; + while (tp1->kind == TK_POINTER && !tp1->smin && tp1->basetype) + tp1 = tp1->basetype; + while (tp2->kind == TK_POINTER && !tp2->smin && tp2->basetype) + tp2 = tp2->basetype; + return (tp1 == tp2); + } +} + + + +void declarefiles(fnames) +Strlist *fnames; +{ + Meaning *mp; + char *cp; + + while (fnames) { + mp = (Meaning *)fnames->value; + if (mp->kind == MK_VAR || mp->kind == MK_FIELD) { + if (mp->namedfile) { + output(storageclassname(varstorageclass(mp))); + output(format_ss("%s %s", charname, + format_s(name_FNVAR, fnames->s))); + output(format_s("[%s];\n", *name_FNSIZE ? name_FNSIZE : "80")); + } + if (mp->bufferedfile && *declbufname) { + cp = format_s("%s", storageclassname(varstorageclass(mp))); + if (*cp && isspace(cp[strlen(cp)-1])) + cp[strlen(cp)-1] = 0; + if (*cp || !*declbufncname) { + output(declbufname); + output("("); + output(fnames->s); + output(","); + output(cp); + } else { + output(declbufncname); + output("("); + output(fnames->s); + } + output(","); + out_type(mp->type->basetype->basetype, 1); + output(");\n"); + } + } + strlist_eat(&fnames); + } +} + + + +char *variantfieldname(num) +int num; +{ + if (num >= 0) + return format_d("U%d", num); + else + return format_d("UM%d", -num); +} + + +int record_is_union(tp) +Type *tp; +{ + return (tp->kind == TK_RECORD && + tp->fbase && tp->fbase->kind == MK_VARIANT); +} + + +void outfieldlist(mp) +Meaning *mp; +{ + Meaning *mp0; + int num, only_union, empty, saveindent, saveindent2; + Strlist *fnames, *fn; + + if (!mp) { + output("int empty_struct; /* Pascal record was empty */\n"); + return; + } + only_union = (mp && mp->kind == MK_VARIANT); + fnames = NULL; + while (mp && mp->kind == MK_FIELD) { + flushcomments(&mp->comments, CMT_PRE, -1); + output(storageclassname(varstorageclass(mp) & 0x10)); + if (mp->dtype) + output(mp->dtype->name); + else + outbasetype(mp->type, 0); + output(" \005"); + for (;;) { + if (mp->dtype) + output(mp->name); + else + outdeclarator(mp->type, mp->name, 0); + if (mp->val.i && (mp->type != tp_abyte || mp->val.i != 8)) + output(format_d(" : %d", mp->val.i)); + if (isfiletype(mp->type, 0)) { + fn = strlist_append(&fnames, mp->name); + fn->value = (long)mp; + } + mp->wasdeclared = 1; + if (!mp->cnext || mp->cnext->kind != MK_FIELD || + mp->dtype != mp->cnext->dtype || + varstorageclass(mp) != varstorageclass(mp->cnext) || + !mixable(mp, mp->cnext, 0, 0)) + break; + mp = mp->cnext; + if (spacecommas) + output(",\001 "); + else + output(",\001"); + } + output(";"); + outtrailcomment(mp->comments, -1, declcommentindent); + flushcomments(&mp->comments, -1, -1); + mp = mp->cnext; + } + declarefiles(fnames); + if (mp) { + saveindent = outindent; + empty = 1; + if (!only_union) { + output("union {\n"); + moreindent(tabsize); + moreindent(structindent); + } + while (mp) { + mp0 = mp->ctx; + num = ord_value(mp->val); + while (mp && mp->ctx == mp0) + mp = mp->cnext; + if (mp0) { + empty = 0; + if (!mp0->cnext && mp0->kind == MK_FIELD) { + mp0->val.i = 0; /* no need for bit fields in a union! */ + outfieldlist(mp0); + } else { + if (mp0->kind == MK_VARIANT) + output("union {\n"); + else + output("struct {\n"); + saveindent2 = outindent; + moreindent(tabsize); + moreindent(structindent); + outfieldlist(mp0); + outindent = saveindent2; + output("} "); + output(format_s(name_VARIANT, variantfieldname(num))); + output(";\n"); + } + flushcomments(&mp0->comments, -1, -1); + } + } + if (empty) + output("int empty_union; /* Pascal variant record was empty */\n"); + if (!only_union) { + outindent = saveindent; + output("} "); + output(format_s(name_UNION, "")); + output(";\n"); + } + } +} + + + +void declarebigfile(type) +Type *type; +{ + output("FILE *f;\n"); + if (!*declbufncname) { + output(declbufname); + output("(f,,"); + } else { + output(declbufncname); + output("(f,"); + } + out_type(type->basetype, 1); + output(");\n"); + output(charname); + output(format_s(" name[%s];\n", *name_FNSIZE ? name_FNSIZE : "80")); +} + + + +void outbasetype(type, flags) +Type *type; +int flags; +{ + Meaning *mp; + int saveindent; + + type = findbasetype(type, flags | ODECL_DECL); + if (type->preserved && type->meaning->wasdeclared) { + output(type->meaning->name); + return; + } + switch (type->kind) { + + case TK_INTEGER: + if (type == tp_uint) { + output("unsigned"); + } else if (type == tp_sint) { + if (useAnyptrMacros == 1) + output("Signed int"); + else if (hassignedchar) + output("signed int"); + else + output("int"); /* will sign-extend by hand */ + } else if (type == tp_unsigned) { + output("unsigned long"); + } else if (type != tp_int) + output(integername); + else + output("int"); + break; + + case TK_SUBR: + if (type == tp_special_anyptr) { + output("Anyptr"); + } else if (type == tp_abyte) { + output("char"); + } else if (type == tp_ubyte) { + output(ucharname); + } else if (type == tp_sbyte) { + output(scharname); + if (signedchars != 1 && !hassignedchar) + note("'signed char' may not be valid in all compilers [102]"); + } else { + if (type == tp_ushort) + output("unsigned "); + output("short"); + } + break; + + case TK_CHAR: + if (type == tp_uchar) { + output(ucharname); + } else if (type == tp_schar) { + output(scharname); + if (signedchars != 1 && !hassignedchar) + note("'signed char' may not be valid in all compilers [102]"); + } else + output(charname); + break; + + case TK_BOOLEAN: + output((*name_BOOLEAN) ? name_BOOLEAN : ucharname); + break; + + case TK_REAL: + if (type == tp_longreal) + output("double"); + else + output("float"); + break; + + case TK_VOID: + if (ansiC == 0) + output("int"); + else if (useAnyptrMacros == 1) + output("Void"); + else + output("void"); + break; + + case TK_PROCPTR: + output(name_PROCEDURE); + break; + + case TK_FILE: + output("FILE"); + break; + + case TK_SPECIAL: + if (type == tp_jmp_buf) + output("jmp_buf"); + break; + + default: + if (type->kind == TK_POINTER && type->smin) { + note("Forward pointer reference assumes struct type [323]"); + output("struct "); + output(format_s(name_STRUCT, type->smin->val.s)); + } else if (type->meaning && type->meaning->kind == MK_TYPE && + type->meaning->wasdeclared) { + output(type->meaning->name); + } else { + switch (type->kind) { + + case TK_ENUM: + output("enum {\n"); + saveindent = outindent; + moreindent(tabsize); + moreindent(structindent); + mp = type->fbase; + while (mp) { + output(mp->name); + mp = mp->xnext; + if (mp) + if (spacecommas) + output(",\001 "); + else + output(",\001"); + } + outindent = saveindent; + output("\n}"); + break; + + case TK_RECORD: + case TK_BIGFILE: + if (record_is_union(type)) + output("union "); + else + output("struct "); + if (type->meaning) + output(format_s(name_STRUCT, type->meaning->name)); + if (!type->structdefd) { + if (type->meaning) { + type->structdefd = 1; + output(" "); + } + output("{\n"); + saveindent = outindent; + moreindent(tabsize); + moreindent(structindent); + if (type->kind == TK_BIGFILE) + declarebigfile(type); + else + outfieldlist(type->fbase); + outindent = saveindent; + output("}"); + } + break; + + default: + break; + + } + } + break; + } +} + + + +void out_type(type, witharrays) +Type *type; +int witharrays; +{ + if (!witharrays && type->kind == TK_ARRAY) + type = makepointertype(type->basetype); + outbasetype(type, 0); + outdeclarator(type, "", 0); /* write an "abstract declarator" */ +} + + + + +int varstorageclass(mp) +Meaning *mp; +{ + int sclass; + + if (mp->kind == MK_PARAM || mp->kind == MK_VARPARAM || + mp->kind == MK_FIELD) + sclass = 0; + else if (blockkind == TOK_EXPORT) + if (usevextern) + if (mp->constdefn && + (mp->kind == MK_VAR || + mp->kind == MK_VARREF)) + sclass = 2; /* extern */ + else + sclass = 1; /* vextern */ + else + sclass = 0; /* (plain) */ + else if (mp->isfunction && mp->kind != MK_FUNCTION) + sclass = 2; /* extern */ + else if (mp->ctx->kind == MK_MODULE && + (var_static != 0 || + (findsymbol(mp->name)->flags & NEEDSTATIC)) && + !mp->exported && !mp->istemporary && blockkind != TOK_END) + sclass = (useAnyptrMacros) ? 4 : 3; /* (private) */ + else if (mp->isforward) + sclass = 3; /* static */ + else + sclass = 0; /* (plain) */ + if (mp->volatilequal) + sclass |= 0x10; + if (mp->constqual) + sclass |= 0x20; + if (debug>2) fprintf(outf, "varstorageclass(%s) = %d\n", mp->name, sclass); + return sclass; +} + + +char *storageclassname(i) +int i; +{ + char *scname; + + switch (i & 0xf) { + case 1: + scname = "vextern "; + break; + case 2: + scname = "extern "; + break; + case 3: + scname = "static "; + break; + case 4: + scname = "Static "; + break; + default: + scname = ""; + break; + } + if (i & 0x10) + if (useAnyptrMacros == 1) + scname = format_s("%sVolatile ", scname); + else if (ansiC > 0) + scname = format_s("%svolatile ", scname); + if (i & 0x20) + if (useAnyptrMacros == 1) + scname = format_s("%sConst ", scname); + else if (ansiC > 0) + scname = format_s("%sconst ", scname); + return scname; +} + + + +Static int var_mixable; + +void declarevar(mp, which) +Meaning *mp; +int which; /* 0x1=header, 0x2=body, 0x4=trailer, 0x8=in varstruct */ +{ + int isstatic, isstructconst, saveindent, i; + Strlist *sl; + + isstructconst = checkstructconst(mp); + isstatic = varstorageclass(mp); + if (which & 0x8) + isstatic &= 0x10; /* clear all but Volatile flags */ + flushcomments(&mp->comments, CMT_PRE, -1); + if (which & 0x1) { + if (isstructconst) + outsection(minorspace); + output(storageclassname(isstatic)); + if (mp->dtype) + output(mp->dtype->name); + else + outbasetype(mp->type, 0); + output(" \005"); + } + if (which & 0x2) { + if (mp->dtype) + output(mp->name); + else + outdeclarator(mp->type, mp->name, 0); + if (mp->constdefn && blockkind != TOK_EXPORT && + (mp->kind == MK_VAR || mp->kind == MK_VARREF)) { + if (mp->varstructflag) { /* move init code into function body */ + intwarning("declarevar", + format_s("Variable %s initializer not removed [125]", mp->name)); + } else { + if (isstructconst) { + output(" = {\n"); + saveindent = outindent; + moreindent(tabsize); + moreindent(structinitindent); + out_expr((Expr *)mp->constdefn->val.i); + outindent = saveindent; + output("\n}"); + var_mixable = 0; + } else if (mp->type->kind == TK_ARRAY && + mp->constdefn->val.type->kind == TK_STRING && + !initpacstrings) { + if (mp->ctx->kind == MK_MODULE) { + sl = strlist_append(&initialcalls, + format_sss("memcpy(%s,\002 %s,\002 sizeof(%s))", + mp->name, + makeCstring(mp->constdefn->val.s, + mp->constdefn->val.i), + mp->name)); + sl->value = 1; + } else if (mp->isforward) { + output(" = {\005"); + for (i = 0; i < mp->constdefn->val.i; i++) { + if (i > 0) + output(",\001"); + output(makeCchar(mp->constdefn->val.s[i])); + } + output("}"); + mp->constdefn = NULL; + var_mixable = 0; + } + } else { + output(" = "); + out_expr(mp->constdefn); + } + } + } + } + if (which & 0x4) { + output(";"); + outtrailcomment(mp->comments, -1, declcommentindent); + flushcomments(&mp->comments, -1, -1); + if (isstructconst) + outsection(minorspace); + } +} + + + + +Static int checkvarmacdef(ex, mp) +Expr *ex; +Meaning *mp; +{ + int i; + + if ((ex->kind == EK_NAME || ex->kind == EK_BICALL) && + !strcmp(ex->val.s, mp->name)) { + ex->kind = EK_VAR; + ex->val.i = (long)mp; + ex->val.type = mp->type; + return 1; + } + if (ex->kind == EK_VAR && ex->val.i == (long)mp) + return 1; + i = ex->nargs; + while (--i >= 0) + if (checkvarmacdef(ex->args[i], mp)) + return 1; + return 0; +} + + +int checkvarmac(mp) +Meaning *mp; +{ + if (mp->kind != MK_VARMAC && mp->kind != MK_FUNCTION) + return 0; + if (!mp->constdefn) + return 0; + return checkvarmacdef(mp->constdefn, mp); +} + + + +#define varkind(k) ((k)==MK_VAR||(k)==MK_VARREF||(k)==MK_PARAM||(k)==MK_VARPARAM) + +int declarevars(ctx, invarstruct) +Meaning *ctx; +int invarstruct; +{ + Meaning *mp, *mp0, *mp2; + Strlist *fnames, *fn; + int flag, first; + + if (ctx->kind == MK_FUNCTION && ctx->varstructflag && !invarstruct) { + output("struct "); + output(format_s(name_LOC, ctx->name)); + output(" "); + output(format_s(name_VARS, ctx->name)); + output(";\n"); + flag = 1; + } else + flag = 0; + if (debug>2) { + fprintf(outf,"declarevars:\n"); + for (mp = ctx->cbase; mp; mp = mp->xnext) { + fprintf(outf, " %-22s%-15s%3d", mp->name, + meaningkindname(mp->kind), + mp->refcount); + if (mp->wasdeclared) + fprintf(outf, " [decl]"); + if (mp->varstructflag) + fprintf(outf, " [struct]"); + fprintf(outf, "\n"); + } + } + fnames = NULL; + for (;;) { + mp = ctx->cbase; + while (mp && (!(varkind(mp->kind) || checkvarmac(mp)) || + mp->wasdeclared || mp->varstructflag != invarstruct || + mp->refcount <= 0)) + mp = mp->cnext; + if (!mp) + break; + flag = 1; + first = 1; + mp0 = mp2 = mp; + var_mixable = 1; + while (mp) { + if ((varkind(mp->kind) || checkvarmac(mp)) && + !mp->wasdeclared && var_mixable && + mp->dtype == mp0->dtype && + varstorageclass(mp) == varstorageclass(mp0) && + mp->varstructflag == invarstruct && mp->refcount > 0) { + if (mixable(mp2, mp, 0, 0) || first) { + if (!first) + if (spacecommas) + output(",\001 "); + else + output(",\001"); + declarevar(mp, (first ? 0x3 : 0x2) | + (invarstruct ? 0x8 : 0)); + mp2 = mp; + mp->wasdeclared = 1; + if (isfiletype(mp->type, 0)) { + fn = strlist_append(&fnames, mp->name); + fn->value = (long)mp; + } + first = 0; + } else + if (mixvars != 1) + break; + } + if (first) { + intwarning("declarevars", + format_s("Unable to declare %s [126]", mp->name)); + mp->wasdeclared = 1; + first = 0; + } + if (mixvars == 0) + break; + mp = mp->cnext; + } + declarevar(mp2, 0x4); + } + declarefiles(fnames); + return flag; +} + + + +void redeclarevars(ctx) +Meaning *ctx; +{ + Meaning *mp; + + for (mp = ctx->cbase; mp; mp = mp->cnext) { + if ((mp->kind == MK_VAR || mp->kind == MK_VARREF) && + mp->constdefn) { + mp->wasdeclared = 0; /* mark for redeclaration, this time */ + } /* with its initializer */ + } +} + + + + + +void out_argdecls(ftype) +Type *ftype; +{ + Meaning *mp, *mp0; + Type *tp; + int done; + int flag = 1; + char *name; + + done = 0; + do { + mp = ftype->fbase; + while (mp && mp->wasdeclared) + mp = mp->xnext; + if (mp) { + if (flag) + output("\n"); + flag = 0; + mp0 = mp; + outbasetype(mp->othername ? mp->rectype : mp->type, + ODECL_CHARSTAR|ODECL_FREEARRAY); + output(" \005"); + while (mp) { + if (!mp->wasdeclared) { + if (mp == mp0 || + mixable(mp0, mp, 1, ODECL_CHARSTAR|ODECL_FREEARRAY)) { + if (mp != mp0) + if (spacecommas) + output(",\001 "); + else + output(",\001"); + name = (mp->othername) ? mp->othername : mp->name; + tp = (mp->othername) ? mp->rectype : mp->type; + outdeclarator(tp, name, + ODECL_CHARSTAR|ODECL_FREEARRAY); + mp->wasdeclared = 1; + } else + if (mixvars != 1) + break; + } + mp = mp->xnext; + } + output(";\n"); + } else + done = 1; + } while (!done); + for (mp0 = ftype->fbase; mp0 && (mp0->type != tp_strptr || + !mp0->anyvarflag); mp0 = mp0->xnext) ; + if (mp0) { + output("int "); + for (mp = mp0; mp; mp = mp->xnext) { + if (mp->type == tp_strptr && mp->anyvarflag) { + if (mp != mp0) { + if (mixvars == 0) + output(";\nint "); + else if (spacecommas) + output(",\001 "); + else + output(",\001"); + } + output(format_s(name_STRMAX, mp->name)); + } + } + output(";\n"); + } + if (ftype->meaning && ftype->meaning->ctx->kind == MK_FUNCTION && + ftype->meaning->ctx->varstructflag) { + if (flag) + output("\n"); + output("struct "); + output(format_s(name_LOC, ftype->meaning->ctx->name)); + output(" *"); + output(format_s(name_LINK, ftype->meaning->ctx->name)); + output(";\n"); + } +} + + + + +void makevarstruct(func) +Meaning *func; +{ + int flag = 0; + int saveindent; + + outsection(minfuncspace); + output(format_s("\n/* Local variables for %s: */\n", func->name)); + output("struct "); + output(format_s(name_LOC, func->name)); + output(" {\n"); + saveindent = outindent; + moreindent(tabsize); + moreindent(structindent); + if (func->ctx->kind == MK_FUNCTION && func->ctx->varstructflag) { + output("struct "); + output(format_s(name_LOC, func->ctx->name)); + output(" *"); + output(format_s(name_LINK, func->ctx->name)); + output(";\n"); + flag++; + } + flag += declarevars(func, 1); + if (!flag) /* Avoid generating an empty struct */ + output("int _meef_;\n"); /* (I don't think this will ever happen) */ + outindent = saveindent; + output("} ;\n"); + outsection(minfuncspace); + strlist_insert(&varstructdecllist, func->name); +} + + + + + + +Type *maketype(kind) +enum typekind kind; +{ + Type *tp; + tp = ALLOC(1, Type, types); + tp->kind = kind; + tp->basetype = NULL; + tp->indextype = NULL; + tp->pointertype = NULL; + tp->meaning = NULL; + tp->fbase = NULL; + tp->smin = NULL; + tp->smax = NULL; + tp->issigned = 0; + tp->dumped = 0; + tp->structdefd = 0; + tp->preserved = 0; + return tp; +} + + + + +Type *makesubrangetype(type, smin, smax) +Type *type; +Expr *smin, *smax; +{ + Type *tp; + + if (type->kind == TK_SUBR) + type = type->basetype; + tp = maketype(TK_SUBR); + tp->basetype = type; + tp->smin = smin; + tp->smax = smax; + return tp; +} + + + +Type *makesettype(setof) +Type *setof; +{ + Type *tp; + long smax; + + if (ord_range(setof, NULL, &smax) && smax < setbits && smallsetconst >= 0) + tp = maketype(TK_SMALLSET); + else + tp = maketype(TK_SET); + tp->basetype = tp_integer; + tp->indextype = setof; + return tp; +} + + + +Type *makestringtype(len) +int len; +{ + Type *type; + int index; + + len |= 1; + if (len >= stringceiling) + type = tp_str255; + else { + index = (len-1) / 2; + if (stringtypecache[index]) + return stringtypecache[index]; + type = maketype(TK_STRING); + type->basetype = tp_char; + type->indextype = makesubrangetype(tp_integer, + makeexpr_long(0), + makeexpr_long(len)); + stringtypecache[index] = type; + } + return type; +} + + + +Type *makepointertype(type) +Type *type; +{ + Type *tp; + + if (type->pointertype) + return type->pointertype; + tp = maketype(TK_POINTER); + tp->basetype = type; + type->pointertype = tp; + return tp; +} + + + + + +Value p_constant(type) +Type *type; +{ + Value val; + Expr *ex; + + ex = p_expr(type); + if (type) + ex = gentle_cast(ex, type); + val = eval_expr(ex); + freeexpr(ex); + if (!val.type) { + warning("Expected a constant [127]"); + val.type = (type) ? type : tp_integer; + } + return val; +} + + + + +int typebits(smin, smax) +long smin, smax; +{ + unsigned long size; + int bits; + + if (smin >= 0 || (smin == -1 && smax == 0)) { + bits = 1; + size = smax; + } else { + bits = 2; + smin = -1L - smin; + if (smin >= smax) + size = smin; + else + size = smax; + } + while (size > 1) { + bits++; + size >>= 1; + } + return bits; +} + + +int packedsize(fname, typep, sizep, mode) +char *fname; +Type **typep; +long *sizep; +int mode; +{ + Type *tp = *typep; + long smin, smax; + int res, issigned; + short savefold; + long size; + + if (packing == 0) /* suppress packing */ + return 0; + if (tp->kind != TK_SUBR && tp->kind != TK_INTEGER && tp->kind != TK_ENUM && + tp->kind != TK_CHAR && tp->kind != TK_BOOLEAN) + return 0; + if (tp == tp_unsigned) + return 0; + if (!ord_range(tp, &smin, &smax)) { + savefold = foldconsts; + foldconsts = 1; + res = ord_range(tp, &smin, &smax); + foldconsts = savefold; + if (res) { + note(format_s("Field width for %s is based on expansion of #defines [103]", + fname)); + } else { + note(format_ss("Cannot compute size of field %s; assuming %s [104]", + fname, integername)); + return 0; + } + } else { + if (tp->kind == TK_ENUM) + note(format_ssd("Field width for %s assumes enum%s has %d elements [105]", + fname, + (tp->meaning) ? format_s(" %s", tp->meaning->name) : "", + smax + 1)); + } + issigned = (smin < 0); + size = typebits(smin, smax); + if (size >= ((sizeof_long > 0) ? sizeof_long : 32)) + return 0; + if (packing != 1) { + if (size <= 8) + size = 8; + else if (size <= 16) + size = 16; + else + return 0; + } + if (!issigned) { + *typep = (mode == 0) ? tp_int : tp_uint; + } else { + if (mode == 2 && !hassignedchar && !*signextname) + return 0; + *typep = (mode == 1) ? tp_int : tp_sint; + } + *sizep = size; + return issigned; +} + + + +Static void fielddecl(mp, type, tp2, val, ispacked, aligned) +Meaning *mp; +Type **type, **tp2; +long *val; +int ispacked, *aligned; +{ + long smin, smax, smin2, smax2; + + *tp2 = *type; + *val = 0; + if (ispacked && !mp->constdefn && *type != tp_unsigned) { + (void)packedsize(mp->sym->name, tp2, val, signedfield); + if (*aligned && *val && + (ord_type(*type)->kind == TK_CHAR || + ord_type(*type)->kind == TK_INTEGER) && + ord_range(findbasetype(*type, 0), &smin, &smax)) { + if (ord_range(*type, &smin2, &smax2)) { + if (typebits(smin, smax) == 16 && + typebits(smin2, smax2) == 8 && *val == 8) { + *tp2 = tp_abyte; + } + } + if (typebits(smin, smax) == *val && + *val != 7) { /* don't be fooled by tp_abyte */ + /* don't need to use a bit-field for this field */ + /* so not specifying one may make it more efficient */ + /* (and also helps to simulate HP's $allow_packed$ mode) */ + *val = 0; + *tp2 = *type; + } + } + if (*aligned && *val == 8 && + (ord_type(*type)->kind == TK_BOOLEAN || + ord_type(*type)->kind == TK_ENUM)) { + *val = 0; + *tp2 = tp_ubyte; + } + } + if (*val != 8 && *val != 16) + *aligned = (*val == 0); +} + + + +/* This function locates byte-sized fields which were unaligned, but which + are followed by aligned quantities so that they can be made aligned + with no loss in storage efficiency. */ + +Static void realignfields(firstmp, stopmp) +Meaning *firstmp, *stopmp; +{ + Meaning *mp; + + for (mp = firstmp; mp && mp != stopmp; mp = mp->cnext) { + if (mp->kind == MK_FIELD) { + if (mp->val.i == 16) { + if (mp->type == tp_uint) + mp->type = tp_ushort; + else + mp->type = tp_sshort; + mp->val.i = 0; + } else if (mp->val.i == 8) { + if (mp->type == tp_uint) { + mp->type = tp_ubyte; + mp->val.i = 0; + } else if (hassignedchar || signedchars == 1) { + mp->type = tp_sbyte; + mp->val.i = 0; + } else + mp->type = tp_abyte; + } + } + } +} + +static void tryrealignfields(firstmp) +Meaning *firstmp; +{ + Meaning *mp, *head; + + head = NULL; + for (mp = firstmp; mp; mp = mp->cnext) { + if (mp->kind == MK_FIELD) { + if ((mp->val.i == 8 && + (mp->type == tp_uint || + hassignedchar || signedchars == 1)) || + mp->val.i == 16) { + if (!head) + head = mp; + } else { + if (mp->val.i == 0) + realignfields(head, mp); + head = NULL; + } + } + } + realignfields(head, NULL); +} + + + +void decl_comments(mp) +Meaning *mp; +{ + Strlist *cmt; + + if (spitcomments != 1) { + changecomments(curcomments, -1, -1, CMT_PRE, 0); + strlist_mix(&mp->comments, curcomments); + curcomments = NULL; + cmt = grabcomment(CMT_TRAIL); + if (cmt) { + changecomments(mp->comments, CMT_TRAIL, -1, CMT_PRE, -1); + strlist_mix(&mp->comments, cmt); + } + if (mp->comments) + mp->refcount++; /* force it to be included if it has comments */ + } +} + + + + + +Static void p_fieldlist(tp, flast, ispacked, tname) +Type *tp; +Meaning **flast; +int ispacked; +Meaning *tname; +{ + Meaning *firstm, *lastm, *veryfirstm, *dtype; + Symbol *sym; + Type *type, *tp2; + long li1, li2; + int aligned, constflag, volatileflag; + short saveskipind; + Strlist *l1; + + saveskipind = skipindices; + skipindices = 0; + aligned = 1; + lastm = NULL; + veryfirstm = NULL; + while (curtok == TOK_IDENT) { + firstm = addfield(curtoksym, &flast, tp, tname); + if (!veryfirstm) + veryfirstm = firstm; + lastm = firstm; + gettok(); + decl_comments(lastm); + while (curtok == TOK_COMMA) { + gettok(); + if (wexpecttok(TOK_IDENT)) + lastm = addfield(curtoksym, &flast, tp, tname); + gettok(); + decl_comments(lastm); + } + if (wneedtok(TOK_COLON)) { + constflag = volatileflag = 0; + p_attributes(); + if ((l1 = strlist_find(attrlist, "READONLY")) != NULL) { + constflag = 1; + strlist_delete(&attrlist, l1); + } + if ((l1 = strlist_find(attrlist, "VOLATILE")) != NULL) { + volatileflag = 1; + strlist_delete(&attrlist, l1); + } + dtype = (curtok == TOK_IDENT) ? curtokmeaning : NULL; + type = p_type(firstm); + decl_comments(lastm); + fielddecl(firstm, &type, &tp2, &li1, ispacked, &aligned); + dtype = validatedtype(dtype, type); + for (;;) { + firstm->type = tp2; + firstm->dtype = dtype; + firstm->val.type = type; + firstm->val.i = li1; + firstm->constqual = constflag; + firstm->volatilequal = volatileflag; + tp->meaning = tname; + setupfilevar(firstm); + tp->meaning = NULL; + if (firstm == lastm) + break; + firstm = firstm->cnext; + } + } else + skiptotoken2(TOK_SEMI, TOK_CASE); + if (curtok == TOK_SEMI) + gettok(); + } + if (curtok == TOK_CASE) { + gettok(); + if (curtok == TOK_COLON) + gettok(); + wexpecttok(TOK_IDENT); + sym = curtoksym; + if (curtokmeaning) + type = curtokmeaning->type; + gettok(); + if (curtok == TOK_COLON) { + firstm = addfield(sym, &flast, tp, tname); + if (!veryfirstm) + veryfirstm = firstm; + gettok(); + firstm->isforward = 1; + firstm->val.type = type = p_type(firstm); + fielddecl(firstm, &firstm->val.type, &firstm->type, &firstm->val.i, + ispacked, &aligned); + } else { + firstm = NULL; + } + if (!wneedtok(TOK_OF)) { + skiptotoken2(TOK_END, TOK_RPAR); + goto bounce; + } + if (firstm) + decl_comments(firstm); + while (curtok == TOK_VBAR) + gettok(); + while (curtok != TOK_END && curtok != TOK_RPAR) { + firstm = NULL; + for (;;) { + lastm = addfield(NULL, &flast, tp, tname); + if (!firstm) + firstm = lastm; + checkkeyword(TOK_OTHERWISE); + if (curtok == TOK_ELSE || curtok == TOK_OTHERWISE) { + lastm->val = make_ord(type, 999); + break; + } else { + lastm->val = p_constant(type); + if (curtok == TOK_DOTS) { + gettok(); + li1 = ord_value(lastm->val); + li2 = ord_value(p_constant(type)); + while (++li1 <= li2) { + lastm = addfield(NULL, &flast, tp, tname); + lastm->val = make_ord(type, li1); + } + } + } + if (curtok == TOK_COMMA) + gettok(); + else + break; + } + if (curtok == TOK_ELSE || curtok == TOK_OTHERWISE) { + gettok(); + } else if (!wneedtok(TOK_COLON) || + (!modula2 && !wneedtok(TOK_LPAR))) { + skiptotoken2(TOK_END, TOK_RPAR); + goto bounce; + } + p_fieldlist(tp, &lastm->ctx, ispacked, tname); + while (firstm != lastm) { + firstm->ctx = lastm->ctx; + firstm = firstm->cnext; + } + if (modula2) { + while (curtok == TOK_VBAR) + gettok(); + } else { + if (!wneedtok(TOK_RPAR)) + skiptotoken(TOK_RPAR); + } + if (curtok == TOK_SEMI) + gettok(); + } + if (modula2) { + wneedtok(TOK_END); + if (curtok == TOK_IDENT) { + note("Record variants supported only at end of record [106]"); + p_fieldlist(tp, &lastm->ctx, ispacked, tname); + } + } + } + tryrealignfields(veryfirstm); + if (lastm && curtok == TOK_END) { + strlist_mix(&lastm->comments, curcomments); + curcomments = NULL; + } + + bounce: + skipindices = saveskipind; +} + + + +Static Type *p_arraydecl(tname, ispacked, confp) +char *tname; +int ispacked; +Meaning ***confp; +{ + Type *tp, *tp2; + Meaning *mp; + Expr *ex; + long size, smin, smax, bitsize, fullbitsize; + int issigned, bpower, hasrange; + + tp = maketype(TK_ARRAY); + if (confp == NULL) { + tp->indextype = p_type(NULL); + if (tp->indextype->kind == TK_SUBR) { + if (ord_range(tp->indextype, &smin, NULL) && + smin > 0 && smin <= skipindices && !ispacked) { + tp->smin = makeexpr_val(make_ord(tp->indextype->basetype, smin)); + ex = makeexpr_val(make_ord(tp->indextype->basetype, 0)); + tp->indextype = makesubrangetype(tp->indextype->basetype, + ex, + copyexpr(tp->indextype->smax)); + } + } + } else { + if (modula2) { + **confp = mp = addmeaning(findsymbol(format_s(name_ALOW, tname)), MK_PARAM); + mp->fakeparam = 1; + mp->constqual = 1; + mp->xnext = addmeaning(findsymbol(format_s(name_AHIGH, tname)), MK_PARAM); + mp->xnext->fakeparam = 1; + mp->xnext->constqual = 1; + *confp = &mp->xnext->xnext; + tp2 = maketype(TK_SUBR); + tp2->basetype = tp_integer; + mp->type = tp_integer; + mp->xnext->type = mp->type; + tp2->smin = makeexpr_long(0); + tp2->smax = makeexpr_minus(makeexpr_var(mp->xnext), + makeexpr_var(mp)); + tp->indextype = tp2; + tp->structdefd = 1; + } else { + wexpecttok(TOK_IDENT); + tp2 = maketype(TK_SUBR); + if (peeknextchar() != ',' && + (!curtokmeaning || curtokmeaning->kind != MK_TYPE)) { + mp = addmeaning(curtoksym, MK_PARAM); + gettok(); + wneedtok(TOK_DOTS); + wexpecttok(TOK_IDENT); + mp->xnext = addmeaning(curtoksym, MK_PARAM); + gettok(); + if (wneedtok(TOK_COLON)) { + tp2->basetype = p_type(NULL); + } else { + tp2->basetype = tp_integer; + } + } else { + mp = addmeaning(findsymbol(format_s(name_ALOW, tname)), MK_PARAM); + mp->xnext = addmeaning(findsymbol(format_s(name_AHIGH, tname)), MK_PARAM); + tp2->basetype = p_type(NULL); + } + mp->fakeparam = 1; + mp->constqual = 1; + mp->xnext->fakeparam = 1; + mp->xnext->constqual = 1; + **confp = mp; + *confp = &mp->xnext->xnext; + mp->type = tp2->basetype; + mp->xnext->type = tp2->basetype; + tp2->smin = makeexpr_var(mp); + tp2->smax = makeexpr_var(mp->xnext); + tp->indextype = tp2; + tp->structdefd = 1; /* conformant array flag */ + } + } + if (curtok == TOK_COMMA || curtok == TOK_SEMI) { + gettok(); + tp->basetype = p_arraydecl(tname, ispacked, confp); + return tp; + } else { + if (!modula2) { + if (!wneedtok(TOK_RBR)) + skiptotoken(TOK_OF); + } + if (!wneedtok(TOK_OF)) + skippasttotoken(TOK_OF, TOK_COMMA); + checkkeyword(TOK_VARYING); + if (confp != NULL && + (curtok == TOK_ARRAY || curtok == TOK_PACKED || + curtok == TOK_VARYING)) { + tp->basetype = p_conformant_array(tname, confp); + } else { + tp->fbase = (curtok == TOK_IDENT) ? curtokmeaning : NULL; + tp->basetype = p_type(NULL); + tp->fbase = validatedtype(tp->fbase, tp->basetype); + } + if (!ispacked) + return tp; + size = 0; + tp2 = tp->basetype; + if (!tname) + tname = "array"; + issigned = packedsize(tname, &tp2, &size, 1); + if (!size || size > 8 || + (issigned && !packsigned) || + (size > 4 && + (!issigned || (signedchars == 1 || hassignedchar)))) + return tp; + bpower = 0; + while ((1<<bpower) < size) + bpower++; /* round size up to power of two */ + size = 1<<bpower; /* size = # bits in an array element */ + tp->escale = bpower; + tp->issigned = issigned; + hasrange = ord_range(tp->indextype, &smin, &smax) && + (smax < 100000); /* don't be confused by giant arrays */ + if (hasrange && + (bitsize = (smax - smin + 1) * size) + <= ((sizeof_integer > 0) ? sizeof_integer : 32)) { + if (bitsize > ((sizeof_short > 0) ? sizeof_short : 16)) { + tp2 = (issigned) ? tp_integer : tp_unsigned; + fullbitsize = ((sizeof_integer > 0) ? sizeof_integer : 32); + } else if (bitsize > ((sizeof_char > 0) ? sizeof_char : 8) || + (issigned && !(signedchars == 1 || hassignedchar))) { + tp2 = (issigned) ? tp_sshort : tp_ushort; + fullbitsize = ((sizeof_short > 0) ? sizeof_short : 16); + } else { + tp2 = (issigned) ? tp_sbyte : tp_ubyte; + fullbitsize = ((sizeof_char > 0) ? sizeof_char : 8); + } + tp->kind = TK_SMALLARRAY; + if (ord_range(tp->indextype, &smin, NULL) && + smin > 0 && smin <= fullbitsize - bitsize) { + tp->smin = makeexpr_val(make_ord(tp->indextype->basetype, smin)); + ex = makeexpr_val(make_ord(tp->indextype->basetype, 0)); + tp->indextype = makesubrangetype(tp->indextype->basetype, ex, + copyexpr(tp->indextype->smax)); + } + } else { + if (!issigned) + tp2 = tp_ubyte; + else if (signedchars == 1 || hassignedchar) + tp2 = tp_sbyte; + else + tp2 = tp_sshort; + } + tp->smax = makeexpr_type(tp->basetype); + tp->basetype = tp2; + return tp; + } +} + + + +Static Type *p_conformant_array(tname, confp) +char *tname; +Meaning ***confp; +{ + int ispacked; + Meaning *mp; + Type *tp, *tp2; + + p_attributes(); + ignore_attributes(); + if (curtok == TOK_PACKED) { + ispacked = 1; + gettok(); + } else + ispacked = 0; + checkkeyword(TOK_VARYING); + if (curtok == TOK_VARYING) { + gettok(); + wneedtok(TOK_LBR); + wexpecttok(TOK_IDENT); + mp = addmeaning(curtoksym, MK_PARAM); + mp->fakeparam = 1; + mp->constqual = 1; + **confp = mp; + *confp = &mp->xnext; + mp->type = tp_integer; + tp2 = maketype(TK_SUBR); + tp2->basetype = tp_integer; + tp2->smin = makeexpr_long(1); + tp2->smax = makeexpr_var(mp); + tp = maketype(TK_STRING); + tp->indextype = tp2; + tp->basetype = tp_char; + tp->structdefd = 1; /* conformant array flag */ + gettok(); + wneedtok(TOK_RBR); + skippasttoken(TOK_OF); + tp->basetype = p_type(NULL); + return tp; + } + if (wneedtok(TOK_ARRAY) && + (modula2 || wneedtok(TOK_LBR))) { + return p_arraydecl(tname, ispacked, confp); + } else { + return tp_integer; + } +} + + + + +/* VAX Pascal: */ +void p_attributes() +{ + Strlist *l1; + + if (modula2) + return; + while (curtok == TOK_LBR) { + implementationmodules = 1; /* auto-detect VAX Pascal */ + do { + gettok(); + if (!wexpecttok(TOK_IDENT)) { + skippasttoken(TOK_RBR); + return; + } + l1 = strlist_append(&attrlist, strupper(curtokbuf)); + l1->value = -1; + gettok(); + if (curtok == TOK_LPAR) { + gettok(); + if (!strcmp(l1->s, "CHECK") || + !strcmp(l1->s, "OPTIMIZE") || + !strcmp(l1->s, "KEY") || + !strcmp(l1->s, "COMMON") || + !strcmp(l1->s, "PSECT") || + !strcmp(l1->s, "EXTERNAL") || + !strcmp(l1->s, "GLOBAL") || + !strcmp(l1->s, "WEAK_EXTERNAL") || + !strcmp(l1->s, "WEAK_GLOBAL")) { + l1->value = (long)stralloc(curtokbuf); + gettok(); + while (curtok == TOK_COMMA) { + gettok(); + gettok(); + } + } else if (!strcmp(l1->s, "INHERIT") || + !strcmp(l1->s, "IDENT") || + !strcmp(l1->s, "ENVIRONMENT")) { + p_expr(NULL); + while (curtok == TOK_COMMA) { + gettok(); + p_expr(NULL); + } + } else { + l1->value = ord_value(p_constant(tp_integer)); + while (curtok == TOK_COMMA) { + gettok(); + p_expr(NULL); + } + } + if (!wneedtok(TOK_RPAR)) { + skippasttotoken(TOK_RPAR, TOK_LBR); + } + } + } while (curtok == TOK_COMMA); + if (!wneedtok(TOK_RBR)) { + skippasttoken(TOK_RBR); + } + } +} + + +void ignore_attributes() +{ + while (attrlist) { + if (strcmp(attrlist->s, "HIDDEN") && + strcmp(attrlist->s, "INHERIT") && + strcmp(attrlist->s, "ENVIRONMENT")) + warning(format_s("Type attribute %s ignored [128]", attrlist->s)); + strlist_eat(&attrlist); + } +} + + +int size_attributes() +{ + int size = -1; + Strlist *l1; + + if ((l1 = strlist_find(attrlist, "BIT")) != NULL) + size = 1; + else if ((l1 = strlist_find(attrlist, "BYTE")) != NULL) + size = 8; + else if ((l1 = strlist_find(attrlist, "WORD")) != NULL) + size = 16; + else if ((l1 = strlist_find(attrlist, "LONG")) != NULL) + size = 32; + else if ((l1 = strlist_find(attrlist, "QUAD")) != NULL) + size = 64; + else if ((l1 = strlist_find(attrlist, "OCTA")) != NULL) + size = 128; + else + return -1; + if (l1->value >= 0) + size *= l1->value; + strlist_delete(&attrlist, l1); + return size; +} + + +void p_mech_spec(doref) +int doref; +{ + if (curtok == TOK_IDENT && doref && + !strcicmp(curtokbuf, "%REF")) { + note("Mechanism specified %REF treated like VAR [107]"); + curtok = TOK_VAR; + return; + } + if (curtok == TOK_IDENT && + (!strcicmp(curtokbuf, "%REF") || + !strcicmp(curtokbuf, "%IMMED") || + !strcicmp(curtokbuf, "%DESCR") || + !strcicmp(curtokbuf, "%STDESCR"))) { + note(format_s("Mechanism specifier %s ignored [108]", curtokbuf)); + gettok(); + } +} + + +Type *p_modula_subrange(basetype) +Type *basetype; +{ + Type *tp; + Value val; + + wneedtok(TOK_LBR); + tp = maketype(TK_SUBR); + tp->smin = p_ord_expr(); + if (basetype) + tp->smin = gentle_cast(tp->smin, basetype); + if (wexpecttok(TOK_DOTS)) { + gettok(); + tp->smax = p_ord_expr(); + if (tp->smax->val.type->kind == TK_REAL && + tp->smax->kind == EK_CONST && + strlen(tp->smax->val.s) == 12 && + strcmp(tp->smax->val.s, "2147483648.0") >= 0 && + strcmp(tp->smax->val.s, "4294967295.0") <= 0) { + tp = tp_unsigned; + } else if (basetype) { + tp->smin = gentle_cast(tp->smin, basetype); + tp->basetype = basetype; + } else { + basetype = ord_type(tp->smin->val.type); + if (basetype->kind == TK_INTEGER) { + val = eval_expr(tp->smin); + if (val.type && val.i >= 0) + basetype = tp_unsigned; + else + basetype = tp_integer; + } + tp->basetype = basetype; + } + } else { + tp = tp_integer; + } + if (!wneedtok(TOK_RBR)) + skippasttotoken(TOK_RBR, TOK_SEMI); + return tp; +} + + +void makefakestruct(tp, tname) +Type *tp; +Meaning *tname; +{ + Symbol *sym; + + if (!tname || blockkind == TOK_IMPORT) + return; + while (tp && (tp->kind == TK_ARRAY || tp->kind == TK_FILE)) + tp = tp->basetype; + if (tp && tp->kind == TK_RECORD && !tp->meaning) { + sym = findsymbol(format_s(name_FAKESTRUCT, tname->name)); + silentalreadydef++; + tp->meaning = addmeaning(sym, MK_TYPE); + silentalreadydef--; + tp->meaning->type = tp; + tp->meaning->refcount++; + declaretype(tp->meaning); + } +} + + +Type *p_type(tname) +Meaning *tname; +{ + Type *tp; + int ispacked = 0; + Meaning **flast; + Meaning *mp; + Strlist *sl; + int num, isfunc, saveind, savenotephase, sizespec; + Expr *ex; + Value val; + static int proctypecount = 0; + + p_attributes(); + sizespec = size_attributes(); + ignore_attributes(); + tp = tp_integer; + if (curtok == TOK_PACKED) { + ispacked = 1; + gettok(); + } + checkkeyword(TOK_VARYING); + if (modula2) + checkkeyword(TOK_POINTER); + switch (curtok) { + + case TOK_RECORD: + gettok(); + savenotephase = notephase; + notephase = 1; + tp = maketype(TK_RECORD); + p_fieldlist(tp, &(tp->fbase), ispacked, tname); + notephase = savenotephase; + if (!wneedtok(TOK_END)) { + skippasttoken(TOK_END); + } + break; + + case TOK_ARRAY: + gettok(); + if (!modula2) { + if (!wneedtok(TOK_LBR)) + break; + } + tp = p_arraydecl(tname ? tname->name : NULL, ispacked, NULL); + makefakestruct(tp, tname); + break; + + case TOK_VARYING: + gettok(); + tp = maketype(TK_STRING); + if (wneedtok(TOK_LBR)) { + ex = p_ord_expr(); + if (!wneedtok(TOK_RBR)) + skippasttoken(TOK_RBR); + } else + ex = makeexpr_long(stringdefault); + if (wneedtok(TOK_OF)) + tp->basetype = p_type(NULL); + else + tp->basetype = tp_char; + val = eval_expr(ex); + if (val.type) { + if (val.i > 255 && val.i > stringceiling) { + note(format_d("Strings longer than %d may have problems [109]", + stringceiling)); + } + if (stringceiling != 255 && + (val.i >= 255 || val.i > stringceiling)) { + freeexpr(ex); + ex = makeexpr_long(stringceiling); + } + } + tp->indextype = makesubrangetype(tp_integer, makeexpr_long(0), ex); + break; + + case TOK_SET: + gettok(); + if (!wneedtok(TOK_OF)) + break; + tp = p_type(NULL); + if (tp == tp_integer || tp == tp_unsigned) + tp = makesubrangetype(tp, makeexpr_long(0), + makeexpr_long(defaultsetsize-1)); + if (tp->kind == TK_ENUM && !tp->meaning && useenum) { + outbasetype(tp, 0); + output(";"); + } + tp = makesettype(tp); + break; + + case TOK_FILE: + gettok(); + if (structfilesflag || + (tname && strlist_cifind(structfiles, tname->name))) + tp = maketype(TK_BIGFILE); + else + tp = maketype(TK_FILE); + if (curtok == TOK_OF) { + gettok(); + tp->basetype = p_type(NULL); + } else { + tp->basetype = tp_abyte; + } + if (tp->basetype->kind == TK_CHAR && charfiletext) { + if (tp->kind == TK_FILE) + tp = tp_text; + else + tp = tp_bigtext; + } else { + if (tp->kind == TK_FILE) { + makefakestruct(tp, tname); + tp = makepointertype(tp); + } + } + break; + + case TOK_PROCEDURE: + case TOK_FUNCTION: + isfunc = (curtok == TOK_FUNCTION); + gettok(); + if (curtok != TOK_LPAR && !isfunc && hasstaticlinks == 1) { + tp = tp_proc; + break; + } + proctypecount++; + mp = addmeaning(findsymbol(format_d("__PROCPTR%d", + proctypecount)), + MK_FUNCTION); + pushctx(mp); + tp = maketype((hasstaticlinks != 0) ? TK_PROCPTR : TK_CPROCPTR); + tp->basetype = p_funcdecl(&isfunc, 1); + tp->fbase = mp; /* (saved, but not currently used) */ + tp->escale = hasstaticlinks; + popctx(); + break; + + case TOK_HAT: + case TOK_ADDR: + case TOK_POINTER: + if (curtok == TOK_POINTER) { + gettok(); + wneedtok(TOK_TO); + if (curtok == TOK_IDENT && !strcmp(curtokbuf, "WORD")) { + tp = tp_anyptr; + gettok(); + break; + } + } else + gettok(); + p_attributes(); + ignore_attributes(); + tp = maketype(TK_POINTER); + if (curtok == TOK_IDENT && + (!curtokmeaning || curtokmeaning->kind != MK_TYPE || + (deferallptrs && curtokmeaning->ctx != curctx && + curtokmeaning->ctx != nullctx))) { + struct ptrdesc *pd; + pd = ALLOC(1, struct ptrdesc, ptrdescs); + pd->sym = curtoksym; + pd->tp = tp; + pd->next = ptrbase; + ptrbase = pd; + tp->basetype = tp_abyte; + tp->smin = makeexpr_name(curtokcase, tp_integer); + anydeferredptrs = 1; + gettok(); + } else { + tp->fbase = (curtok == TOK_IDENT) ? curtokmeaning : NULL; + tp->basetype = p_type(NULL); + tp->fbase = validatedtype(tp->fbase, tp->basetype); + if (!tp->basetype->pointertype) + tp->basetype->pointertype = tp; + } + break; + + case TOK_LPAR: + if (!useenum) + outsection(minorspace); + enum_tname = tname; + tp = maketype(TK_ENUM); + flast = &(tp->fbase); + num = 0; + do { + gettok(); + if (!wexpecttok(TOK_IDENT)) { + skiptotoken(TOK_RPAR); + break; + } + sl = strlist_find(constmacros, curtoksym->name); + mp = addmeaningas(curtoksym, MK_CONST, MK_VARIANT); + mp->val.type = tp; + mp->val.i = num++; + mp->type = tp; + if (sl) { + mp->constdefn = (Expr *)sl->value; + mp->anyvarflag = 1; /* Make sure constant is folded */ + strlist_delete(&constmacros, sl); + if (mp->constdefn->kind == EK_NAME) + strchange(&mp->name, mp->constdefn->val.s); + } else { + if (!useenum) { + output(format_s("#define %s", mp->name)); + mp->isreturn = 1; + out_spaces(constindent, 0, 0, 0); + saveind = outindent; + outindent = cur_column(); + output(format_d("%d\n", mp->val.i)); + outindent = saveind; + } + } + *flast = mp; + flast = &(mp->xnext); + gettok(); + } while (curtok == TOK_COMMA); + if (!wneedtok(TOK_RPAR)) + skippasttoken(TOK_RPAR); + tp->smin = makeexpr_long(0); + tp->smax = makeexpr_long(num-1); + if (!useenum) + outsection(minorspace); + break; + + case TOK_LBR: + tp = p_modula_subrange(NULL); + break; + + case TOK_IDENT: + if (!curtokmeaning) { + undefsym(curtoksym); + tp = tp_integer; + mp = addmeaning(curtoksym, MK_TYPE); + mp->type = tp; + gettok(); + break; + } else if (curtokmeaning == mp_string) { + gettok(); + tp = maketype(TK_STRING); + tp->basetype = tp_char; + if (curtok == TOK_LBR) { + gettok(); + ex = p_ord_expr(); + if (!wneedtok(TOK_RBR)) + skippasttoken(TOK_RBR); + } else { + ex = makeexpr_long(stringdefault); + } + val = eval_expr(ex); + if (val.type && stringceiling != 255 && + (val.i >= 255 || val.i > stringceiling)) { + freeexpr(ex); + ex = makeexpr_long(stringceiling); + } + tp->indextype = makesubrangetype(tp_integer, makeexpr_long(0), ex); + break; + } else if (curtokmeaning->kind == MK_TYPE) { + tp = curtokmeaning->type; + if (sizespec > 0) { + if (ord_type(tp)->kind == TK_INTEGER && sizespec <= 32) { + if (checkconst(tp->smin, 0)) { + if (sizespec == 32) + tp = tp_unsigned; + else + tp = makesubrangetype(tp_unsigned, + makeexpr_long(0), + makeexpr_long((1L << sizespec) - 1)); + } else { + tp = makesubrangetype(tp_integer, + makeexpr_long(- ((1L << (sizespec-1)))), + makeexpr_long((1L << (sizespec-1)) - 1)); + } + sizespec = -1; + } + } + gettok(); + if (curtok == TOK_LBR) { + if (modula2) { + tp = p_modula_subrange(tp); + } else { + gettok(); + ex = p_expr(tp_integer); + note("UCSD size spec ignored; using 'long int' [110]"); + if (ord_type(tp)->kind == TK_INTEGER) + tp = tp_integer; + if (!wneedtok(TOK_RBR)) + skippasttotoken(TOK_RBR, TOK_SEMI); + } + } + if (tp == tp_text && + (structfilesflag || + (tname && strlist_cifind(structfiles, tname->name)))) + tp = tp_bigtext; + break; + } + + /* fall through */ + default: + tp = maketype(TK_SUBR); + tp->smin = p_ord_expr(); + if (curtok == TOK_COLON) + curtok = TOK_DOTS; /* UCSD Pascal */ + if (wexpecttok(TOK_DOTS)) { + gettok(); + tp->smax = p_ord_expr(); + if (tp->smax->val.type->kind == TK_REAL && + tp->smax->kind == EK_CONST && + strlen(tp->smax->val.s) == 12 && + strcmp(tp->smax->val.s, "2147483648.0") >= 0 && + strcmp(tp->smax->val.s, "4294967295.0") <= 0) { + tp = tp_unsigned; + break; + } + tp->basetype = ord_type(tp->smin->val.type); + if (sizespec >= 0) { + long smin, smax; + if (ord_range(tp, &smin, &smax) && + typebits(smin, smax) == sizespec) + sizespec = -1; + } + } else { + tp = tp_integer; + } + break; + } + if (sizespec >= 0) + note(format_d("Don't know how to interpret size = %d bits [111]", sizespec)); + return tp; +} + + + + + +Type *p_funcdecl(isfunc, istype) +int *isfunc, istype; +{ + Meaning *retmp = NULL, *mp, *firstmp, *lastmp, **prevm, **oldprevm; + Type *type, *tp; + enum meaningkind parkind; + int anyvarflag, constflag, volatileflag, num = 0; + Symbol *sym; + Expr *defval; + Token savetok; + Strlist *l1; + + if (*isfunc || modula2) { + sym = findsymbol(format_s(name_RETV, curctx->name)); + retmp = addmeaning(sym, MK_VAR); + retmp->isreturn = 1; + } + type = maketype(TK_FUNCTION); + if (curtok == TOK_LPAR) { + prevm = &type->fbase; + do { + gettok(); + if (curtok == TOK_RPAR) + break; + p_mech_spec(1); + p_attributes(); + checkkeyword(TOK_ANYVAR); + if (curtok == TOK_VAR || curtok == TOK_ANYVAR) { + parkind = MK_VARPARAM; + anyvarflag = (curtok == TOK_ANYVAR); + gettok(); + } else if (curtok == TOK_PROCEDURE || curtok == TOK_FUNCTION) { + savetok = curtok; + gettok(); + wexpecttok(TOK_IDENT); + *prevm = firstmp = addmeaning(curtoksym, MK_PARAM); + prevm = &firstmp->xnext; + firstmp->anyvarflag = 0; + curtok = savetok; /* rearrange tokens to a proc ptr type! */ + firstmp->type = p_type(firstmp); + continue; + } else { + parkind = MK_PARAM; + anyvarflag = 0; + } + oldprevm = prevm; + if (modula2 && istype) { + firstmp = addmeaning(findsymbol(format_d("_A%d", ++num)), parkind); + } else { + wexpecttok(TOK_IDENT); + firstmp = addmeaning(curtoksym, parkind); + gettok(); + } + *prevm = firstmp; + prevm = &firstmp->xnext; + firstmp->isactive = 0; /* nit-picking Turbo compatibility */ + lastmp = firstmp; + while (curtok == TOK_COMMA) { + gettok(); + if (wexpecttok(TOK_IDENT)) { + *prevm = lastmp = addmeaning(curtoksym, parkind); + prevm = &lastmp->xnext; + lastmp->isactive = 0; + } + gettok(); + } + constflag = volatileflag = 0; + defval = NULL; + if (curtok != TOK_COLON && !modula2) { + if (parkind != MK_VARPARAM) + wexpecttok(TOK_COLON); + parkind = MK_VARPARAM; + tp = tp_anyptr; + anyvarflag = 1; + } else { + if (curtok == TOK_COLON) + gettok(); + if (curtok == TOK_IDENT && !curtokmeaning && + !strcicmp(curtokbuf, "UNIV")) { + if (parkind == MK_PARAM) + note("UNIV may not work for non-VAR parameters [112]"); + anyvarflag = 1; + gettok(); + } + p_attributes(); + if ((l1 = strlist_find(attrlist, "READONLY")) != NULL) { + constflag = 1; + strlist_delete(&attrlist, l1); + } + if ((l1 = strlist_find(attrlist, "VOLATILE")) != NULL) { + volatileflag = 1; + strlist_delete(&attrlist, l1); + } + if ((l1 = strlist_find(attrlist, "UNSAFE")) != NULL && + parkind == MK_VARPARAM) { + anyvarflag = 1; + strlist_delete(&attrlist, l1); + } + if ((l1 = strlist_find(attrlist, "REFERENCE")) != NULL) { + note("REFERENCE attribute treated like VAR [107]"); + parkind = MK_VARPARAM; + strlist_delete(&attrlist, l1); + } + checkkeyword(TOK_VARYING); + if (curtok == TOK_IDENT && curtokmeaning == mp_string && + !anyvarflag && parkind == MK_VARPARAM) { + anyvarflag = (varstrings > 0); + tp = tp_str255; + gettok(); + if (curtok == TOK_LBR) { + wexpecttok(TOK_SEMI); + skipparens(); + } + } else if (curtok == TOK_ARRAY || curtok == TOK_PACKED || + curtok == TOK_VARYING) { + prevm = oldprevm; + tp = p_conformant_array(firstmp->name, &prevm); + *prevm = firstmp; + while (*prevm) + prevm = &(*prevm)->xnext; + } else { + tp = p_type(firstmp); + } + if (!varfiles && isfiletype(tp, 0)) + parkind = MK_PARAM; + if (parkind == MK_VARPARAM) + tp = makepointertype(tp); + } + if (curtok == TOK_ASSIGN) { /* check for parameter default */ + gettok(); + p_mech_spec(0); + defval = gentle_cast(p_expr(tp), tp); + if ((tp->kind == TK_STRING || tp->kind == TK_ARRAY) && + tp->basetype->kind == TK_CHAR && + tp->structdefd && /* conformant string */ + defval->val.type->kind == TK_STRING) { + mp = *oldprevm; + if (tp->kind == TK_ARRAY) { + mp->constdefn = makeexpr_long(1); + mp = mp->xnext; + } + mp->constdefn = strmax_func(defval); + } + } + while (firstmp) { + firstmp->type = tp; + firstmp->kind = parkind; /* in case it changed */ + firstmp->isactive = 1; + firstmp->anyvarflag = anyvarflag; + firstmp->constqual = constflag; + firstmp->volatilequal = volatileflag; + if (defval) { + if (firstmp == lastmp) + firstmp->constdefn = defval; + else + firstmp->constdefn = copyexpr(defval); + } + if (parkind == MK_PARAM && + (tp->kind == TK_STRING || + tp->kind == TK_ARRAY || + tp->kind == TK_SET || + ((tp->kind == TK_RECORD || + tp->kind == TK_BIGFILE || + tp->kind == TK_PROCPTR) && copystructs < 2))) { + firstmp->othername = stralloc(format_s(name_COPYPAR, + firstmp->name)); + firstmp->rectype = makepointertype(tp); + } + if (firstmp == lastmp) + break; + firstmp = firstmp->xnext; + } + } while (curtok == TOK_SEMI || curtok == TOK_COMMA); + if (!wneedtok(TOK_RPAR)) + skippasttotoken(TOK_RPAR, TOK_SEMI); + } + if (modula2) { + if (curtok == TOK_COLON) { + *isfunc = 1; + } else { + unaddmeaning(retmp); + } + } + if (*isfunc) { + if (wneedtok(TOK_COLON)) { + retmp->type = type->basetype = p_type(NULL); + switch (retmp->type->kind) { + + case TK_RECORD: + case TK_BIGFILE: + case TK_PROCPTR: + if (copystructs >= 3) + break; + + /* fall through */ + case TK_ARRAY: + case TK_STRING: + case TK_SET: + type->basetype = retmp->type = makepointertype(retmp->type); + retmp->kind = MK_VARPARAM; + retmp->anyvarflag = 0; + retmp->xnext = type->fbase; + type->fbase = retmp; + retmp->refcount++; + break; + + default: + break; + } + } else + retmp->type = type->basetype = tp_integer; + } else + type->basetype = tp_void; + return type; +} + + + + + +Symbol *findlabelsym() +{ + if (curtok == TOK_IDENT && + curtokmeaning && curtokmeaning->kind == MK_LABEL) { +#if 0 + if (curtokmeaning->ctx != curctx && curtokmeaning->val.i != 0) + curtokmeaning->val.i = --nonloclabelcount; +#endif + } else if (curtok == TOK_INTLIT) { + strcpy(curtokcase, curtokbuf); + curtoksym = findsymbol(curtokbuf); + curtokmeaning = curtoksym->mbase; + while (curtokmeaning && !curtokmeaning->isactive) + curtokmeaning = curtokmeaning->snext; + if (!curtokmeaning || curtokmeaning->kind != MK_LABEL) + return NULL; +#if 0 + if (curtokmeaning->ctx != curctx && curtokmeaning->val.i != 0) + if (curtokint == 0) + curtokmeaning->val.i = -1; + else + curtokmeaning->val.i = curtokint; +#endif + } else + return NULL; + return curtoksym; +} + + +void p_labeldecl() +{ + Symbol *sp; + Meaning *mp; + + do { + gettok(); + if (curtok != TOK_IDENT) + wexpecttok(TOK_INTLIT); + sp = findlabelsym(); + mp = addmeaning(curtoksym, MK_LABEL); + mp->val.i = 0; + mp->xnext = addmeaning(findsymbol(format_s(name_LABVAR, + mp->name)), + MK_VAR); + mp->xnext->type = tp_jmp_buf; + mp->xnext->refcount = 0; + gettok(); + } while (curtok == TOK_COMMA); + if (!wneedtok(TOK_SEMI)) + skippasttoken(TOK_SEMI); +} + + + + + +Meaning *findfieldname(sym, variants, nvars) +Symbol *sym; +Meaning **variants; +int *nvars; +{ + Meaning *mp, *mp0; + + mp = variants[*nvars-1]; + while (mp && mp->kind == MK_FIELD) { + if (mp->sym == sym) { + return mp; + } + mp = mp->cnext; + } + while (mp) { + variants[(*nvars)++] = mp->ctx; + mp0 = findfieldname(sym, variants, nvars); + if (mp0) + return mp0; + (*nvars)--; + while (mp->cnext && mp->cnext->ctx == mp->ctx) + mp = mp->cnext; + mp = mp->cnext; + } + return NULL; +} + + + + +Expr *p_constrecord(type, style) +Type *type; +int style; /* 0=HP, 1=Turbo, 2=Oregon+VAX */ +{ + Meaning *mp, *mp0, *variants[20], *newvariants[20], *curfield; + Symbol *sym; + Value val; + Expr *ex, *cex; + int i, j, nvars, newnvars, varcounts[20]; + + if (!wneedtok(style ? TOK_LPAR : TOK_LBR)) + return makeexpr_long(0); + cex = makeexpr(EK_STRUCTCONST, 0); + nvars = 0; + varcounts[0] = 0; + curfield = type->fbase; + for (;;) { + if (style == 2) { + if (curfield) { + mp = curfield; + if (mp->kind == MK_VARIANT || mp->isforward) { + val = p_constant(mp->type); + if (mp->kind == MK_FIELD) { + insertarg(&cex, cex->nargs, makeexpr_val(val)); + mp = mp->cnext; + } + val.type = mp->val.type; + if (!valuesame(val, mp->val)) { + while (mp && !valuesame(val, mp->val)) + mp = mp->cnext; + if (mp) { + note("Attempting to initialize union member other than first [113]"); + curfield = mp->ctx; + } else { + warning("Tag value does not exist in record [129]"); + curfield = NULL; + } + } else + curfield = mp->ctx; + goto ignorefield; + } else { + i = cex->nargs; + insertarg(&cex, i, NULL); + if (mp->isforward && curfield->cnext) + curfield = curfield->cnext->ctx; + else + curfield = curfield->cnext; + } + } else { + warning("Too many fields in record constructor [130]"); + ex = p_expr(NULL); + freeexpr(ex); + goto ignorefield; + } + } else { + if (!wexpecttok(TOK_IDENT)) { + skiptotoken2(TOK_RPAR, TOK_RBR); + break; + } + sym = curtoksym; + gettok(); + if (!wneedtok(TOK_COLON)) { + skiptotoken2(TOK_RPAR, TOK_RBR); + break; + } + newnvars = 1; + newvariants[0] = type->fbase; + mp = findfieldname(sym, newvariants, &newnvars); + if (!mp) { + warning(format_s("Field %s not in record [131]", sym->name)); + ex = p_expr(NULL); /* good enough */ + freeexpr(ex); + goto ignorefield; + } + for (i = 0; i < nvars && i < newnvars; i++) { + if (variants[i] != newvariants[i]) { + warning("Fields are members of incompatible variants [132]"); + ex = p_subconst(mp->type, style); + freeexpr(ex); + goto ignorefield; + } + } + while (nvars < newnvars) { + variants[nvars] = newvariants[nvars]; + if (nvars > 0) { + for (mp0 = variants[nvars-1]; mp0->kind != MK_VARIANT; mp0 = mp0->cnext) ; + if (mp0->ctx != variants[nvars]) + note("Attempting to initialize union member other than first [113]"); + } + i = varcounts[nvars]; + for (mp0 = variants[nvars]; mp0 && mp0->kind == MK_FIELD; mp0 = mp0->cnext) + i++; + nvars++; + varcounts[nvars] = i; + while (cex->nargs < i) + insertarg(&cex, cex->nargs, NULL); + } + i = varcounts[newnvars-1]; + for (mp0 = variants[newnvars-1]; mp0->sym != sym; mp0 = mp0->cnext) + i++; + if (cex->args[i]) + warning(format_s("Two constructors for %s [133]", mp->name)); + } + ex = p_subconst(mp->type, style); + if (ex->kind == EK_CONST && + (ex->val.type->kind == TK_RECORD || + ex->val.type->kind == TK_ARRAY)) + ex = (Expr *)ex->val.i; + cex->args[i] = ex; +ignorefield: + if (curtok == TOK_COMMA || curtok == TOK_SEMI) + gettok(); + else + break; + } + if (!wneedtok(style ? TOK_RPAR : TOK_RBR)) + skippasttoken2(TOK_RPAR, TOK_RBR); + if (style != 2) { + j = 0; + mp = variants[0]; + for (i = 0; i < cex->nargs; i++) { + while (!mp || mp->kind != MK_FIELD) + mp = variants[++j]; + if (!cex->args[i]) { + warning(format_s("No constructor for %s [134]", mp->name)); + cex->args[i] = makeexpr_name("<oops>", mp->type); + } + mp = mp->cnext; + } + } + val.type = type; + val.i = (long)cex; + val.s = NULL; + return makeexpr_val(val); +} + + + + +Expr *p_constarray(type, style) +Type *type; +int style; +{ + Value val; + Expr *ex, *cex; + int nvals, skipped; + long smin, smax; + + if (type->kind == TK_SMALLARRAY) + warning("Small-array constructors not yet implemented [135]"); + if (!wneedtok(style ? TOK_LPAR : TOK_LBR)) + return makeexpr_long(0); + if (type->smin && type->smin->kind == EK_CONST) + skipped = type->smin->val.i; + else + skipped = 0; + cex = NULL; + for (;;) { + if (style && (curtok == TOK_LPAR || curtok == TOK_LBR)) { + ex = p_subconst(type->basetype, style); + nvals = 1; + } else if (curtok == TOK_REPEAT) { + gettok(); + ex = p_expr(type->basetype); + if (ord_range(type->indextype, &smin, &smax)) { + nvals = smax - smin + 1; + if (cex) + nvals -= cex->nargs; + } else { + nvals = 1; + note("REPEAT not translatable for non-constant array bounds [114]"); + } + ex = gentle_cast(ex, type->basetype); + } else { + ex = p_expr(type->basetype); + if (ex->kind == EK_CONST && ex->val.type->kind == TK_STRING && + ex->val.i > 1 && !skipped && style == 0 && !cex && + type->basetype->kind == TK_CHAR && + checkconst(type->indextype->smin, 1)) { + if (!wneedtok(TOK_RBR)) + skippasttoken2(TOK_RBR, TOK_RPAR); + return ex; /* not quite right, but close enough */ + } + if (curtok == TOK_OF) { + ex = gentle_cast(ex, tp_integer); + val = eval_expr(ex); + freeexpr(ex); + if (!val.type) + warning("Expected a constant [127]"); + nvals = val.i; + gettok(); + ex = p_expr(type->basetype); + } else + nvals = 1; + ex = gentle_cast(ex, type->basetype); + } + nvals += skipped; + skipped = 0; + if (ex->kind == EK_CONST && + (ex->val.type->kind == TK_RECORD || + ex->val.type->kind == TK_ARRAY)) + ex = (Expr *)ex->val.i; + if (nvals != 1) { + ex = makeexpr_un(EK_STRUCTOF, type->basetype, ex); + ex->val.i = nvals; + } + if (cex) + insertarg(&cex, cex->nargs, ex); + else + cex = makeexpr_un(EK_STRUCTCONST, type, ex); + if (curtok == TOK_COMMA) + gettok(); + else + break; + } + if (!wneedtok(style ? TOK_RPAR : TOK_RBR)) + skippasttoken2(TOK_RPAR, TOK_RBR); + val.type = type; + val.i = (long)cex; + val.s = NULL; + return makeexpr_val(val); +} + + + + +Expr *p_conststring(type, style) +Type *type; +int style; +{ + Expr *ex; + Token close = (style ? TOK_RPAR : TOK_RBR); + + if (curtok != (style ? TOK_LPAR : TOK_LBR)) + return p_expr(type); + gettok(); + ex = p_expr(tp_integer); /* should handle "OF" and "," for constructors */ + if (curtok == TOK_OF || curtok == TOK_COMMA) { + warning("Multi-element string constructors not yet supported [136]"); + skiptotoken(close); + } + if (!wneedtok(close)) + skippasttoken(close); + return ex; +} + + + + +Expr *p_subconst(type, style) +Type *type; +int style; +{ + Value val; + + if (curtok == TOK_IDENT && curtokmeaning && + curtokmeaning->kind == MK_TYPE) { + if (curtokmeaning->type != type) + warning("Type conflict in constant [137]"); + gettok(); + } + if (curtok == TOK_IDENT && !strcicmp(curtokbuf, "ZERO") && + !curtokmeaning) { /* VAX Pascal foolishness */ + gettok(); + if (type->kind == TK_STRING) + return makeexpr_string(""); + if (type->kind == TK_REAL) + return makeexpr_real("0.0"); + val.type = type; + if (type->kind == TK_RECORD || type->kind == TK_ARRAY || + type->kind == TK_SET) + val.i = (long)makeexpr_un(EK_STRUCTCONST, type, makeexpr_long(0)); + else + val.i = 0; + val.s = NULL; + return makeexpr_val(val); + } + switch (type->kind) { + + case TK_RECORD: + if (curtok == (style ? TOK_LPAR : TOK_LBR)) + return p_constrecord(type, style); + break; + + case TK_SMALLARRAY: + case TK_ARRAY: + if (curtok == (style ? TOK_LPAR : TOK_LBR)) + return p_constarray(type, style); + break; + + case TK_SMALLSET: + case TK_SET: + if (curtok == TOK_LBR) + return p_setfactor(type, 1); + break; + + default: + break; + + } + return gentle_cast(p_expr(type), type); +} + + + +void p_constdecl() +{ + Meaning *mp; + Expr *ex, *ex2; + Type *oldtype; + char savetokcase[sizeof(curtokcase)]; + Symbol *savetoksym; + Strlist *sl; + int i, saveindent, outflag = (blockkind != TOK_IMPORT); + + if (outflag) + outsection(majorspace); + flushcomments(NULL, -1, -1); + gettok(); + oldtype = NULL; + while (curtok == TOK_IDENT) { + strcpy(savetokcase, curtokcase); + savetoksym = curtoksym; + gettok(); + strcpy(curtokcase, savetokcase); /* what a kludge! */ + curtoksym = savetoksym; + if (curtok == TOK_COLON) { /* Turbo Pascal typed constant */ + mp = addmeaning(curtoksym, MK_VAR); + decl_comments(mp); + gettok(); + mp->type = p_type(mp); + if (wneedtok(TOK_EQ)) { + if (mp->kind == MK_VARMAC) { + freeexpr(p_subconst(mp->type, 1)); + note("Initializer ignored for variable with VarMacro [115]"); + } else { + mp->constdefn = p_subconst(mp->type, 1); + if (blockkind == TOK_EXPORT) { + /* nothing */ + } else { + mp->isforward = 1; /* static variable */ + } + } + } + decl_comments(mp); + } else { + sl = strlist_find(constmacros, curtoksym->name); + if (sl) { + mp = addmeaning(curtoksym, MK_VARMAC); + mp->constdefn = (Expr *)sl->value; + strlist_delete(&constmacros, sl); + } else { + mp = addmeaning(curtoksym, MK_CONST); + } + decl_comments(mp); + if (!wexpecttok(TOK_EQ)) { + skippasttoken(TOK_SEMI); + continue; + } + mp->isactive = 0; /* A fine point indeed (see below) */ + gettok(); + if (curtok == TOK_IDENT && + curtokmeaning && curtokmeaning->kind == MK_TYPE && + (curtokmeaning->type->kind == TK_RECORD || + curtokmeaning->type->kind == TK_SMALLARRAY || + curtokmeaning->type->kind == TK_ARRAY)) { + oldtype = curtokmeaning->type; + gettok(); + ex = p_subconst(oldtype, (curtok == TOK_LBR) ? 0 : 2); + } else { + ex = p_expr(NULL); + if (charconsts) + ex = makeexpr_charcast(ex); + } + mp->isactive = 1; /* Re-enable visibility of the new constant */ + if (mp->kind == MK_CONST) + mp->constdefn = ex; + if (ord_type(ex->val.type)->kind == TK_INTEGER) { + i = exprlongness(ex); + if (i > 0) + ex->val.type = tp_integer; + else if (i < 0) + ex->val.type = tp_int; + } + decl_comments(mp); + mp->type = ex->val.type; + mp->val = eval_expr(ex); + if (mp->kind == MK_CONST) { + switch (ex->val.type->kind) { + + case TK_INTEGER: + case TK_BOOLEAN: + case TK_CHAR: + case TK_ENUM: + case TK_SUBR: + case TK_REAL: + if (foldconsts > 0) + mp->anyvarflag = 1; + break; + + case TK_STRING: + if (foldstrconsts > 0) + mp->anyvarflag = 1; + break; + + default: + break; + } + } + flushcomments(&mp->comments, CMT_PRE, -1); + if (ex->val.type->kind == TK_SET) { + mp->val.type = NULL; + if (mp->kind == MK_CONST) { + ex2 = makeexpr(EK_MACARG, 0); + ex2->val.type = ex->val.type; + mp->constdefn = makeexpr_assign(ex2, ex); + } + } else if (mp->kind == MK_CONST && outflag) { + if (ex->val.type != oldtype) { + outsection(minorspace); + oldtype = ex->val.type; + } + switch (ex->val.type->kind) { + + case TK_ARRAY: + case TK_RECORD: + select_outfile(codef); + outsection(minorspace); + if (blockkind == TOK_IMPLEMENT || blockkind == TOK_PROGRAM) + output("static "); + if (useAnyptrMacros == 1 || useconsts == 2) + output("Const "); + else if (useconsts > 0) + output("const "); + outbasetype(mp->type, ODECL_CHARSTAR|ODECL_FREEARRAY); + output(" "); + outdeclarator(mp->type, mp->name, + ODECL_CHARSTAR|ODECL_FREEARRAY); + output(" = {"); + outtrailcomment(mp->comments, -1, declcommentindent); + saveindent = outindent; + moreindent(tabsize); + moreindent(structinitindent); + /* if (mp->val.s) + output(mp->val.s); + else */ + out_expr((Expr *)mp->val.i); + outindent = saveindent; + output("\n};\n"); + outsection(minorspace); + if (blockkind == TOK_EXPORT) { + select_outfile(hdrf); + if (usevextern) + output("vextern "); + if (useAnyptrMacros == 1 || useconsts == 2) + output("Const "); + else if (useconsts > 0) + output("const "); + outbasetype(mp->type, ODECL_CHARSTAR); + output(" "); + outdeclarator(mp->type, mp->name, ODECL_CHARSTAR); + output(";\n"); + } + break; + + default: + if (foldconsts > 0) break; + output(format_s("#define %s", mp->name)); + mp->isreturn = 1; + out_spaces(constindent, 0, 0, 0); + saveindent = outindent; + outindent = cur_column(); + out_expr_factor(ex); + outindent = saveindent; + outtrailcomment(mp->comments, -1, declcommentindent); + break; + + } + } + flushcomments(&mp->comments, -1, -1); + if (mp->kind == MK_VARMAC) + freeexpr(ex); + mp->wasdeclared = 1; + } + if (!wneedtok(TOK_SEMI)) + skippasttoken(TOK_SEMI); + } + if (outflag) + outsection(majorspace); +} + + + + +void declaresubtypes(mp) +Meaning *mp; +{ + Meaning *mp2; + Type *tp; + struct ptrdesc *pd; + + while (mp) { + if (mp->kind == MK_VARIANT) { + declaresubtypes(mp->ctx); + } else { + tp = mp->type; + while (tp->basetype && !tp->meaning && tp->kind != TK_POINTER) + tp = tp->basetype; + if (tp->meaning && !tp->meaning->wasdeclared && + (tp->kind == TK_RECORD || tp->kind == TK_ENUM) && + tp->meaning->ctx && tp->meaning->ctx != nullctx) { + pd = ptrbase; /* Do this now, just in case */ + while (pd) { + if (pd->tp->smin && pd->tp->basetype == tp_abyte) { + pd->tp->smin = NULL; + mp2 = pd->sym->mbase; + while (mp2 && !mp2->isactive) + mp2 = mp2->snext; + if (mp2 && mp2->kind == MK_TYPE) { + pd->tp->basetype = mp2->type; + pd->tp->fbase = mp2; + if (!mp2->type->pointertype) + mp2->type->pointertype = pd->tp; + } + } + pd = pd->next; + } + declaretype(tp->meaning); + } + } + mp = mp->cnext; + } +} + + +void declaretype(mp) +Meaning *mp; +{ + int saveindent, pres; + + switch (mp->type->kind) { + + case TK_RECORD: + case TK_BIGFILE: + if (mp->type->meaning != mp) { + output(format_ss("typedef %s %s;", + mp->type->meaning->name, + mp->name)); + } else { + declaresubtypes(mp->type->fbase); + outsection(minorspace); + if (record_is_union(mp->type)) + output("typedef union "); + else + output("typedef struct "); + output(format_s("%s {\n", format_s(name_STRUCT, mp->name))); + saveindent = outindent; + moreindent(tabsize); + moreindent(structindent); + if (mp->type->kind == TK_BIGFILE) + declarebigfile(mp->type); + else + outfieldlist(mp->type->fbase); + outindent = saveindent; + output(format_s("} %s;", mp->name)); + } + outtrailcomment(mp->comments, -1, declcommentindent); + mp->type->structdefd = 1; + if (mp->type->meaning == mp) + outsection(minorspace); + break; + + case TK_ARRAY: + case TK_SMALLARRAY: + output("typedef "); + if (mp->type->meaning != mp) { + output(format_ss("%s %s", + mp->type->meaning->name, + mp->name)); + } else { + outbasetype(mp->type, 0); + output(" "); + outdeclarator(mp->type, mp->name, 0); + } + output(";"); + outtrailcomment(mp->comments, -1, declcommentindent); + break; + + case TK_ENUM: + if (useenum) { + output("typedef "); + if (mp->type->meaning != mp) + output(mp->type->meaning->name); + else + outbasetype(mp->type, 0); + output(" "); + output(mp->name); + output(";"); + outtrailcomment(mp->comments, -1, + declcommentindent); + } + break; + + default: + pres = preservetypes; + if (mp->type->kind == TK_POINTER && preservepointers >= 0) + pres = preservepointers; + if (mp->type->kind == TK_STRING && preservestrings >= 0) + if (preservestrings == 2) + pres = mp->type->indextype->smax->kind != EK_CONST; + else + pres = preservestrings; + if (pres) { + output("typedef "); + mp->type->preserved = 0; + outbasetype(mp->type, 0); + output(" "); + outdeclarator(mp->type, mp->name, 0); + output(";\n"); + mp->type->preserved = 1; + outtrailcomment(mp->comments, -1, declcommentindent); + } + break; + } + mp->wasdeclared = 1; +} + + + +void declaretypes(outflag) +int outflag; +{ + Meaning *mp; + + for (mp = curctx->cbase; mp; mp = mp->cnext) { + if (mp->kind == MK_TYPE && !mp->wasdeclared) { + if (outflag) { + flushcomments(&mp->comments, CMT_PRE, -1); + declaretype(mp); + flushcomments(&mp->comments, -1, -1); + } + mp->wasdeclared = 1; + } + } +} + + + +void p_typedecl() +{ + Meaning *mp; + int outflag = (blockkind != TOK_IMPORT); + struct ptrdesc *pd; + + if (outflag) + outsection(majorspace); + flushcomments(NULL, -1, -1); + gettok(); + outsection(minorspace); + deferallptrs = 1; + anydeferredptrs = 0; + notephase = 1; + while (curtok == TOK_IDENT) { + mp = addmeaning(curtoksym, MK_TYPE); + mp->type = tp_integer; /* in case of syntax errors */ + gettok(); + decl_comments(mp); + if (curtok == TOK_SEMI) { + mp->type = tp_anyptr; /* Modula-2 opaque type */ + } else { + if (!wneedtok(TOK_EQ)) { + skippasttoken(TOK_SEMI); + continue; + } + mp->type = p_type(mp); + decl_comments(mp); + if (!mp->type->meaning) + mp->type->meaning = mp; + if (mp->type->kind == TK_RECORD || + mp->type->kind == TK_BIGFILE) + mp->type->structdefd = 1; + if (!anydeferredptrs) + declaretypes(outflag); + } + if (!wneedtok(TOK_SEMI)) + skippasttoken(TOK_SEMI); + } + notephase = 0; + deferallptrs = 0; + while (ptrbase) { + pd = ptrbase; + if (pd->tp->smin && pd->tp->basetype == tp_abyte) { + pd->tp->smin = NULL; + mp = pd->sym->mbase; + while (mp && !mp->isactive) + mp = mp->snext; + if (!mp || mp->kind != MK_TYPE) { + warning(format_s("Unsatisfied forward reference to type %s [138]", pd->sym->name)); + } else { + pd->tp->basetype = mp->type; + pd->tp->fbase = mp; + if (!mp->type->pointertype) + mp->type->pointertype = pd->tp; + } + } + ptrbase = ptrbase->next; + FREE(pd); + } + declaretypes(outflag); + outsection(minorspace); + flushcomments(NULL, -1, -1); + if (outflag) + outsection(majorspace); +} + + + + + +Static void nameexternalvar(mp, name) +Meaning *mp; +char *name; +{ + if (!wasaliased) { + if (*externalias && my_strchr(externalias, '%')) + strchange(&mp->name, format_s(externalias, name)); + else + strchange(&mp->name, name); + } +} + + +Static void handlebrackets(mp, skip, wasaliased) +Meaning *mp; +int skip, wasaliased; +{ + Expr *ex; + + checkkeyword(TOK_ORIGIN); + if (curtok == TOK_ORIGIN) { + gettok(); + ex = p_expr(tp_integer); + mp->kind = MK_VARREF; + mp->constdefn = gentle_cast(ex, tp_integer); + } else if (curtok == TOK_LBR) { + gettok(); + ex = p_expr(tp_integer); + if (!wneedtok(TOK_RBR)) + skippasttotoken(TOK_RBR, TOK_SEMI); + if (skip) { + freeexpr(ex); + return; + } + if (ex->kind == EK_CONST && ex->val.type->kind == TK_STRING) { + nameexternalvar(mp, ex->val.s); + mp->isfunction = 1; /* make it extern */ + } else { + note(format_s("Absolute-addressed variable %s was generated [116]", mp->name)); + mp->kind = MK_VARREF; + mp->constdefn = gentle_cast(ex, tp_integer); + } + } +} + + + +Static void handleabsolute(mp, skip) +Meaning *mp; +int skip; +{ + Expr *ex; + Value val; + long i; + + checkkeyword(TOK_ABSOLUTE); + if (curtok == TOK_ABSOLUTE) { + gettok(); + if (skip) { + freeexpr(p_expr(tp_integer)); + if (curtok == TOK_COLON) { + gettok(); + freeexpr(p_expr(tp_integer)); + } + return; + } + note(format_s("Absolute-addressed variable %s was generated [116]", mp->name)); + mp->kind = MK_VARREF; + if (curtok == TOK_IDENT && + curtokmeaning && (curtokmeaning->kind != MK_CONST || + ord_type(curtokmeaning->type)->kind != TK_INTEGER)) { + mp->constdefn = makeexpr_addr(p_expr(NULL)); + mp->isfunction = 1; /* make it extern */ + } else { + ex = gentle_cast(p_expr(tp_integer), tp_integer); + if (curtok == TOK_COLON) { + val = eval_expr(ex); + if (!val.type) + warning("Expected a constant [127]"); + i = val.i & 0xffff; + gettok(); + val = p_constant(tp_integer); + i = (i<<16) | (val.i & 0xffff); /* as good a notation as any! */ + ex = makeexpr_long(i); + insertarg(&ex, 0, makeexpr_name("%#lx", tp_integer)); + } + mp->constdefn = ex; + } + } +} + + + +void setupfilevar(mp) +Meaning *mp; +{ + if (mp->kind != MK_VARMAC) { + if (isfiletype(mp->type, 0)) { + if (storefilenames && *name_FNVAR) + mp->namedfile = 1; + if (checkvarinlists(bufferedfiles, unbufferedfiles, 0, mp)) + mp->bufferedfile = 1; + } else if (isfiletype(mp->type, 1)) { + mp->namedfile = 1; + mp->bufferedfile = 1; + } + } +} + + + +Meaning *validatedtype(dtype, type) +Meaning *dtype; +Type *type; +{ + if (dtype && + (!type->preserved || !type->meaning || + dtype->kind != MK_TYPE || dtype->type != type || + type->meaning == dtype)) + return NULL; + return dtype; +} + + +void p_vardecl() +{ + Meaning *firstmp, *lastmp, *dtype; + Type *tp; + int aliasflag, volatileflag, constflag, staticflag, globalflag, externflag; + Strlist *l1; + Expr *initexpr; + + gettok(); + notephase = 1; + while (curtok == TOK_IDENT) { + firstmp = lastmp = addmeaning(curtoksym, MK_VAR); + lastmp->type = tp_integer; /* in case of syntax errors */ + aliasflag = wasaliased; + gettok(); + handlebrackets(lastmp, (lastmp->kind != MK_VAR), aliasflag); + decl_comments(lastmp); + while (curtok == TOK_COMMA) { + gettok(); + if (wexpecttok(TOK_IDENT)) { + lastmp = addmeaning(curtoksym, MK_VAR); + lastmp->type = tp_integer; + aliasflag = wasaliased; + gettok(); + handlebrackets(lastmp, (lastmp->kind != MK_VAR), aliasflag); + decl_comments(lastmp); + } + } + if (!wneedtok(TOK_COLON)) { + skippasttoken(TOK_SEMI); + continue; + } + p_attributes(); + volatileflag = constflag = staticflag = globalflag = externflag = 0; + if ((l1 = strlist_find(attrlist, "READONLY")) != NULL) { + constflag = 1; + strlist_delete(&attrlist, l1); + } + if ((l1 = strlist_find(attrlist, "VOLATILE")) != NULL) { + volatileflag = 1; + strlist_delete(&attrlist, l1); + } + if ((l1 = strlist_find(attrlist, "STATIC")) != NULL) { + staticflag = 1; + strlist_delete(&attrlist, l1); + } + if ((l1 = strlist_find(attrlist, "AUTOMATIC")) != NULL) { + /* This is the default! */ + strlist_delete(&attrlist, l1); + } + if ((l1 = strlist_find(attrlist, "AT")) != NULL) { + note(format_s("Absolute-addressed variable %s was generated [116]", lastmp->name)); + lastmp->kind = MK_VARREF; + lastmp->constdefn = makeexpr_long(l1->value); + strlist_delete(&attrlist, l1); + } + if ((l1 = strlist_find(attrlist, "GLOBAL")) != NULL || + (l1 = strlist_find(attrlist, "WEAK_GLOBAL")) != NULL) { + globalflag = 1; + if (l1->value != -1) + nameexternalvar(lastmp, (char *)l1->value); + if (l1->s[0] != 'W') + strlist_delete(&attrlist, l1); + } + if ((l1 = strlist_find(attrlist, "EXTERNAL")) != NULL || + (l1 = strlist_find(attrlist, "WEAK_EXTERNAL")) != NULL) { + externflag = 1; + if (l1->value != -1) + nameexternalvar(lastmp, (char *)l1->value); + if (l1->s[0] != 'W') + strlist_delete(&attrlist, l1); + } + dtype = (curtok == TOK_IDENT) ? curtokmeaning : NULL; + tp = p_type(firstmp); + decl_comments(lastmp); + handleabsolute(lastmp, (lastmp->kind != MK_VAR)); + initexpr = NULL; + if (curtok == TOK_ASSIGN) { /* VAX Pascal initializer */ + gettok(); + initexpr = p_subconst(tp, 2); + if (lastmp->kind == MK_VARMAC) { + freeexpr(initexpr); + initexpr = NULL; + note("Initializer ignored for variable with VarMacro [115]"); + } + } + dtype = validatedtype(dtype, tp); + for (;;) { + if (firstmp->kind == MK_VARREF) { + firstmp->type = makepointertype(tp); + firstmp->constdefn = makeexpr_cast(firstmp->constdefn, firstmp->type); + } else { + firstmp->type = tp; + setupfilevar(firstmp); + if (initexpr) { + if (firstmp == lastmp) + firstmp->constdefn = initexpr; + else + firstmp->constdefn = copyexpr(initexpr); + } + } + firstmp->dtype = dtype; + firstmp->volatilequal = volatileflag; + firstmp->constqual = constflag; + firstmp->isforward |= staticflag; + firstmp->isfunction |= externflag; + firstmp->exported |= globalflag; + if (globalflag && (curctx->kind != MK_MODULE || mainlocals)) + declarevar(firstmp, -1); + if (firstmp == lastmp) + break; + firstmp = firstmp->cnext; + } + if (!wneedtok(TOK_SEMI)) + skippasttoken(TOK_SEMI); + } + notephase = 0; +} + + + + +void p_valuedecl() +{ + Meaning *mp; + + gettok(); + while (curtok == TOK_IDENT) { + if (!curtokmeaning || + curtokmeaning->kind != MK_VAR) { + warning(format_s("Initializer ignored for variable %s [139]", + curtokbuf)); + skippasttoken(TOK_SEMI); + } else { + mp = curtokmeaning; + gettok(); + if (curtok == TOK_DOT || curtok == TOK_LBR) { + note("Partial structure initialization not supported [117]"); + skippasttoken(TOK_SEMI); + } else if (wneedtok(TOK_ASSIGN)) { + mp->constdefn = p_subconst(mp->type, 2); + if (!wneedtok(TOK_SEMI)) + skippasttoken(TOK_SEMI); + } else + skippasttoken(TOK_SEMI); + } + } +} + + + + + + + +/* Make a temporary variable that must be freed manually (or at the end of + the current function by default) */ + +Meaning *maketempvar(type, name) +Type *type; +char *name; +{ + struct tempvarlist *tv, **tvp; + Symbol *sym; + Meaning *mp; + char *fullname; + + tvp = &tempvars; /* find a freed but allocated temporary */ + while ((tv = *tvp) && (!similartypes(tv->tvar->type, type) || + tv->tvar->refcount == 0 || + strcmp(tv->tvar->val.s, name))) + tvp = &(tv->next); + if (!tv) { + tvp = &tempvars; /* take over a now-cancelled temporary */ + while ((tv = *tvp) && (tv->tvar->refcount > 0 || + strcmp(tv->tvar->val.s, name))) + tvp = &(tv->next); + } + if (tv) { + tv->tvar->type = type; + *tvp = tv->next; + mp = tv->tvar; + FREE(tv); + mp->refcount++; + if (debug>1) { fprintf(outf,"maketempvar revives %s\n", mp->name); } + } else { + tempvarcount = 0; /***/ /* experimental... */ + for (;;) { + if (tempvarcount) + fullname = format_s(name, format_d("%d", tempvarcount)); + else + fullname = format_s(name, ""); + ++tempvarcount; + sym = findsymbol(fullname); + mp = sym->mbase; + while (mp && !mp->isactive) + mp = mp->snext; + if (!mp) + break; + if (debug>1) { fprintf(outf,"maketempvar rejects %s\n", fullname); } + } + mp = addmeaning(sym, MK_VAR); + mp->istemporary = 1; + mp->type = type; + mp->refcount = 1; + mp->val.s = stralloc(name); + if (debug>1) { fprintf(outf,"maketempvar creates %s\n", mp->name); } + } + return mp; +} + + + +/* Make a temporary variable that will be freed at the end of this statement + (rather than at the end of the function) by default */ + +Meaning *makestmttempvar(type, name) +Type *type; +char *name; +{ + struct tempvarlist *tv; + Meaning *tvar; + + tvar = maketempvar(type, name); + tv = ALLOC(1, struct tempvarlist, tempvars); + tv->tvar = tvar; + tv->active = 1; + tv->next = stmttempvars; + stmttempvars = tv; + return tvar; +} + + + +Meaning *markstmttemps() +{ + return (stmttempvars) ? stmttempvars->tvar : NULL; +} + + +void freestmttemps(mark) +Meaning *mark; +{ + struct tempvarlist *tv; + + while ((tv = stmttempvars) && tv->tvar != mark) { + if (tv->active) + freetempvar(tv->tvar); + stmttempvars = tv->next; + FREE(tv); + } +} + + + +/* This temporary variable is no longer used */ + +void freetempvar(tvar) +Meaning *tvar; +{ + struct tempvarlist *tv; + + if (debug>1) { fprintf(outf,"freetempvar frees %s\n", tvar->name); } + tv = stmttempvars; + while (tv && tv->tvar != tvar) + tv = tv->next; + if (tv) + tv->active = 0; + tv = ALLOC(1, struct tempvarlist, tempvars); + tv->tvar = tvar; + tv->next = tempvars; + tempvars = tv; +} + + + +/* The code that used this temporary variable has been deleted */ + +void canceltempvar(tvar) +Meaning *tvar; +{ + if (debug>1) { fprintf(outf,"canceltempvar cancels %s\n", tvar->name); } + tvar->refcount--; + freetempvar(tvar); +} + + + + + + + + +/* End. */ + + diff --git a/MultiSource/Benchmarks/MallocBench/p2c/dir.c b/MultiSource/Benchmarks/MallocBench/p2c/dir.c new file mode 100644 index 00000000..82ec98ca --- /dev/null +++ b/MultiSource/Benchmarks/MallocBench/p2c/dir.c @@ -0,0 +1,257 @@ +/* "p2c", a Pascal to C translator. + Copyright (C) 1989, 1990, 1991 Free Software Foundation. + Author's address: daveg@csvax.caltech.edu; 256-80 Caltech/Pasadena CA 91125. + +This program is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation (any version). + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; see the file COPYING. If not, write to +the Free Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ + + + +#define define_parameters +#define PROTO_DIR_C +#include "trans.h" + + +/* This file is user-modifiable. It is the "directory" of C functions + for compiling in-line various Pascal library routines. */ + + + +extern void setup_module_hp(); +extern void setup_module_cit(); +extern void setup_module_tanner(); + + + + +/* This function is called once when p2c is starting up, before + the p2crc file has been read. +*/ + +void init_dir() +{ + + +} + + + + + +/* This function is called once when p2c is starting up, after + the p2crc file has been read. +*/ + +void setup_dir() +{ + + +} + + + + + +/* This procedure is called after reading the import text for a module, + where "name" is the module name, in upper-case letters. Calls to + "addmeaning", "makestandardfunc", etc. will annotate the context of + the module. Note that this will be called if the module is searched, + even if it is never actually imported. +*/ + +#if 0 +Static void _setup(name, defn) +char *name; +int defn; +{ + /* this is a dummy procedure which may be called by setup_module */ +} +#endif + +#define _setup(a,b) + +void setup_module(name, defn) +char *name; +int defn; +{ + if (!strcicmp(name, "SYSTEM")) + decl_builtins(); +#ifdef CUST1 + CUST1(name, defn); +#endif +#ifdef CUST2 + CUST2(name, defn); +#endif +#ifdef CUST3 + CUST3(name, defn); +#endif +#ifdef CUST4 + CUST4(name, defn); +#endif +#ifdef CUST5 + CUST5(name, defn); +#endif +} + + + + + +/* This procedure is called once after the p2crc file has been + read and the built-in parameters have been "fixed". It should + check ranges and add defaults for any newly introduced parameters + in the "rctable" (see "trans.h"). +*/ + +void fix_parameters() +{ + + +} + + + + + +/* This function is called during a traversal of the tree of statements for + a procedure. Ordinarily it returns its argument; it may instead return + an arbitrary other statement or sequence of statements, which will then + be spliced in to replace the original one. It may return NULL to delete + the statement altogether. +*/ + +Stmt *fix_statement(sp) +Stmt *sp; +{ + return sp; +} + + + + + +/* This is the analogous function for expression traversals. It is + called after the arguments have been (recursively) fixed and all + built-in fixes have been performed. +*/ + +Expr *fix_expression(ex, env) +Expr *ex; +int env; +{ + return ex; +} + + + + + +/* This procedure is called when fixing an expression of type + EK_BICALL. It is called before the arguments are fixed. If + it recognizes the BICALL, it should fix the arguments, then + return a (possibly modified) fixed expression, which may or + may not be a BICALL. That expression will then be sent to + fix_expression() as usual, but other standard fixes will not + automatically be performed on it. If the BICALL is not + recognized, the function should return NULL. +*/ + +Expr *fix_bicall(ex, env) +Expr *ex; +int env; +{ + return NULL; +} + + + + + +/* This function returns nonzero if the built-in function "name" + should be written "if (f(x))" rather than "if (f(x) != 0)" + when used as a boolean. The call does *not* necessarily have + to return a 1-or-0 value. +*/ + +int boolean_bicall(name) +char *name; +{ + return (!strcmp(name, "strcmp") || + !strcmp(name, "strncmp") || + !strcmp(name, "memcmp") || + !strcmp(name, "feof") || + !strcmp(name, "feoln")); +} + + + + + +/* The function "name" promises not to change certain of its + VAR-style parameters. For each of arguments i = 0 through 15, + if bit 1<<i of the return value of this function is set, and + the i'th parameter is a pointer to an object, then the function + guarantees not to change that object. +*/ + +unsigned int safemask_bicall(name) +char *name; +{ + Symbol *sp; + + sp = findsymbol_opt(name); + if (sp) { + if (sp->flags & (STRUCTF|STRLAPF)) + return ~1; + if (sp->flags & (NOSIDEEFF|DETERMF)) + return ~0; + } + if (!strcmp(name, "fwrite") || + !strcmp(name, "memchr")) + return 1; + if (!strcmp(name, "memcpy") || + !strcmp(name, "memmove")) + return 2; + if (!strcmp(name, "memcmp")) + return 3; + if (!strcmp(name, "sprintf") || + !strcmp(name, "fprintf")) + return ~1; + if (!strcmp(name, "printf")) + return ~0; + return 0; +} + + + + + +/* The function "name" has side effects that could affect other variables + in the program besides those that are explicitly mentioned. +*/ + +int sideeffects_bicall(name) +char *name; +{ + return 0; +} + + + + + + +/* End. */ + + + diff --git a/MultiSource/Benchmarks/MallocBench/p2c/expr.c b/MultiSource/Benchmarks/MallocBench/p2c/expr.c new file mode 100644 index 00000000..4aabd75c --- /dev/null +++ b/MultiSource/Benchmarks/MallocBench/p2c/expr.c @@ -0,0 +1,5574 @@ +/* "p2c", a Pascal to C translator. + Copyright (C) 1989, 1990, 1991 Free Software Foundation. + Author's address: daveg@csvax.caltech.edu; 256-80 Caltech/Pasadena CA 91125. + +This program is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation (any version). + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; see the file COPYING. If not, write to +the Free Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ + + + +#define PROTO_EXPR_C +#include "trans.h" + + + + + +void free_value(val) +Value *val; +{ + if (!val || !val->type) + return; + switch (val->type->kind) { + + case TK_STRING: + case TK_REAL: + case TK_ARRAY: + case TK_RECORD: + case TK_SET: + if (val->s) + FREE(val->s); + break; + + default: + break; + } +} + + +Value copyvalue(val) +Value val; +{ + char *cp; + + switch (val.type->kind) { + + case TK_STRING: + case TK_SET: + if (val.s) { + cp = ALLOC(val.i+1, char, literals); + memcpy(cp, val.s, val.i); + cp[val.i] = 0; + val.s = cp; + } + break; + + case TK_REAL: + case TK_ARRAY: + case TK_RECORD: + if (val.s) + val.s = stralloc(val.s); + break; + + default: + break; + } + return val; +} + + +int valuesame(a, b) +Value a, b; +{ + if (a.type != b.type) + return 0; + switch (a.type->kind) { + + case TK_INTEGER: + case TK_CHAR: + case TK_BOOLEAN: + case TK_ENUM: + case TK_SMALLSET: + case TK_SMALLARRAY: + return (a.i == b.i); + + case TK_STRING: + case TK_SET: + return (a.i == b.i && !memcmp(a.s, b.s, a.i)); + + case TK_REAL: + case TK_ARRAY: + case TK_RECORD: + return (!strcmp(a.s, b.s)); + + default: + return 1; + } +} + + + +char *value_name(val, intfmt, islong) +Value val; +char *intfmt; +int islong; +{ + Meaning *mp; + Type *type = val.type; + + if (type->kind == TK_SUBR) + type = type->basetype; + switch (type->kind) { + + case TK_INTEGER: + case TK_SMALLSET: + case TK_SMALLARRAY: + if (!intfmt) + intfmt = "%ld"; + if (*intfmt == '\'') { + if (val.i >= -'~' && val.i <= -' ') { + intfmt = format_s("-%s", intfmt); + val.i = -val.i; + } + if (val.i < ' ' || val.i > '~' || islong) + intfmt = "%ld"; + } + if (islong) + intfmt = format_s("%sL", intfmt); + return format_d(intfmt, val.i); + + case TK_REAL: + return val.s; + + case TK_ARRAY: /* obsolete */ + case TK_RECORD: /* obsolete */ + return val.s; + + case TK_STRING: + return makeCstring(val.s, val.i); + + case TK_BOOLEAN: + if (!intfmt) + if (val.i == 1 && *name_TRUE && + strcmp(name_TRUE, "1") && !islong) + intfmt = name_TRUE; + else if (val.i == 0 && *name_FALSE && + strcmp(name_FALSE, "0") && !islong) + intfmt = name_FALSE; + else + intfmt = "%ld"; + if (islong) + intfmt = format_s("%sL", intfmt); + return format_d(intfmt, val.i); + + case TK_CHAR: + if (islong) + return format_d("%ldL", val.i); + else if ((val.i < 0 || val.i > 127) && highcharints) + return format_d("%ld", val.i); + else + return makeCchar(val.i); + + case TK_POINTER: + return (*name_NULL) ? name_NULL : "NULL"; + + case TK_ENUM: + mp = val.type->fbase; + while (mp && mp->val.i != val.i) + mp = mp->xnext; + if (!mp) { + intwarning("value_name", "bad enum value [152]"); + return format_d("%ld", val.i); + } + return mp->name; + + default: + intwarning("value_name", format_s("bad type for constant: %s [153]", + typekindname(type->kind))); + return "<spam>"; + } +} + + + + +Value value_cast(val, type) +Value val; +Type *type; +{ + char buf[20]; + + if (type->kind == TK_SUBR) + type = type->basetype; + if (val.type == type) + return val; + if (type && val.type) { + switch (type->kind) { + + case TK_REAL: + if (ord_type(val.type)->kind == TK_INTEGER) { + sprintf(buf, "%d.0", val.i); + val.s = stralloc(buf); + val.type = tp_real; + return val; + } + break; + + case TK_CHAR: + if (val.type->kind == TK_STRING) { + if (val.i != 1) + if (val.i > 0) + warning("Char constant with more than one character [154]"); + else + warning("Empty char constant [155]"); + val.i = val.s[0] & 0xff; + val.s = NULL; + val.type = tp_char; + return val; + } + + case TK_POINTER: + if (val.type == tp_anyptr && castnull != 1) { + val.type = type; + return val; + } + + default: + break; + } + } + val.type = NULL; + return val; +} + + + +Type *ord_type(tp) +Type *tp; +{ + if (!tp) { + warning("Expected a constant [127]"); + return tp_integer; + } + switch (tp->kind) { + + case TK_SUBR: + tp = tp->basetype; + break; + + case TK_STRING: + if (!CHECKORDEXPR(tp->indextype->smax, 1)) + tp = tp_char; + break; + + default: + break; + + } + return tp; +} + + + +int long_type(tp) +Type *tp; +{ + switch (tp->kind) { + + case TK_INTEGER: + return (tp != tp_int && tp != tp_uint && tp != tp_sint); + + case TK_SUBR: + return (findbasetype(tp, ODECL_NOPRES) == tp_integer); + + default: + return 0; + } +} + + + +Value make_ord(type, i) +Type *type; +long i; +{ + Value val; + + if (type->kind == TK_ENUM) + type = findbasetype(type, ODECL_NOPRES); + if (type->kind == TK_SUBR) + type = type->basetype; + val.type = type; + val.i = i; + val.s = NULL; + return val; +} + + + +long ord_value(val) +Value val; +{ + switch (val.type->kind) { + + case TK_INTEGER: + case TK_ENUM: + case TK_CHAR: + case TK_BOOLEAN: + return val.i; + + case TK_STRING: + if (val.i == 1) + return val.s[0] & 0xff; + + /* fall through */ + default: + warning("Expected an ordinal type [156]"); + return 0; + } +} + + + +void ord_range_expr(type, smin, smax) +Type *type; +Expr **smin, **smax; +{ + if (!type) { + warning("Expected a constant [127]"); + type = tp_integer; + } + if (type->kind == TK_STRING) + type = tp_char; + switch (type->kind) { + + case TK_SUBR: + case TK_INTEGER: + case TK_ENUM: + case TK_CHAR: + case TK_BOOLEAN: + if (smin) *smin = type->smin; + if (smax) *smax = type->smax; + break; + + default: + warning("Expected an ordinal type [156]"); + if (smin) *smin = makeexpr_long(0); + if (smax) *smax = makeexpr_long(1); + break; + } +} + + +int ord_range(type, smin, smax) +Type *type; +long *smin, *smax; +{ + Expr *emin, *emax; + Value vmin, vmax; + + ord_range_expr(type, &emin, &emax); + if (smin) { + vmin = eval_expr(emin); + if (!vmin.type) + return 0; + } + if (smax) { + vmax = eval_expr(emax); + if (!vmax.type) + return 0; + } + if (smin) *smin = ord_value(vmin); + if (smax) *smax = ord_value(vmax); + return 1; +} + + + + + + + +void freeexpr(ex) +register Expr *ex; +{ + register int i; + + if (ex) { + for (i = 0; i < ex->nargs; i++) + freeexpr(ex->args[i]); + switch (ex->kind) { + + case EK_CONST: + case EK_LONGCONST: + free_value(&ex->val); + break; + + case EK_DOT: + case EK_NAME: + case EK_BICALL: + if (ex->val.s) + FREE(ex->val.s); + break; + + default: + break; + } + FREE(ex); + } +} + + + + +Expr *makeexpr(kind, n) +enum exprkind kind; +int n; +{ + Expr *ex; + + ex = ALLOCV(sizeof(Expr) + (n-1)*sizeof(Expr *), Expr, exprs); + ex->val.i = 0; + ex->val.s = NULL; + ex->kind = kind; + ex->nargs = n; + return ex; +} + + +Expr *makeexpr_un(kind, type, arg1) +enum exprkind kind; +Type *type; +Expr *arg1; +{ + Expr *ex; + + ex = makeexpr(kind, 1); + ex->val.type = type; + ex->args[0] = arg1; + if (debug>2) { fprintf(outf,"makeexpr_un returns "); dumpexpr(ex); fprintf(outf,"\n"); } + return ex; +} + + +Expr *makeexpr_bin(kind, type, arg1, arg2) +enum exprkind kind; +Type *type; +Expr *arg1, *arg2; +{ + Expr *ex; + + ex = makeexpr(kind, 2); + ex->val.type = type; + ex->args[0] = arg1; + ex->args[1] = arg2; + if (debug>2) { fprintf(outf,"makeexpr_bin returns "); dumpexpr(ex); fprintf(outf,"\n"); } + return ex; +} + + + +Expr *makeexpr_val(val) +Value val; +{ + Expr *ex; + + if (val.type->kind == TK_INTEGER && + (val.i < -32767 || val.i > 32767) && + sizeof_int < 32) + ex = makeexpr(EK_LONGCONST, 0); + else + ex = makeexpr(EK_CONST, 0); + ex->val = val; + if (debug>2) { fprintf(outf,"makeexpr_val returns "); dumpexpr(ex); fprintf(outf,"\n"); } + return ex; +} + + + +Expr *makeexpr_char(c) +int c; +{ + return makeexpr_val(make_ord(tp_char, c)); +} + + +Expr *makeexpr_long(i) +long i; +{ + return makeexpr_val(make_ord(tp_integer, i)); +} + + +Expr *makeexpr_real(r) +char *r; +{ + Value val; + + val.type = tp_real; + val.i = 0; + val.s = stralloc(r); + return makeexpr_val(val); +} + + +Expr *makeexpr_lstring(msg, len) +char *msg; +int len; +{ + Value val; + + val.type = tp_str255; + val.i = len; + val.s = ALLOC(len+1, char, literals); + memcpy(val.s, msg, len); + val.s[len] = 0; + return makeexpr_val(val); +} + + +Expr *makeexpr_string(msg) +char *msg; +{ + Value val; + + val.type = tp_str255; + val.i = strlen(msg); + val.s = stralloc(msg); + return makeexpr_val(val); +} + + +int checkstring(ex, msg) +Expr *ex; +char *msg; +{ + if (!ex || ex->val.type->kind != TK_STRING || ex->kind != EK_CONST) + return 0; + if (ex->val.i != strlen(msg)) + return 0; + return memcmp(ex->val.s, msg, ex->val.i) == 0; +} + + + +Expr *makeexpr_var(mp) +Meaning *mp; +{ + Expr *ex; + + ex = makeexpr(EK_VAR, 0); + ex->val.i = (long) mp; + ex->val.type = mp->type; + if (debug>2) { fprintf(outf,"makeexpr_var returns "); dumpexpr(ex); fprintf(outf,"\n"); } + return ex; +} + + + +Expr *makeexpr_name(name, type) +char *name; +Type *type; +{ + Expr *ex; + + ex = makeexpr(EK_NAME, 0); + ex->val.s = stralloc(name); + ex->val.type = type; + if (debug>2) { fprintf(outf,"makeexpr_name returns "); dumpexpr(ex); fprintf(outf,"\n"); } + return ex; +} + + + +Expr *makeexpr_setbits() +{ + if (*name_SETBITS) + return makeexpr_name(name_SETBITS, tp_integer); + else + return makeexpr_long(setbits); +} + + + +/* Note: BICALL's to the following functions should obey the ANSI standard. */ +/* Non-ANSI transformations occur while writing the expression. */ +/* char *sprintf(buf, fmt, ...) [returns buf] */ +/* void *memcpy(dest, src, size) [returns dest] */ + +Expr *makeexpr_bicall_0(name, type) +char *name; +Type *type; +{ + Expr *ex; + + if (!name || !*name) { + intwarning("makeexpr_bicall_0", "Required name of built-in procedure is missing [157]"); + name = "MissingProc"; + } + ex = makeexpr(EK_BICALL, 0); + ex->val.s = stralloc(name); + ex->val.type = type; + if (debug>2) { fprintf(outf,"makeexpr_bicall returns "); dumpexpr(ex); fprintf(outf,"\n"); } + return ex; +} + + +Expr *makeexpr_bicall_1(name, type, arg1) +char *name; +Type *type; +Expr *arg1; +{ + Expr *ex; + + if (!name || !*name) { + intwarning("makeexpr_bicall_1", "Required name of built-in procedure is missing [157]"); + name = "MissingProc"; + } + ex = makeexpr(EK_BICALL, 1); + ex->val.s = stralloc(name); + ex->val.type = type; + ex->args[0] = arg1; + if (debug>2) { fprintf(outf,"makeexpr_bicall returns "); dumpexpr(ex); fprintf(outf,"\n"); } + return ex; +} + + +Expr *makeexpr_bicall_2(name, type, arg1, arg2) +char *name; +Type *type; +Expr *arg1, *arg2; +{ + Expr *ex; + + if (!name || !*name) { + intwarning("makeexpr_bicall_2", "Required name of built-in procedure is missing [157]"); + name = "MissingProc"; + } + ex = makeexpr(EK_BICALL, 2); + if (!strcmp(name, "~SETIO")) + name = (iocheck_flag) ? "~~SETIO" : name_SETIO; + ex->val.s = stralloc(name); + ex->val.type = type; + ex->args[0] = arg1; + ex->args[1] = arg2; + if (debug>2) { fprintf(outf,"makeexpr_bicall returns "); dumpexpr(ex); fprintf(outf,"\n"); } + return ex; +} + + +Expr *makeexpr_bicall_3(name, type, arg1, arg2, arg3) +char *name; +Type *type; +Expr *arg1, *arg2, *arg3; +{ + Expr *ex; + + if (!name || !*name) { + intwarning("makeexpr_bicall_3", "Required name of built-in procedure is missing [157]"); + name = "MissingProc"; + } + ex = makeexpr(EK_BICALL, 3); + ex->val.s = stralloc(name); + ex->val.type = type; + ex->args[0] = arg1; + ex->args[1] = arg2; + ex->args[2] = arg3; + if (debug>2) { fprintf(outf,"makeexpr_bicall returns "); dumpexpr(ex); fprintf(outf,"\n"); } + return ex; +} + + +Expr *makeexpr_bicall_4(name, type, arg1, arg2, arg3, arg4) +char *name; +Type *type; +Expr *arg1, *arg2, *arg3, *arg4; +{ + Expr *ex; + + if (!name || !*name) { + intwarning("makeexpr_bicall_4", "Required name of built-in procedure is missing [157]"); + name = "MissingProc"; + } + ex = makeexpr(EK_BICALL, 4); + if (!strcmp(name, "~CHKIO")) + name = (iocheck_flag) ? "~~CHKIO" : name_CHKIO; + ex->val.s = stralloc(name); + ex->val.type = type; + ex->args[0] = arg1; + ex->args[1] = arg2; + ex->args[2] = arg3; + ex->args[3] = arg4; + if (debug>2) { fprintf(outf,"makeexpr_bicall returns "); dumpexpr(ex); fprintf(outf,"\n"); } + return ex; +} + + +Expr *makeexpr_bicall_5(name, type, arg1, arg2, arg3, arg4, arg5) +char *name; +Type *type; +Expr *arg1, *arg2, *arg3, *arg4, *arg5; +{ + Expr *ex; + + if (!name || !*name) { + intwarning("makeexpr_bicall_5", "Required name of built-in procedure is missing [157]"); + name = "MissingProc"; + } + ex = makeexpr(EK_BICALL, 5); + ex->val.s = stralloc(name); + ex->val.type = type; + ex->args[0] = arg1; + ex->args[1] = arg2; + ex->args[2] = arg3; + ex->args[3] = arg4; + ex->args[4] = arg5; + if (debug>2) { fprintf(outf,"makeexpr_bicall returns "); dumpexpr(ex); fprintf(outf,"\n"); } + return ex; +} + + + + +Expr *copyexpr(ex) +register Expr *ex; +{ + register int i; + register Expr *ex2; + + if (ex) { + ex2 = makeexpr(ex->kind, ex->nargs); + for (i = 0; i < ex->nargs; i++) + ex2->args[i] = copyexpr(ex->args[i]); + switch (ex->kind) { + + case EK_CONST: + case EK_LONGCONST: + ex2->val = copyvalue(ex->val); + break; + + case EK_DOT: + case EK_NAME: + case EK_BICALL: + ex2->val.type = ex->val.type; + ex2->val.i = ex->val.i; + if (ex->val.s) + ex2->val.s = stralloc(ex->val.s); + break; + + default: + ex2->val = ex->val; + break; + } + return ex2; + } else + return NULL; +} + + + +int exprsame(a, b, strict) +register Expr *a, *b; +int strict; +{ + register int i; + + if (!a) + return (!b); + if (!b) + return 0; + if (a->val.type != b->val.type && strict != 2) { + if (strict || + !((a->val.type->kind == TK_POINTER && + a->val.type->basetype == b->val.type) || + (b->val.type->kind == TK_POINTER && + b->val.type->basetype == a->val.type))) + return 0; + } + if (a->kind != b->kind || a->nargs != b->nargs) + return 0; + switch (a->kind) { + + case EK_CONST: + case EK_LONGCONST: + if (!valuesame(a->val, b->val)) + return 0; + break; + + case EK_BICALL: + case EK_NAME: + if (strcmp(a->val.s, b->val.s)) + return 0; + break; + + case EK_VAR: + case EK_FUNCTION: + case EK_CTX: + case EK_MACARG: + if (a->val.i != b->val.i) + return 0; + break; + + case EK_DOT: + if (a->val.i != b->val.i || + (!a->val.i && strcmp(a->val.s, b->val.s))) + return 0; + break; + + default: + break; + } + i = a->nargs; + while (--i >= 0) + if (!exprsame(a->args[i], b->args[i], (strict == 2) ? 1 : strict)) + return 0; + return 1; +} + + + +int exprequiv(a, b) +register Expr *a, *b; +{ + register int i, j, k; + enum exprkind kind2; + + if (!a) + return (!b); + if (!b) + return 0; + switch (a->kind) { + + case EK_PLUS: + case EK_TIMES: + case EK_BAND: + case EK_BOR: + case EK_BXOR: + case EK_EQ: + case EK_NE: + if (b->kind != a->kind || b->nargs != a->nargs || + b->val.type != a->val.type) + return 0; + if (a->nargs > 3) + break; + for (i = 0; i < b->nargs; i++) { + if (exprequiv(a->args[0], b->args[i])) { + for (j = 0; j < b->nargs; j++) { + if (j != i && + exprequiv(a->args[1], b->args[i])) { + if (a->nargs == 2) + return 1; + for (k = 0; k < b->nargs; k++) { + if (k != i && k != j && + exprequiv(a->args[2], b->args[k])) + return 1; + } + } + } + } + } + break; + + case EK_LT: + case EK_GT: + case EK_LE: + case EK_GE: + switch (a->kind) { + case EK_LT: kind2 = EK_GT; break; + case EK_GT: kind2 = EK_LT; break; + case EK_LE: kind2 = EK_GE; break; + default: kind2 = EK_LE; break; + } + if (b->kind != kind2 || b->val.type != a->val.type) + break; + if (exprequiv(a->args[0], b->args[1]) && + exprequiv(a->args[1], b->args[0])) { + return 1; + } + break; + + case EK_CONST: + case EK_LONGCONST: + case EK_BICALL: + case EK_NAME: + case EK_VAR: + case EK_FUNCTION: + case EK_CTX: + case EK_DOT: + return exprsame(a, b, 0); + + default: + break; + } + if (b->kind != a->kind || b->nargs != a->nargs || + b->val.type != a->val.type) + return 0; + i = a->nargs; + while (--i >= 0) + if (!exprequiv(a->args[i], b->args[i])) + return 0; + return 1; +} + + + +void deletearg(ex, n) +Expr **ex; +register int n; +{ + register Expr *ex1 = *ex, *ex2; + register int i; + + if (debug>2) { fprintf(outf,"deletearg("); dumpexpr(*ex); fprintf(outf,", %d)\n", n); } + if (n < 0 || n >= (*ex)->nargs) { + intwarning("deletearg", "argument number out of range [158]"); + return; + } + ex2 = makeexpr(ex1->kind, ex1->nargs-1); + ex2->val = ex1->val; + for (i = 0; i < n; i++) + ex2->args[i] = ex1->args[i]; + for (; i < ex2->nargs; i++) + ex2->args[i] = ex1->args[i+1]; + *ex = ex2; + FREE(ex1); + if (debug>2) { fprintf(outf,"deletearg returns "); dumpexpr(*ex); fprintf(outf,"\n"); } +} + + + +void insertarg(ex, n, arg) +Expr **ex; +Expr *arg; +register int n; +{ + register Expr *ex1 = *ex, *ex2; + register int i; + + if (debug>2) { fprintf(outf,"insertarg("); dumpexpr(*ex); fprintf(outf,", %d)\n", n); } + if (n < 0 || n > (*ex)->nargs) { + intwarning("insertarg", "argument number out of range [159]"); + return; + } + ex2 = makeexpr(ex1->kind, ex1->nargs+1); + ex2->val = ex1->val; + for (i = 0; i < n; i++) + ex2->args[i] = ex1->args[i]; + ex2->args[n] = arg; + for (; i < ex1->nargs; i++) + ex2->args[i+1] = ex1->args[i]; + *ex = ex2; + FREE(ex1); + if (debug>2) { fprintf(outf,"insertarg returns "); dumpexpr(*ex); fprintf(outf,"\n"); } +} + + + +Expr *grabarg(ex, n) +Expr *ex; +int n; +{ + Expr *ex2; + + if (n < 0 || n >= ex->nargs) { + intwarning("grabarg", "argument number out of range [160]"); + return ex; + } + ex2 = ex->args[n]; + ex->args[n] = makeexpr_long(0); /* placeholder */ + freeexpr(ex); + return ex2; +} + + + +void delsimparg(ep, n) +Expr **ep; +int n; +{ + if (n < 0 || n >= (*ep)->nargs) { + intwarning("delsimparg", "argument number out of range [161]"); + return; + } + deletearg(ep, n); + switch ((*ep)->kind) { + + case EK_PLUS: + case EK_TIMES: + case EK_COMMA: + if ((*ep)->nargs == 1) + *ep = grabarg(*ep, 0); + break; + + default: + break; + + } +} + + + + +Expr *resimplify(ex) +Expr *ex; +{ + Expr *ex2; + Type *type; + int i; + + if (debug>2) { fprintf(outf,"resimplify("); dumpexpr(ex); fprintf(outf,")\n"); } + if (!ex) + return NULL; + type = ex->val.type; + switch (ex->kind) { + + case EK_PLUS: + ex2 = ex->args[0]; + for (i = 1; i < ex->nargs; i++) + ex2 = makeexpr_plus(ex2, ex->args[i]); + FREE(ex); + return ex2; + + case EK_TIMES: + ex2 = ex->args[0]; + for (i = 1; i < ex->nargs; i++) + ex2 = makeexpr_times(ex2, ex->args[i]); + FREE(ex); + return ex2; + + case EK_NEG: + ex = makeexpr_neg(grabarg(ex, 0)); + ex->val.type = type; + return ex; + + case EK_NOT: + ex = makeexpr_not(grabarg(ex, 0)); + ex->val.type = type; + return ex; + + case EK_HAT: + ex = makeexpr_hat(grabarg(ex, 0), 0); + if (ex->kind == EK_HAT) + ex->val.type = type; + return ex; + + case EK_ADDR: + ex = makeexpr_addr(grabarg(ex, 0)); + ex->val.type = type; + return ex; + + case EK_ASSIGN: + ex2 = makeexpr_assign(ex->args[0], ex->args[1]); + FREE(ex); + return ex2; + + default: + break; + } + return ex; +} + + + + + + +int realzero(s) +register char *s; +{ + if (*s == '-') s++; + while (*s == '0' || *s == '.') s++; + return (!isdigit(*s)); +} + +int realint(s, i) +register char *s; +int i; +{ + if (i == 0) + return realzero(s); + if (*s == '-') { + s++; + i = -i; + } + if (i < 0 || i > 9) return 0; /* we don't care about large values here */ + while (*s == '0') s++; + if (*s++ != i + '0') return 0; + if (*s == '.') + while (*++s == '0') ; + return (!isdigit(*s)); +} + + +int checkconst(ex, val) +Expr *ex; +long val; +{ + Meaning *mp; + Value exval; + + if (!ex) + return 0; + if (ex->kind == EK_CAST || ex->kind == EK_ACTCAST) + ex = ex->args[0]; + if (ex->kind == EK_CONST || ex->kind == EK_LONGCONST) + exval = ex->val; + else if (ex->kind == EK_VAR && + (mp = (Meaning *)ex->val.i)->kind == MK_CONST && + mp->val.type && + foldconsts != 0) + exval = mp->val; + else + return 0; + switch (exval.type->kind) { + + case TK_BOOLEAN: + case TK_INTEGER: + case TK_CHAR: + case TK_ENUM: + case TK_SUBR: + case TK_SMALLSET: + case TK_SMALLARRAY: + return exval.i == val; + + case TK_POINTER: + case TK_STRING: + return (val == 0 && exval.i == 0); + + case TK_REAL: + return realint(exval.s, val); + + default: + return 0; + } +} + + + +int isliteralconst(ex, valp) +Expr *ex; +Value *valp; +{ + Meaning *mp; + + if (ex) { + switch (ex->kind) { + + case EK_CONST: + case EK_LONGCONST: + if (valp) + *valp = ex->val; + return 2; + + case EK_VAR: + mp = (Meaning *)ex->val.i; + if (mp->kind == MK_CONST) { + if (valp) { + if (foldconsts == 0) + valp->type = NULL; + else + *valp = mp->val; + } + return 1; + } + break; + + default: + break; + } + } + if (valp) + valp->type = NULL; + return 0; +} + + + +int isconstexpr(ex, valp) +Expr *ex; +long *valp; +{ + Value exval; + + if (debug>2) { fprintf(outf,"isconstexpr("); dumpexpr(ex); fprintf(outf,")\n"); } + exval = eval_expr(ex); + if (exval.type) { + if (valp) + *valp = exval.i; + return 1; + } else + return 0; +} + + + +int isconstantexpr(ex) +Expr *ex; +{ + Meaning *mp; + int i; + + switch (ex->kind) { + + case EK_CONST: + case EK_LONGCONST: + case EK_SIZEOF: + return 1; + + case EK_ADDR: + if (ex->args[0]->kind == EK_VAR) { + mp = (Meaning *)ex->val.i; + return (!mp->ctx || mp->ctx->kind == MK_MODULE); + } + return 0; + + case EK_VAR: + mp = (Meaning *)ex->val.i; + return (mp->kind == MK_CONST); + + case EK_BICALL: + case EK_FUNCTION: + if (!deterministic_func(ex)) + return 0; + + /* fall through */ + case EK_EQ: + case EK_NE: + case EK_LT: + case EK_GT: + case EK_LE: + case EK_GE: + case EK_PLUS: + case EK_NEG: + case EK_TIMES: + case EK_DIVIDE: + case EK_DIV: + case EK_MOD: + case EK_AND: + case EK_OR: + case EK_NOT: + case EK_BAND: + case EK_BOR: + case EK_BXOR: + case EK_BNOT: + case EK_LSH: + case EK_RSH: + case EK_CAST: + case EK_ACTCAST: + case EK_COND: + for (i = 0; i < ex->nargs; i++) { + if (!isconstantexpr(ex->args[i])) + return 0; + } + return 1; + + case EK_COMMA: + return isconstantexpr(ex->args[ex->nargs-1]); + + default: + return 0; + } +} + + + + + +Static Expr *docast(a, type) +Expr *a; +Type *type; +{ + Value val; + Meaning *mp; + int i; + Expr *ex; + + if (a->val.type->kind == TK_SMALLSET && type->kind == TK_SET) { + mp = makestmttempvar(type, name_SET); + return makeexpr_bicall_2(setexpandname, type, + makeexpr_var(mp), + makeexpr_arglong(a, 1)); + } else if (a->val.type->kind == TK_SET && type->kind == TK_SMALLSET) { + return packset(a, type); + } + switch (a->kind) { + + case EK_VAR: + mp = (Meaning *) a->val.i; + if (mp->kind == MK_CONST) { + if (mp->val.type && mp->val.type->kind == TK_STRING && + type->kind == TK_CHAR) { + val = value_cast(mp->val, type); + a->kind = EK_CONST; + a->val = val; + return a; + } + } + break; + + case EK_CONST: + case EK_LONGCONST: + val = value_cast(a->val, type); + if (val.type) { + a->val = val; + return a; + } + break; + + case EK_PLUS: + case EK_NEG: + case EK_TIMES: + if (type->kind == TK_REAL) { + for (i = 0; i < a->nargs; i++) { + ex = docast(a->args[i], type); + if (ex) { + a->args[i] = ex; + a->val.type = type; + return a; + } + } + } + break; + + default: + break; + } + return NULL; +} + + + +/* Make an "active" cast, i.e., one that performs an explicit operation */ +Expr *makeexpr_actcast(a, type) +Expr *a; +Type *type; +{ + if (debug>2) { fprintf(outf,"makeexpr_actcast("); dumpexpr(a); fprintf(outf,", "); dumptypename(type, 1); fprintf(outf,")\n"); } + + if (similartypes(a->val.type, type)) { + a->val.type = type; + return a; + } + return makeexpr_un(EK_ACTCAST, type, a); +} + + + +Expr *makeexpr_cast(a, type) +Expr *a; +Type *type; +{ + Expr *ex; + + if (debug>2) { fprintf(outf,"makeexpr_cast("); dumpexpr(a); fprintf(outf,", "); dumptypename(type, 1); fprintf(outf,")\n"); } + if (a->val.type == type) + return a; + ex = docast(a, type); + if (ex) + return ex; + if (a->kind == EK_CAST && + a->args[0]->val.type->kind == TK_POINTER && + similartypes(type, a->args[0]->val.type)) { + a = grabarg(a, 0); + a->val.type = type; + return a; + } + if ((a->kind == EK_CAST && + ((a->val.type->kind == TK_POINTER && type->kind == TK_POINTER) || + (ord_type(a->val.type)->kind == TK_INTEGER && ord_type(type)->kind == TK_INTEGER))) || + similartypes(type, a->val.type)) { + a->val.type = type; + return a; + } + return makeexpr_un(EK_CAST, type, a); +} + + + +Expr *gentle_cast(a, type) +Expr *a; +Type *type; +{ + Expr *ex; + Type *btype; + long smin, smax; + Value val; + char c; + + if (debug>2) { fprintf(outf,"gentle_cast("); dumpexpr(a); fprintf(outf,", "); dumptypename(type, 1); fprintf(outf,")\n"); } + if (!type) { + intwarning("gentle_cast", "type == NULL"); + return a; + } + if (a->val.type->kind == TK_POINTER && type->kind == TK_POINTER) { + if (voidstar && (type == tp_anyptr || a->val.type == tp_anyptr)) { + if (type == tp_anyptr && a->kind == EK_CAST && + a->args[0]->val.type->kind == TK_POINTER) + return a->args[0]; /* remove explicit cast since casting implicitly */ + return a; /* casting to/from "void *" */ + } + return makeexpr_cast(a, type); + } + if (type->kind == TK_STRING) + return makeexpr_stringify(a); + if (type->kind == TK_ARRAY && + (a->val.type->kind == TK_STRING || + a->val.type->kind == TK_CHAR) && + isliteralconst(a, &val) && val.type && + ord_range(type->indextype, &smin, &smax)) { + smax = smax - smin + 1; + if (a->val.type->kind == TK_CHAR) { + val.s = &c; + c = val.i; + val.i = 1; + } + if (val.i > smax) { + warning("Too many characters for packed array of char [162]"); + } else if (val.i < smax || a->val.type->kind == TK_CHAR) { + ex = makeexpr_lstring(val.s, smax); + while (smax > val.i) + ex->val.s[--smax] = ' '; + freeexpr(a); + return ex; + } + } + btype = (type->kind == TK_SUBR) ? type->basetype : type; + if ((a->kind == EK_CAST || a->kind == EK_ACTCAST) && + btype->kind == TK_INTEGER && + ord_type(a->val.type)->kind == TK_INTEGER) + return makeexpr_longcast(a, long_type(type)); + if (a->val.type == btype) + return a; + ex = docast(a, btype); + if (ex) + return ex; + if (btype->kind == TK_CHAR && a->val.type->kind == TK_STRING) + return makeexpr_hat(a, 0); + return a; +} + + + +Expr *makeexpr_charcast(ex) +Expr *ex; +{ + Meaning *mp; + + if (ex->kind == EK_CONST && ex->val.type->kind == TK_STRING && + ex->val.i == 1) { + ex->val.type = tp_char; + ex->val.i = ex->val.s[0] & 0xff; + ex->val.s = NULL; + } + if (ex->kind == EK_VAR && + (mp = (Meaning *)ex->val.i)->kind == MK_CONST && + mp->val.type && + mp->val.type->kind == TK_STRING && + mp->val.i == 1) { + ex->kind = EK_CONST; + ex->val.type = tp_char; + ex->val.i = mp->val.s[0] & 0xff; + ex->val.s = NULL; + } + return ex; +} + + + +Expr *makeexpr_stringcast(ex) +Expr *ex; +{ + char ch; + + if (ex->kind == EK_CONST && ord_type(ex->val.type)->kind == TK_CHAR) { + ch = ex->val.i; + freeexpr(ex); + ex = makeexpr_lstring(&ch, 1); + } + return ex; +} + + + + + +/* 0/1 = force to int/long, 2/3 = check if int/long */ + +Static Expr *dolongcast(a, tolong) +Expr *a; +int tolong; +{ + Meaning *mp; + Expr *ex; + Type *type; + int i; + + switch (a->kind) { + + case EK_DOT: + if (!a->val.i) { + if (long_type(a->val.type) == (tolong&1)) + return a; + break; + } + + /* fall through */ + case EK_VAR: + mp = (Meaning *)a->val.i; + if (mp->kind == MK_FIELD && mp->val.i) { + if (mp->val.i <= ((sizeof_int > 0) ? sizeof_int : 16) && + !(tolong&1)) + return a; + } else if (mp->kind == MK_VAR || + mp->kind == MK_VARREF || + mp->kind == MK_PARAM || + mp->kind == MK_VARPARAM || + mp->kind == MK_FIELD) { + if (long_type(mp->type) == (tolong&1)) + return a; + } + break; + + case EK_FUNCTION: + mp = (Meaning *)a->val.i; + if (long_type(mp->type->basetype) == (tolong&1)) + return a; + break; + + case EK_BICALL: + if (!strcmp(a->val.s, signextname) && *signextname) { + i = 0; + goto unary; + } + if (!strcmp(a->val.s, "strlen")) + goto size_t_case; + /* fall through */ + + case EK_HAT: /* get true type from a->val.type */ + case EK_INDEX: + case EK_SPCALL: + case EK_NAME: + if (long_type(a->val.type) == (tolong&1)) + return a; + break; + + case EK_ASSIGN: /* destination determines type, */ + case EK_POSTINC: /* but must not be changed */ + case EK_POSTDEC: + return dolongcast(a->args[0], tolong|2); + + case EK_CAST: + if (ord_type(a->val.type)->kind == TK_INTEGER && + long_type(a->val.type) == (tolong&1)) + return a; + if (tolong == 0) { + a->val.type = tp_int; + return a; + } else if (tolong == 1) { + a->val.type = tp_integer; + return a; + } + break; + + case EK_ACTCAST: + if (ord_type(a->val.type)->kind == TK_INTEGER && + long_type(a->val.type) == (tolong&1)) + return a; + break; + + case EK_CONST: + type = ord_type(a->val.type); + if (type->kind == TK_INTEGER || type->kind == TK_SMALLSET) { + if (tolong == 1) + a->kind = EK_LONGCONST; + if (tolong != 3) + return a; + } + break; + + case EK_LONGCONST: + if (tolong == 0) { + if (a->val.i >= -32767 && a->val.i <= 32767) + a->kind = EK_CONST; + else + return NULL; + } + if (tolong != 2) + return a; + break; + + case EK_SIZEOF: + size_t_case: + if (size_t_long > 0 && tolong&1) + return a; + if (size_t_long == 0 && !(tolong&1)) + return a; + break; + + case EK_PLUS: /* usual arithmetic conversions apply */ + case EK_TIMES: + case EK_DIV: + case EK_MOD: + case EK_BAND: + case EK_BOR: + case EK_BXOR: + case EK_COND: + i = (a->kind == EK_COND) ? 1 : 0; + if (tolong&1) { + for (; i < a->nargs; i++) { + ex = dolongcast(a->args[i], tolong); + if (ex) { + a->args[i] = ex; + return a; + } + } + } else { + for (; i < a->nargs; i++) { + if (!dolongcast(a->args[i], tolong)) + return NULL; + } + return a; + } + break; + + case EK_BNOT: /* single argument defines result type */ + case EK_NEG: + case EK_LSH: + case EK_RSH: + case EK_COMMA: + i = (a->kind == EK_COMMA) ? a->nargs-1 : 0; +unary: + if (tolong&1) { + ex = dolongcast(a->args[i], tolong); + if (ex) { + a->args[i] = ex; + return a; + } + } else { + if (dolongcast(a->args[i], tolong)) + return a; + } + break; + + case EK_AND: /* operators which always return int */ + case EK_OR: + case EK_EQ: + case EK_NE: + case EK_LT: + case EK_GT: + case EK_LE: + case EK_GE: + if (tolong&1) + break; + return a; + + default: + break; + } + return NULL; +} + + +/* Return -1 if short int or plain int, 1 if long, 0 if can't tell */ +int exprlongness(ex) +Expr *ex; +{ + if (sizeof_int >= 32) + return -1; + return (dolongcast(ex, 3) != NULL) - + (dolongcast(ex, 2) != NULL); +} + + +Expr *makeexpr_longcast(a, tolong) +Expr *a; +int tolong; +{ + Expr *ex; + Type *type; + + if (sizeof_int >= 32) + return a; + type = ord_type(a->val.type); + if (type->kind != TK_INTEGER && type->kind != TK_SMALLSET) + return a; + a = makeexpr_unlongcast(a); + if (tolong) { + ex = dolongcast(a, 1); + } else { + ex = dolongcast(copyexpr(a), 0); + if (ex) { + if (!dolongcast(ex, 2)) { + freeexpr(ex); + ex = NULL; + } + } + } + if (ex) + return ex; + return makeexpr_un(EK_CAST, (tolong) ? tp_integer : tp_int, a); +} + + +Expr *makeexpr_arglong(a, tolong) +Expr *a; +int tolong; +{ + int cast = castlongargs; + if (cast < 0) + cast = castargs; + if (cast > 0 || (cast < 0 && prototypes == 0)) { + return makeexpr_longcast(a, tolong); + } + return a; +} + + + +Expr *makeexpr_unlongcast(a) +Expr *a; +{ + switch (a->kind) { + + case EK_LONGCONST: + if (a->val.i >= -32767 && a->val.i <= 32767) + a->kind = EK_CONST; + break; + + case EK_CAST: + if ((a->val.type == tp_integer || + a->val.type == tp_int) && + ord_type(a->args[0]->val.type)->kind == TK_INTEGER) { + a = grabarg(a, 0); + } + break; + + default: + break; + + } + return a; +} + + + +Expr *makeexpr_forcelongness(a) /* force a to have a definite longness */ +Expr *a; +{ + Expr *ex; + + ex = makeexpr_unlongcast(copyexpr(a)); + if (exprlongness(ex)) { + freeexpr(a); + return ex; + } + freeexpr(ex); + if (exprlongness(a) == 0) + return makeexpr_longcast(a, 1); + else + return a; +} + + + +Expr *makeexpr_ord(ex) +Expr *ex; +{ + ex = makeexpr_charcast(ex); + switch (ord_type(ex->val.type)->kind) { + + case TK_ENUM: + return makeexpr_cast(ex, tp_int); + + case TK_CHAR: + if (ex->kind == EK_CONST && + (ex->val.i >= 32 && ex->val.i < 127)) { + insertarg(&ex, 0, makeexpr_name("'%lc'", tp_integer)); + } + ex->val.type = tp_int; + return ex; + + case TK_BOOLEAN: + ex->val.type = tp_int; + return ex; + + case TK_POINTER: + return makeexpr_cast(ex, tp_integer); + + default: + return ex; + } +} + + + + +/* Tell whether an expression "looks" negative */ +int expr_looks_neg(ex) +Expr *ex; +{ + int i; + + switch (ex->kind) { + + case EK_NEG: + return 1; + + case EK_CONST: + case EK_LONGCONST: + switch (ord_type(ex->val.type)->kind) { + case TK_INTEGER: + case TK_CHAR: + return (ex->val.i < 0); + case TK_REAL: + return (ex->val.s && ex->val.s[0] == '-'); + default: + return 0; + } + + case EK_TIMES: + case EK_DIVIDE: + for (i = 0; i < ex->nargs; i++) { + if (expr_looks_neg(ex->args[i])) + return 1; + } + return 0; + + case EK_CAST: + return expr_looks_neg(ex->args[0]); + + default: + return 0; + } +} + + + +/* Tell whether an expression is probably negative */ +int expr_is_neg(ex) +Expr *ex; +{ + int i; + + i = possiblesigns(ex) & (1|4); + if (i == 1) + return 1; /* if expression really is negative! */ + if (i == 4) + return 0; /* if expression is definitely positive. */ + return expr_looks_neg(ex); +} + + + +int expr_neg_cost(a) +Expr *a; +{ + int i, c; + + switch (a->kind) { + + case EK_CONST: + case EK_LONGCONST: + switch (ord_type(a->val.type)->kind) { + case TK_INTEGER: + case TK_CHAR: + case TK_REAL: + return 0; + default: + return 1; + } + + case EK_NEG: + return -1; + + case EK_TIMES: + case EK_DIVIDE: + for (i = 0; i < a->nargs; i++) { + c = expr_neg_cost(a->args[i]); + if (c <= 0) + return c; + } + return 1; + + case EK_PLUS: + for (i = 0; i < a->nargs; i++) { + if (expr_looks_neg(a->args[i])) + return 0; + } + return 1; + + default: + return 1; + } +} + + + +Expr *enum_to_int(a) +Expr *a; +{ + if (ord_type(a->val.type)->kind == TK_ENUM) { + if (a->kind == EK_CAST && + ord_type(a->args[0]->val.type)->kind == TK_INTEGER) + return grabarg(a, 0); + else + return makeexpr_cast(a, tp_integer); + } else + return a; +} + + + +Expr *neg_inside_sum(a) +Expr *a; +{ + int i; + + for (i = 0; i < a->nargs; i++) + a->args[i] = makeexpr_neg(a->args[i]); + return a; +} + + + +Expr *makeexpr_neg(a) +Expr *a; +{ + int i; + + if (debug>2) { fprintf(outf,"makeexpr_neg("); dumpexpr(a); fprintf(outf,")\n"); } + a = enum_to_int(a); + switch (a->kind) { + + case EK_CONST: + case EK_LONGCONST: + switch (ord_type(a->val.type)->kind) { + + case TK_INTEGER: + case TK_CHAR: + if (a->val.i == MININT) + valrange(); + else + a->val.i = - a->val.i; + return a; + + case TK_REAL: + if (!realzero(a->val.s)) { + if (a->val.s[0] == '-') + strchange(&a->val.s, a->val.s+1); + else + strchange(&a->val.s, format_s("-%s", a->val.s)); + } + return a; + + default: + break; + } + break; + + case EK_PLUS: + if (expr_neg_cost(a) <= 0) + return neg_inside_sum(a); + break; + + case EK_TIMES: + case EK_DIVIDE: + for (i = 0; i < a->nargs; i++) { + if (expr_neg_cost(a->args[i]) <= 0) { + a->args[i] = makeexpr_neg(a->args[i]); + return a; + } + } + break; + + case EK_CAST: + if (a->val.type != tp_unsigned && + a->val.type != tp_uint && + a->val.type != tp_ushort && + a->val.type != tp_ubyte && + a->args[0]->val.type != tp_unsigned && + a->args[0]->val.type != tp_uint && + a->args[0]->val.type != tp_ushort && + a->args[0]->val.type != tp_ubyte && + expr_looks_neg(a->args[0])) { + a->args[0] = makeexpr_neg(a->args[0]); + return a; + } + break; + + case EK_NEG: + return grabarg(a, 0); + + default: + break; + } + return makeexpr_un(EK_NEG, promote_type(a->val.type), a); +} + + + + +#define ISCONST(kind) ((kind)==EK_CONST || (kind)==EK_LONGCONST) +#define MOVCONST(ex) (ISCONST((ex)->kind) && (ex)->val.type->kind != TK_STRING) +#define COMMUTATIVE (kind != EK_COMMA && type->kind != TK_REAL) + +Type *true_type(ex) +Expr *ex; +{ + Meaning *mp; + Type *type, *tp; + + while (ex->kind == EK_CAST) + ex = ex->args[0]; + type = ex->val.type; + if (ex->kind == EK_VAR || ex->kind == EK_FUNCTION || ex->kind == EK_DOT) { + mp = (Meaning *)ex->val.i; + if (mp && mp->type && mp->type->kind != TK_VOID) + type = mp->type; + } + if (ex->kind == EK_INDEX) { + tp = true_type(ex->args[0]); + if ((tp->kind == TK_ARRAY || tp->kind == TK_SMALLARRAY || + tp->kind == TK_STRING) && + tp->basetype && tp->basetype->kind != TK_VOID) + type = tp->basetype; + } + if (type->kind == TK_SUBR) + type = findbasetype(type, ODECL_NOPRES); + return type; +} + +int ischartype(ex) +Expr *ex; +{ + if (ord_type(ex->val.type)->kind == TK_CHAR) + return 1; + if (true_type(ex)->kind == TK_CHAR) + return 1; + if (ISCONST(ex->kind) && ex->nargs > 0 && + ex->args[0]->kind == EK_NAME && + ex->args[0]->val.s[0] == '\'') + return 1; + return 0; +} + +Static Expr *commute(a, b, kind) +Expr *a, *b; +enum exprkind kind; +{ + int i, di; + Type *type; + + if (debug>2) { fprintf(outf,"commute("); dumpexpr(a); fprintf(outf,", "); dumpexpr(b); fprintf(outf,")\n"); } +#if 1 + type = promote_type_bin(a->val.type, b->val.type); +#else + type = a->val.type; + if (b->val.type->kind == TK_REAL) + type = b->val.type; +#endif + if (MOVCONST(a) && !MOVCONST(b) && COMMUTATIVE) + swapexprs(a, b); /* put constant last */ + if (a->kind == kind) { + di = (MOVCONST(a->args[a->nargs-1]) && COMMUTATIVE) ? -1 : 0; + if (b->kind == kind) { + for (i = 0; i < b->nargs; i++) + insertarg(&a, a->nargs + di, b->args[i]); + FREE(b); + } else + insertarg(&a, a->nargs + di, b); + a->val.type = type; + } else if (b->kind == kind) { + if (MOVCONST(a) && COMMUTATIVE) + insertarg(&b, b->nargs, a); + else + insertarg(&b, 0, a); + a = b; + a->val.type = type; + } else { + a = makeexpr_bin(kind, type, a, b); + } + if (debug>2) { fprintf(outf,"commute returns "); dumpexpr(a); fprintf(outf,"\n"); } + return a; +} + + +Expr *makeexpr_plus(a, b) +Expr *a, *b; +{ + int i, j, k, castdouble = 0; + Type *type; + + if (debug>2) { fprintf(outf,"makeexpr_plus("); dumpexpr(a); fprintf(outf,", "); dumpexpr(b); fprintf(outf,")\n"); } + if (!a) + return b; + if (!b) + return a; + if (a->kind == EK_NEG && a->args[0]->kind == EK_PLUS) + a = neg_inside_sum(grabarg(a, 0)); + if (b->kind == EK_NEG && b->args[0]->kind == EK_PLUS) + b = neg_inside_sum(grabarg(b, 0)); + a = commute(enum_to_int(a), enum_to_int(b), EK_PLUS); + type = NULL; + for (i = 0; i < a->nargs; i++) { + if (ord_type(a->args[i]->val.type)->kind == TK_CHAR || + a->args[i]->val.type->kind == TK_POINTER || + a->args[i]->val.type->kind == TK_STRING) { /* for string literals */ + if (type == ord_type(a->args[i]->val.type)) + type = tp_integer; /* 'z'-'a' and p1-p2 are integers */ + else + type = ord_type(a->args[i]->val.type); + } + } + if (type) + a->val.type = type; + for (i = 0; i < a->nargs && !ISCONST(a->args[i]->kind); i++) ; + if (i < a->nargs-1) { + for (j = i+1; j < a->nargs; j++) { + if (ISCONST(a->args[j]->kind)) { + if ((ord_type(a->args[i]->val.type) == ord_type(a->args[j]->val.type) || + ord_type(a->args[i]->val.type)->kind == TK_INTEGER || + ord_type(a->args[j]->val.type)->kind == TK_INTEGER) && + (!(ischartype(a->args[i]) || ischartype(a->args[j])) || + a->args[i]->val.i == - a->args[j]->val.i || + a->args[i]->val.i == 0 || a->args[j]->val.i == 0) && + (a->args[i]->val.type->kind != TK_REAL && + a->args[i]->val.type->kind != TK_STRING && + a->args[j]->val.type->kind != TK_REAL && + a->args[j]->val.type->kind != TK_STRING)) { + a->args[i]->val.i += a->args[j]->val.i; + delfreearg(&a, j); + j--; + } else if (a->args[i]->val.type->kind == TK_STRING && + ord_type(a->args[j]->val.type)->kind == TK_INTEGER && + a->args[j]->val.i < 0 && + a->args[j]->val.i >= -stringleaders) { + /* strictly speaking, the following is illegal pointer arithmetic */ + a->args[i] = makeexpr_lstring(a->args[i]->val.s + a->args[j]->val.i, + a->args[i]->val.i - a->args[j]->val.i); + for (k = 0; k < - a->args[j]->val.i; k++) + a->args[i]->val.s[k] = '>'; + delfreearg(&a, j); + j--; + } + } + } + } + if (checkconst(a->args[a->nargs-1], 0)) { + if (a->args[a->nargs-1]->val.type->kind == TK_REAL && + a->args[0]->val.type->kind != TK_REAL) + castdouble = 1; + delfreearg(&a, a->nargs-1); + } + for (i = 0; i < a->nargs; i++) { + if (a->args[i]->kind == EK_NEG && nosideeffects(a->args[i], 1)) { + for (j = 0; j < a->nargs; j++) { + if (exprsame(a->args[j], a->args[i]->args[0], 1)) { + delfreearg(&a, i); + if (i < j) j--; else i--; + delfreearg(&a, j); + i--; + break; + } + } + } + } + if (a->nargs == 0) { + type = a->val.type; + FREE(a); + a = gentle_cast(makeexpr_long(0), type); + a->val.type = type; + return a; + } else if (a->nargs == 1) { + b = a->args[0]; + FREE(a); + a = b; + } else { + if (a->nargs == 2 && ISCONST(a->args[1]->kind) && + a->args[1]->val.i <= -127 && + true_type(a->args[0]) == tp_char && signedchars != 0) { + a->args[0] = force_unsigned(a->args[0]); + } + if (a->nargs > 2 && + ISCONST(a->args[a->nargs-1]->kind) && + ISCONST(a->args[a->nargs-2]->kind) && + ischartype(a->args[a->nargs-1]) && + ischartype(a->args[a->nargs-2])) { + i = a->args[a->nargs-1]->val.i; + j = a->args[a->nargs-2]->val.i; + if ((i == 'a' || i == 'A' || i == -'a' || i == -'A') && + (j == 'a' || j == 'A' || j == -'a' || j == -'A')) { + if (abs(i+j) == 32) { + delfreearg(&a, a->nargs-1); + delsimpfreearg(&a, a->nargs-1); + a = makeexpr_bicall_1((i+j > 0) ? "_tolower" : "_toupper", + tp_char, a); + } + } + } + } + if (castdouble) + a = makeexpr_cast(a, tp_real); + return a; +} + + +Expr *makeexpr_minus(a, b) +Expr *a, *b; +{ + int okneg; + + if (debug>2) { fprintf(outf,"makeexpr_minus("); dumpexpr(a); fprintf(outf,", "); dumpexpr(b); fprintf(outf,")\n"); } + if (ISCONST(b->kind) && b->val.i == 0 && /* kludge for array indexing */ + ord_type(b->val.type)->kind == TK_ENUM) { + b->val.type = tp_integer; + } + okneg = (a->kind != EK_PLUS && b->kind != EK_PLUS); + a = makeexpr_plus(a, makeexpr_neg(b)); + if (okneg && a->kind == EK_PLUS) + a->val.i = 1; /* this flag says to write as "a-b" if possible */ + return a; +} + + +Expr *makeexpr_inc(a, b) +Expr *a, *b; +{ + Type *type; + + type = a->val.type; + a = makeexpr_plus(makeexpr_charcast(a), b); + if (ord_type(type)->kind != TK_INTEGER && + ord_type(type)->kind != TK_CHAR) + a = makeexpr_cast(a, type); + return a; +} + + + +/* Apply the distributive law for a sum of products */ +Expr *distribute_plus(ex) +Expr *ex; +{ + int i, j, icom; + Expr *common, *outer, *ex2, **exp; + + if (debug>2) { fprintf(outf,"distribute_plus("); dumpexpr(ex); fprintf(outf,")\n"); } + if (ex->kind != EK_PLUS) + return ex; + for (i = 0; i < ex->nargs; i++) + if (ex->args[i]->kind == EK_TIMES) + break; + if (i == ex->nargs) + return ex; + outer = NULL; + icom = 0; + for (;;) { + ex2 = ex->args[0]; + if (ex2->kind == EK_NEG) + ex2 = ex2->args[0]; + if (ex2->kind == EK_TIMES) { + if (icom >= ex2->nargs) + break; + common = ex2->args[icom]; + if (common->kind == EK_NEG) + common = common->args[0]; + } else { + if (icom > 0) + break; + common = ex2; + icom++; + } + for (i = 1; i < ex->nargs; i++) { + ex2 = ex->args[i]; + if (ex2->kind == EK_NEG) + ex2 = ex2->args[i]; + if (ex2->kind == EK_TIMES) { + for (j = ex2->nargs; --j >= 0; ) { + if (exprsame(ex2->args[j], common, 1) || + (ex2->args[j]->kind == EK_NEG && + exprsame(ex2->args[j]->args[0], common, 1))) + break; + } + if (j < 0) + break; + } else { + if (!exprsame(ex2, common, 1)) + break; + } + } + if (i == ex->nargs) { + if (debug>2) { fprintf(outf,"distribute_plus does "); dumpexpr(common); fprintf(outf,"\n"); } + common = copyexpr(common); + for (i = 0; i < ex->nargs; i++) { + if (ex->args[i]->kind == EK_NEG) + ex2 = *(exp = &ex->args[i]->args[0]); + else + ex2 = *(exp = &ex->args[i]); + if (ex2->kind == EK_TIMES) { + for (j = ex2->nargs; --j >= 0; ) { + if (exprsame(ex2->args[j], common, 1)) { + delsimpfreearg(exp, j); + break; + } else if (ex2->args[j]->kind == EK_NEG && + exprsame(ex2->args[j]->args[0], common,1)) { + freeexpr(ex2->args[j]); + ex2->args[j] = makeexpr_long(-1); + break; + } + } + } else { + freeexpr(ex2); + *exp = makeexpr_long(1); + } + ex->args[i] = resimplify(ex->args[i]); + } + outer = makeexpr_times(common, outer); + } else + icom++; + } + return makeexpr_times(resimplify(ex), outer); +} + + + + + +Expr *makeexpr_times(a, b) +Expr *a, *b; +{ + int i, n, castdouble = 0; + Type *type; + + if (debug>2) { fprintf(outf,"makeexpr_times("); dumpexpr(a); fprintf(outf,", "); dumpexpr(b); fprintf(outf,")\n"); } + if (!a) + return b; + if (!b) + return a; + a = commute(a, b, EK_TIMES); + if (a->val.type->kind == TK_INTEGER) { + i = a->nargs-1; + if (i > 0 && ISCONST(a->args[i-1]->kind)) { + a->args[i-1]->val.i *= a->args[i]->val.i; + delfreearg(&a, i); + } + } + for (i = n = 0; i < a->nargs; i++) { + if (expr_neg_cost(a->args[i]) < 0) + n++; + } + if (n & 1) { + for (i = 0; i < a->nargs; i++) { + if (ISCONST(a->args[i]->kind) && + expr_neg_cost(a->args[i]) >= 0) { + a->args[i] = makeexpr_neg(a->args[i]); + n++; + break; + } + } + } else + n++; + for (i = 0; i < a->nargs && n >= 2; i++) { + if (expr_neg_cost(a->args[i]) < 0) { + a->args[i] = makeexpr_neg(a->args[i]); + n--; + } + } + if (checkconst(a->args[a->nargs-1], 1)) { + if (a->args[a->nargs-1]->val.type->kind == TK_REAL && + a->args[0]->val.type->kind != TK_REAL) + castdouble = 1; + delfreearg(&a, a->nargs-1); + } else if (checkconst(a->args[a->nargs-1], -1)) { + if (a->args[a->nargs-1]->val.type->kind == TK_REAL && + a->args[0]->val.type->kind != TK_REAL) + castdouble = 1; + delfreearg(&a, a->nargs-1); + a->args[0] = makeexpr_neg(a->args[0]); + } else if (checkconst(a->args[a->nargs-1], 0) && nosideeffects(a, 1)) { + if (a->args[a->nargs-1]->val.type->kind == TK_REAL) + type = a->args[a->nargs-1]->val.type; + else + type = a->val.type; + return makeexpr_cast(grabarg(a, a->nargs-1), type); + } + if (a->nargs < 2) { + if (a->nargs < 1) { + FREE(a); + a = makeexpr_long(1); + } else { + b = a->args[0]; + FREE(a); + a = b; + } + } + if (castdouble) + a = makeexpr_cast(a, tp_real); + return a; +} + + + +Expr *makeexpr_sqr(ex, cube) +Expr *ex; +int cube; +{ + Expr *ex2; + Meaning *tvar; + Type *type; + + if (exprspeed(ex) <= 2 && nosideeffects(ex, 0)) { + ex2 = NULL; + } else { + type = (ex->val.type->kind == TK_REAL) ? tp_longreal : tp_integer; + tvar = makestmttempvar(type, name_TEMP); + ex2 = makeexpr_assign(makeexpr_var(tvar), ex); + ex = makeexpr_var(tvar); + } + if (cube) + ex = makeexpr_times(ex, makeexpr_times(copyexpr(ex), copyexpr(ex))); + else + ex = makeexpr_times(ex, copyexpr(ex)); + return makeexpr_comma(ex2, ex); +} + + + +Expr *makeexpr_divide(a, b) +Expr *a, *b; +{ + Expr *ex; + int p; + + if (debug>2) { fprintf(outf,"makeexpr_divide("); dumpexpr(a); fprintf(outf,", "); dumpexpr(b); fprintf(outf,")\n"); } + if (a->val.type->kind != TK_REAL && + b->val.type->kind != TK_REAL) { /* must do a real division */ + ex = docast(a, tp_longreal); + if (ex) + a = ex; + else { + ex = docast(b, tp_longreal); + if (ex) + b = ex; + else + a = makeexpr_cast(a, tp_longreal); + } + } + if (a->kind == EK_TIMES) { + for (p = 0; p < a->nargs; p++) + if (exprsame(a->args[p], b, 1)) + break; + if (p < a->nargs) { + delfreearg(&a, p); + freeexpr(b); + if (a->nargs == 1) + return grabarg(a, 0); + else + return a; + } + } + if (expr_neg_cost(a) < 0 && expr_neg_cost(b) < 0) { + a = makeexpr_neg(a); + b = makeexpr_neg(b); + } + if (checkconst(b, 0)) + warning("Division by zero [163]"); + return makeexpr_bin(EK_DIVIDE, tp_longreal, a, b); +} + + + + +int gcd(a, b) +int a, b; +{ + if (a < 0) a = -a; + if (b < 0) b = -b; + while (a != 0) { + b %= a; + if (b != 0) + a %= b; + else + return a; + } + return b; +} + + + +/* possible signs of ex: 1=may be neg, 2=may be zero, 4=may be pos */ + +int negsigns(mask) +int mask; +{ + return (mask & 2) | + ((mask & 1) << 2) | + ((mask & 4) >> 2); +} + + +int possiblesigns(ex) +Expr *ex; +{ + Value val; + Type *tp; + char *cp; + int i, mask, mask2; + + if (isliteralconst(ex, &val) && val.type) { + if (val.type == tp_real || val.type == tp_longreal) { + if (realzero(val.s)) + return 2; + if (*val.s == '-') + return 1; + return 4; + } else + return (val.i < 0) ? 1 : (val.i == 0) ? 2 : 4; + } + if (ex->kind == EK_CAST && + similartypes(ex->val.type, ex->args[0]->val.type)) + return possiblesigns(ex->args[0]); + if (ex->kind == EK_NEG) + return negsigns(possiblesigns(ex->args[0])); + if (ex->kind == EK_TIMES || ex->kind == EK_DIVIDE) { + mask = possiblesigns(ex->args[0]); + for (i = 1; i < ex->nargs; i++) { + mask2 = possiblesigns(ex->args[i]); + if (mask2 & 2) + mask |= 2; + if ((mask2 & (1|4)) == 1) + mask = negsigns(mask); + else if ((mask2 & (1|4)) != 4) + mask = 1|2|4; + } + return mask; + } + if (ex->kind == EK_DIV || ex->kind == EK_MOD) { + mask = possiblesigns(ex->args[0]); + mask2 = possiblesigns(ex->args[1]); + if (!((mask | mask2) & 1)) + return 2|4; + } + if (ex->kind == EK_PLUS) { + mask = 0; + for (i = 0; i < ex->nargs; i++) { + mask2 = possiblesigns(ex->args[i]); + if ((mask & negsigns(mask2)) & (1|4)) + mask |= (1|2|4); + else + mask |= mask2; + } + return mask; + } + if (ex->kind == EK_COND) { + return possiblesigns(ex->args[1]) | possiblesigns(ex->args[2]); + } + if (ex->kind == EK_EQ || ex->kind == EK_LT || ex->kind == EK_GT || + ex->kind == EK_NE || ex->kind == EK_LE || ex->kind == EK_GE || + ex->kind == EK_AND || ex->kind == EK_OR || ex->kind == EK_NOT) + return 2|4; + if (ex->kind == EK_BICALL) { + cp = ex->val.s; + if (!strcmp(cp, "strlen") || + !strcmp(cp, "abs") || + !strcmp(cp, "labs") || + !strcmp(cp, "fabs")) + return 2|4; + } + tp = (ex->kind == EK_VAR) ? ((Meaning *)ex->val.i)->type : ex->val.type; + if (ord_range(ex->val.type, &val.i, NULL)) { + if (val.i > 0) + return 4; + if (val.i >= 0) + return 2|4; + } + if (ord_range(ex->val.type, NULL, &val.i)) { + if (val.i < 0) + return 1; + if (val.i <= 0) + return 1|2; + } + return 1|2|4; +} + + + + + +Expr *dodivmod(funcname, ekind, a, b) +char *funcname; +enum exprkind ekind; +Expr *a, *b; +{ + Meaning *tvar; + Type *type; + Expr *asn; + int sa, sb; + + type = promote_type_bin(a->val.type, b->val.type); + tvar = NULL; + sa = possiblesigns(a); + sb = possiblesigns(b); + if ((sa & 1) || (sb & 1)) { + if (*funcname) { + asn = NULL; + if (*funcname == '*') { + if (exprspeed(a) >= 5 || !nosideeffects(a, 0)) { + tvar = makestmttempvar(a->val.type, name_TEMP); + asn = makeexpr_assign(makeexpr_var(tvar), a); + a = makeexpr_var(tvar); + } + if (exprspeed(b) >= 5 || !nosideeffects(b, 0)) { + tvar = makestmttempvar(b->val.type, name_TEMP); + asn = makeexpr_comma(asn, + makeexpr_assign(makeexpr_var(tvar), + b)); + b = makeexpr_var(tvar); + } + } + return makeexpr_comma(asn, + makeexpr_bicall_2(funcname, type, a, b)); + } else { + if ((sa & 1) && (ekind == EK_MOD)) + note("Using % for possibly-negative arguments [317]"); + return makeexpr_bin(ekind, type, a, b); + } + } else + return makeexpr_bin(ekind, type, a, b); +} + + + +Expr *makeexpr_div(a, b) +Expr *a, *b; +{ + Meaning *mp; + Type *type; + long i; + int p; + + if (ISCONST(a->kind) && ISCONST(b->kind)) { + if (a->val.i >= 0 && b->val.i > 0) { + a->val.i /= b->val.i; + freeexpr(b); + return a; + } + i = gcd(a->val.i, b->val.i); + if (i >= 0) { + a->val.i /= i; + b->val.i /= i; + } + } + if (((b->kind == EK_CONST && (i = b->val.i)) || + (b->kind == EK_VAR && (mp = (Meaning *)b->val.i)->kind == MK_CONST && + mp->val.type && (i = mp->val.i) && foldconsts != 0)) && i > 0) { + if (i == 1) + return a; + if (div_po2 > 0) { + p = 0; + while (!(i&1)) + p++, i >>= 1; + if (i == 1) { + type = promote_type_bin(a->val.type, b->val.type); + return makeexpr_bin(EK_RSH, type, a, makeexpr_long(p)); + } + } + } + if (a->kind == EK_TIMES) { + for (p = 0; p < a->nargs; p++) { + if (exprsame(a->args[p], b, 1)) { + delfreearg(&a, p); + freeexpr(b); + if (a->nargs == 1) + return grabarg(a, 0); + else + return a; + } else if (ISCONST(a->args[p]->kind) && ISCONST(b->kind)) { + i = gcd(a->args[p]->val.i, b->val.i); + if (i > 1) { + a->args[p]->val.i /= i; + b->val.i /= i; + i = a->args[p]->val.i; + delfreearg(&a, p); + a = makeexpr_times(a, makeexpr_long(i)); /* resimplify */ + p = -1; /* start the loop over */ + } + } + } + } + if (checkconst(b, 1)) { + freeexpr(b); + return a; + } else if (checkconst(b, -1)) { + freeexpr(b); + return makeexpr_neg(a); + } else { + if (checkconst(b, 0)) + warning("Division by zero [163]"); + return dodivmod(divname, EK_DIV, a, b); + } +} + + + +Expr *makeexpr_mod(a, b) +Expr *a, *b; +{ + Meaning *mp; + Type *type; + long i; + + if (a->kind == EK_CONST && b->kind == EK_CONST && + a->val.i >= 0 && b->val.i > 0) { + a->val.i %= b->val.i; + freeexpr(b); + return a; + } + if (((b->kind == EK_CONST && (i = b->val.i)) || + (b->kind == EK_VAR && (mp = (Meaning *)b->val.i)->kind == MK_CONST && + mp->val.type && (i = mp->val.i) && foldconsts != 0)) && i > 0) { + if (i == 1) + return makeexpr_long(0); + if (mod_po2 != 0) { + while (!(i&1)) + i >>= 1; + if (i == 1) { + type = promote_type_bin(a->val.type, b->val.type); + return makeexpr_bin(EK_BAND, type, a, + makeexpr_minus(b, makeexpr_long(1))); + } + } + } + if (checkconst(b, 0)) + warning("Division by zero [163]"); + return dodivmod(modname, EK_MOD, a, b); +} + + + +Expr *makeexpr_rem(a, b) +Expr *a, *b; +{ + if (!(possiblesigns(a) & 1) && !(possiblesigns(b) & 1)) + return makeexpr_mod(a, b); + if (checkconst(b, 0)) + warning("Division by zero [163]"); + if (!*remname) + note("Translating REM same as MOD [141]"); + return dodivmod(*remname ? remname : modname, EK_MOD, a, b); +} + + + + + +int expr_not_cost(a) +Expr *a; +{ + int i, c; + + switch (a->kind) { + + case EK_CONST: + return 0; + + case EK_NOT: + return -1; + + case EK_EQ: + case EK_NE: + case EK_LT: + case EK_GT: + case EK_LE: + case EK_GE: + return 0; + + case EK_AND: + case EK_OR: + c = 0; + for (i = 0; i < a->nargs; i++) + c += expr_not_cost(a->args[i]); + return (c > 1) ? 1 : c; + + case EK_BICALL: + if (!strcmp(a->val.s, oddname) || + !strcmp(a->val.s, evenname)) + return 0; + return 1; + + default: + return 1; + } +} + + + +Expr *makeexpr_not(a) +Expr *a; +{ + Expr *ex; + int i; + + if (debug>2) { fprintf(outf,"makeexpr_not("); dumpexpr(a); fprintf(outf,")\n"); } + switch (a->kind) { + + case EK_CONST: + if (a->val.type == tp_boolean) { + a->val.i = !a->val.i; + return a; + } + break; + + case EK_EQ: + a->kind = EK_NE; + return a; + + case EK_NE: + a->kind = EK_EQ; + return a; + + case EK_LT: + a->kind = EK_GE; + return a; + + case EK_GT: + a->kind = EK_LE; + return a; + + case EK_LE: + a->kind = EK_GT; + return a; + + case EK_GE: + a->kind = EK_LT; + return a; + + case EK_AND: + case EK_OR: + if (expr_not_cost(a) > 0) + break; + a->kind = (a->kind == EK_OR) ? EK_AND : EK_OR; + for (i = 0; i < a->nargs; i++) + a->args[i] = makeexpr_not(a->args[i]); + return a; + + case EK_NOT: + ex = a->args[0]; + FREE(a); + ex->val.type = tp_boolean; + return ex; + + case EK_BICALL: + if (!strcmp(a->val.s, oddname) && *evenname) { + strchange(&a->val.s, evenname); + return a; + } else if (!strcmp(a->val.s, evenname)) { + strchange(&a->val.s, oddname); + return a; + } + break; + + default: + break; + } + return makeexpr_un(EK_NOT, tp_boolean, a); +} + + + + +Type *mixsets(ep1, ep2) +Expr **ep1, **ep2; +{ + Expr *ex1 = *ep1, *ex2 = *ep2; + Meaning *tvar; + long min1, max1, min2, max2; + Type *type; + + if (ex1->val.type->kind == TK_SMALLSET && + ex2->val.type->kind == TK_SMALLSET) + return ex1->val.type; + if (ex1->val.type->kind == TK_SMALLSET) { + tvar = makestmttempvar(ex2->val.type, name_SET); + ex1 = makeexpr_bicall_2(setexpandname, ex2->val.type, + makeexpr_var(tvar), + makeexpr_arglong(ex1, 1)); + } + if (ex2->val.type->kind == TK_SMALLSET) { + tvar = makestmttempvar(ex1->val.type, name_SET); + ex2 = makeexpr_bicall_2(setexpandname, ex1->val.type, + makeexpr_var(tvar), + makeexpr_arglong(ex2, 1)); + } + if (ord_range(ex1->val.type->indextype, &min1, &max1) && + ord_range(ex2->val.type->indextype, &min2, &max2)) { + if (min1 <= min2 && max1 >= max2) + type = ex1->val.type; + else if (min2 <= min1 && max2 >= max1) + type = ex2->val.type; + else { + if (min2 < min1) min1 = min2; + if (max2 > max1) max1 = max2; + type = maketype(TK_SET); + type->basetype = tp_integer; + type->indextype = maketype(TK_SUBR); + type->indextype->basetype = ord_type(ex1->val.type->indextype); + type->indextype->smin = makeexpr_long(min1); + type->indextype->smax = makeexpr_long(max1); + } + } else + type = ex1->val.type; + *ep1 = ex1, *ep2 = ex2; + return type; +} + + + +Meaning *istempprocptr(ex) +Expr *ex; +{ + Meaning *mp; + + if (debug>2) { fprintf(outf,"istempprocptr("); dumpexpr(ex); fprintf(outf,")\n"); } + if (ex->kind == EK_COMMA && ex->nargs == 3) { + if ((mp = istempvar(ex->args[2])) != NULL && + mp->type->kind == TK_PROCPTR && + ex->args[0]->kind == EK_ASSIGN && + ex->args[0]->args[0]->kind == EK_DOT && + exprsame(ex->args[0]->args[0]->args[0], ex->args[2], 1) && + ex->args[1]->kind == EK_ASSIGN && + ex->args[1]->args[0]->kind == EK_DOT && + exprsame(ex->args[1]->args[0]->args[0], ex->args[2], 1)) + return mp; + } + if (ex->kind == EK_COMMA && ex->nargs == 2) { + if ((mp = istempvar(ex->args[1])) != NULL && + mp->type->kind == TK_CPROCPTR && + ex->args[0]->kind == EK_ASSIGN && + exprsame(ex->args[0]->args[0], ex->args[1], 1)) + return mp; + } + return NULL; +} + + + + +Expr *makeexpr_stringify(ex) +Expr *ex; +{ + ex = makeexpr_stringcast(ex); + if (ex->val.type->kind == TK_STRING) + return ex; + return makeexpr_sprintfify(ex); +} + + + +Expr *makeexpr_rel(rel, a, b) +enum exprkind rel; +Expr *a, *b; +{ + int i, sign; + Expr *ex, *ex2; + Meaning *mp; + char *name; + + if (debug>2) { fprintf(outf,"makeexpr_rel(%s,", exprkindname(rel)); dumpexpr(a); fprintf(outf,", "); dumpexpr(b); fprintf(outf,")\n"); } + + a = makeexpr_unlongcast(a); + b = makeexpr_unlongcast(b); + if ((compenums == 0 || (compenums < 0 && ansiC <= 0)) && + (rel != EK_EQ && rel != EK_NE)){ + a = enum_to_int(a); + b = enum_to_int(b); + } + if (a->val.type != b->val.type) { + if (a->val.type->kind == TK_STRING && + a->kind != EK_CONST) { + b = makeexpr_stringify(b); + } else if (b->val.type->kind == TK_STRING && + b->kind != EK_CONST) { + a = makeexpr_stringify(a); + } else if (ord_type(a->val.type)->kind == TK_CHAR || + a->val.type->kind == TK_ARRAY) { + b = gentle_cast(b, ord_type(a->val.type)); + } else if (ord_type(b->val.type)->kind == TK_CHAR || + b->val.type->kind == TK_ARRAY) { + a = gentle_cast(a, ord_type(b->val.type)); + } else if (a->val.type == tp_anyptr && !voidstar) { + a = gentle_cast(a, b->val.type); + } else if (b->val.type == tp_anyptr && !voidstar) { + b = gentle_cast(b, a->val.type); + } + } + if (useisspace && b->val.type->kind == TK_CHAR && checkconst(b, ' ')) { + if (rel == EK_EQ) { + freeexpr(b); + return makeexpr_bicall_1("isspace", tp_boolean, a); + } else if (rel == EK_NE) { + freeexpr(b); + return makeexpr_not(makeexpr_bicall_1("isspace", tp_boolean, a)); + } + } + if (rel == EK_LT || rel == EK_GE) + sign = 1; + else if (rel == EK_GT || rel == EK_LE) + sign = -1; + else + sign = 0; + if (ord_type(b->val.type)->kind == TK_INTEGER || + ord_type(b->val.type)->kind == TK_CHAR) { + for (;;) { + if (a->kind == EK_PLUS && ISCONST(a->args[a->nargs-1]->kind) && + a->args[a->nargs-1]->val.i && + (ISCONST(b->kind) || + (b->kind == EK_PLUS && ISCONST(b->args[b->nargs-1]->kind)))) { + b = makeexpr_minus(b, copyexpr(a->args[a->nargs-1])); + a = makeexpr_minus(a, copyexpr(a->args[a->nargs-1])); + continue; + } + if (b->kind == EK_PLUS && ISCONST(b->args[b->nargs-1]->kind) && + b->args[b->nargs-1]->val.i && + ISCONST(a->kind)) { + a = makeexpr_minus(a, copyexpr(b->args[b->nargs-1])); + b = makeexpr_minus(b, copyexpr(b->args[b->nargs-1])); + continue; + } + if (b->kind == EK_PLUS && sign && + ISCONST(b->args[b->nargs-1]->kind) && + checkconst(b->args[b->nargs-1], sign)) { + b = makeexpr_plus(b, makeexpr_long(-sign)); + switch (rel) { + case EK_LT: + rel = EK_LE; + break; + case EK_GT: + rel = EK_GE; + break; + case EK_LE: + rel = EK_LT; + break; + case EK_GE: + rel = EK_GT; + break; + default: + break; + } + sign = -sign; + continue; + } + if (a->kind == EK_TIMES && checkconst(b, 0) && !sign) { + for (i = 0; i < a->nargs; i++) { + if (ISCONST(a->args[i]->kind) && a->args[i]->val.i) + break; + if (a->args[i]->kind == EK_SIZEOF) + break; + } + if (i < a->nargs) { + delfreearg(&a, i); + continue; + } + } + break; + } + if (a->kind == EK_BICALL && !strcmp(a->val.s, "strlen") && + checkconst(b, 0)) { + if (rel == EK_LT || rel == EK_GE) { + note("Unusual use of STRLEN encountered [142]"); + } else { + freeexpr(b); + a = makeexpr_hat(grabarg(a, 0), 0); + b = makeexpr_char(0); /* "strlen(a) = 0" => "*a == 0" */ + if (rel == EK_EQ || rel == EK_LE) + return makeexpr_rel(EK_EQ, a, b); + else + return makeexpr_rel(EK_NE, a, b); + } + } + if (ISCONST(a->kind) && ISCONST(b->kind)) { + if ((a->val.i == b->val.i && (rel == EK_EQ || rel == EK_GE || rel == EK_LE)) || + (a->val.i < b->val.i && (rel == EK_NE || rel == EK_LE || rel == EK_LT)) || + (a->val.i > b->val.i && (rel == EK_NE || rel == EK_GE || rel == EK_GT))) + return makeexpr_val(make_ord(tp_boolean, 1)); + else + return makeexpr_val(make_ord(tp_boolean, 0)); + } + if ((a->val.type == tp_char || true_type(a) == tp_char) && + ISCONST(b->kind) && signedchars != 0) { + i = (b->val.i == 128 && sign == 1) || + (b->val.i == 127 && sign == -1); + if (highcharbits && (highcharbits > 0 || signedchars < 0) && i) { + if (highcharbits == 2) + b = makeexpr_long(128); + else + b = makeexpr_un(EK_BNOT, tp_integer, makeexpr_long(127)); + return makeexpr_rel((rel == EK_GE || rel == EK_GT) + ? EK_NE : EK_EQ, + makeexpr_bin(EK_BAND, tp_integer, + eatcasts(a), b), + makeexpr_long(0)); + } else if (signedchars == 1 && i) { + return makeexpr_rel((rel == EK_GE || rel == EK_GT) + ? EK_LT : EK_GE, + eatcasts(a), makeexpr_long(0)); + } else if (signedchars == 1 && b->val.i >= 128 && sign == 0) { + b->val.i -= 256; + } else if (b->val.i >= 128 || + (b->val.i == 127 && sign != 0)) { + if (highcharbits && (highcharbits > 0 || signedchars < 0)) + a = makeexpr_bin(EK_BAND, a->val.type, eatcasts(a), + makeexpr_long(255)); + else + a = force_unsigned(a); + } + } + } else if (a->val.type->kind == TK_STRING && + b->val.type->kind == TK_STRING) { + if (b->kind == EK_CONST && b->val.i == 0 && !sign) { + a = makeexpr_hat(a, 0); + b = makeexpr_char(0); /* "a = ''" => "*a == 0" */ + } else { + a = makeexpr_bicall_2("strcmp", tp_int, a, b); + b = makeexpr_long(0); + } + } else if ((a->val.type->kind == TK_ARRAY || + a->val.type->kind == TK_STRING || + a->val.type->kind == TK_RECORD) && + (b->val.type->kind == TK_ARRAY || + b->val.type->kind == TK_STRING || + b->val.type->kind == TK_RECORD)) { + if (a->val.type->kind == TK_ARRAY) { + if (b->val.type->kind == TK_ARRAY) { + ex = makeexpr_sizeof(copyexpr(a), 0); + ex2 = makeexpr_sizeof(copyexpr(b), 0); + if (!exprsame(ex, ex2, 1)) + warning("Incompatible array sizes [164]"); + freeexpr(ex2); + } else { + ex = makeexpr_sizeof(copyexpr(a), 0); + } + } else + ex = makeexpr_sizeof(copyexpr(b), 0); + name = (usestrncmp && + a->val.type->kind == TK_ARRAY && + a->val.type->basetype->kind == TK_CHAR) ? "strncmp" : "memcmp"; + a = makeexpr_bicall_3(name, tp_int, + makeexpr_addr(a), + makeexpr_addr(b), ex); + b = makeexpr_long(0); + } else if (a->val.type->kind == TK_SET || + a->val.type->kind == TK_SMALLSET) { + if (rel == EK_GE) { + swapexprs(a, b); + rel = EK_LE; + } + if (mixsets(&a, &b)->kind == TK_SMALLSET) { + if (rel == EK_LE) { + a = makeexpr_bin(EK_BAND, tp_integer, + a, makeexpr_un(EK_BNOT, tp_integer, b)); + b = makeexpr_long(0); + rel = EK_EQ; + } + } else if (b->kind == EK_BICALL && + !strcmp(b->val.s, setexpandname) && + (mp = istempvar(b->args[0])) != NULL && + checkconst(b->args[1], 0)) { + canceltempvar(mp); + a = makeexpr_hat(a, 0); + b = grabarg(b, 1); + if (rel == EK_LE) + rel = EK_EQ; + } else { + ex = makeexpr_bicall_2((rel == EK_LE) ? subsetname : setequalname, + tp_boolean, a, b); + return (rel == EK_NE) ? makeexpr_not(ex) : ex; + } + } else if (a->val.type->kind == TK_PROCPTR || + a->val.type->kind == TK_CPROCPTR) { + /* we compare proc only (not link) -- same as Pascal compiler! */ + if (a->val.type->kind == TK_PROCPTR) + a = makeexpr_dotq(a, "proc", tp_anyptr); + if ((mp = istempprocptr(b)) != NULL) { + canceltempvar(mp); + b = grabarg(grabarg(b, 0), 1); + if (!voidstar) + b = makeexpr_cast(b, tp_anyptr); + } else if (b->val.type->kind == TK_PROCPTR) + b = makeexpr_dotq(b, "proc", tp_anyptr); + } + return makeexpr_bin(rel, tp_boolean, a, b); +} + + + + +Expr *makeexpr_and(a, b) +Expr *a, *b; +{ + Expr *ex, **exp, *low; + + if (!a) + return b; + if (!b) + return a; + for (exp = &a; (ex = *exp)->kind == EK_AND; exp = &ex->args[1]) ; + if ((b->kind == EK_LT || b->kind == EK_LE) && + ((ex->kind == EK_LE && exprsame(ex->args[1], b->args[0], 1)) || + (ex->kind == EK_GE && exprsame(ex->args[0], b->args[0], 1)))) { + low = (ex->kind == EK_LE) ? ex->args[0] : ex->args[1]; + if (unsignedtrick && checkconst(low, 0)) { + freeexpr(ex); + b->args[0] = force_unsigned(b->args[0]); + *exp = b; + return a; + } + if (b->args[1]->val.type->kind == TK_CHAR && useisalpha) { + if (checkconst(low, 'A') && checkconst(b->args[1], 'Z')) { + freeexpr(ex); + *exp = makeexpr_bicall_1("isupper", tp_boolean, grabarg(b, 0)); + return a; + } + if (checkconst(low, 'a') && checkconst(b->args[1], 'z')) { + freeexpr(ex); + *exp = makeexpr_bicall_1("islower", tp_boolean, grabarg(b, 0)); + return a; + } + if (checkconst(low, '0') && checkconst(b->args[1], '9')) { + freeexpr(ex); + *exp = makeexpr_bicall_1("isdigit", tp_boolean, grabarg(b, 0)); + return a; + } + } + } + return makeexpr_bin(EK_AND, tp_boolean, a, b); +} + + + +Expr *makeexpr_or(a, b) +Expr *a, *b; +{ + Expr *ex, **exp, *low; + + if (!a) + return b; + if (!b) + return a; + for (exp = &a; (ex = *exp)->kind == EK_OR; exp = &ex->args[1]) ; + if (((b->kind == EK_BICALL && !strcmp(b->val.s, "isdigit") && + ex->kind == EK_BICALL && !strcmp(ex->val.s, "isalpha")) || + (b->kind == EK_BICALL && !strcmp(b->val.s, "isalpha") && + ex->kind == EK_BICALL && !strcmp(ex->val.s, "isdigit"))) && + exprsame(ex->args[0], b->args[0], 1)) { + strchange(&ex->val.s, "isalnum"); + freeexpr(b); + return a; + } + if (((b->kind == EK_BICALL && !strcmp(b->val.s, "islower") && + ex->kind == EK_BICALL && !strcmp(ex->val.s, "isupper")) || + (b->kind == EK_BICALL && !strcmp(b->val.s, "isupper") && + ex->kind == EK_BICALL && !strcmp(ex->val.s, "islower"))) && + exprsame(ex->args[0], b->args[0], 1)) { + strchange(&ex->val.s, "isalpha"); + freeexpr(b); + return a; + } + if ((b->kind == EK_GT || b->kind == EK_GE) && + ((ex->kind == EK_GT && exprsame(ex->args[1], b->args[0], 1)) || + (ex->kind == EK_LT && exprsame(ex->args[0], b->args[0], 1)))) { + low = (ex->kind == EK_GT) ? ex->args[0] : ex->args[1]; + if (unsignedtrick && checkconst(low, 0)) { + freeexpr(ex); + b->args[0] = force_unsigned(b->args[0]); + *exp = b; + return a; + } + } + return makeexpr_bin(EK_OR, tp_boolean, a, b); +} + + + +Expr *makeexpr_range(ex, exlow, exhigh, higheq) +Expr *ex, *exlow, *exhigh; +int higheq; +{ + Expr *ex2; + enum exprkind rel = (higheq) ? EK_LE : EK_LT; + + if (exprsame(exlow, exhigh, 1) && higheq) + return makeexpr_rel(EK_EQ, ex, exlow); + ex2 = makeexpr_rel(rel, copyexpr(ex), exhigh); + if (lelerange) + return makeexpr_and(makeexpr_rel(EK_LE, exlow, ex), ex2); + else + return makeexpr_and(makeexpr_rel(EK_GE, ex, exlow), ex2); +} + + + + +Expr *makeexpr_cond(c, a, b) +Expr *c, *a, *b; +{ + Expr *ex; + + ex = makeexpr(EK_COND, 3); + ex->val.type = a->val.type; + ex->args[0] = c; + ex->args[1] = a; + ex->args[2] = b; + if (debug>2) { fprintf(outf,"makeexpr_cond returns "); dumpexpr(ex); fprintf(outf,"\n"); } + return ex; +} + + + + +int expr_is_lvalue(ex) +Expr *ex; +{ + Meaning *mp; + + switch (ex->kind) { + + case EK_VAR: + mp = (Meaning *)ex->val.i; + return (mp->kind == MK_VAR || mp->kind == MK_PARAM || + mp->kind == MK_VARPARAM || + (mp->kind == MK_CONST && + (mp->type->kind == TK_ARRAY || + mp->type->kind == TK_RECORD || + mp->type->kind == TK_SET))); + + case EK_HAT: + case EK_NAME: + return 1; + + case EK_INDEX: + case EK_DOT: + return expr_is_lvalue(ex->args[0]); + + case EK_COMMA: + return expr_is_lvalue(ex->args[ex->nargs-1]); + + default: + return 0; + } +} + + +int expr_has_address(ex) +Expr *ex; +{ + if (ex->kind == EK_DOT && + ((Meaning *)ex->val.i)->val.i) + return 0; /* bit fields do not have an address */ + return expr_is_lvalue(ex); +} + + + +Expr *checknil(ex) +Expr *ex; +{ + if (nilcheck == 1) { + if (singlevar(ex)) { + ex = makeexpr_un(EK_CHECKNIL, ex->val.type, ex); + } else { + ex = makeexpr_bin(EK_CHECKNIL, ex->val.type, ex, + makeexpr_var(makestmttempvar(ex->val.type, + name_PTR))); + } + } + return ex; +} + + +int checkvarinlists(yes, no, def, mp) +Strlist *yes, *no; +int def; +Meaning *mp; +{ + char *cp; + Meaning *ctx; + + if (mp->kind == MK_FIELD) + ctx = mp->rectype->meaning; + else + ctx = mp->ctx; + if (ctx && ctx->name) + cp = format_ss("%s.%s", ctx->name, mp->name); + else + cp = NULL; + if (strlist_cifind(yes, cp)) + return 1; + if (strlist_cifind(no, cp)) + return 0; + if (strlist_cifind(yes, mp->name)) + return 1; + if (strlist_cifind(no, mp->name)) + return 0; + if (strlist_cifind(yes, "1")) + return 1; + if (strlist_cifind(no, "1")) + return 0; + return def; +} + + +void requirefilebuffer(ex) +Expr *ex; +{ + Meaning *mp; + + if (!isfiletype(ex->val.type, 0)) + return; + mp = isfilevar(ex); + if (!mp) { + if (ex->kind == EK_HAT) + ex = ex->args[0]; + if (ex->kind == EK_VAR) { + mp = (Meaning *)ex->val.i; + if (mp->kind == MK_PARAM || mp->kind == MK_VARPARAM) + note(format_s("File parameter %s can't access buffers (try StructFiles = 1) [318]", + mp->name)); + } + } else if (!mp->bufferedfile && + checkvarinlists(bufferedfiles, unbufferedfiles, 1, mp)) { + if (mp->wasdeclared) + note(format_s("Discovered too late that %s should be buffered [143]", + mp->name)); + mp->bufferedfile = 1; + } +} + + +Expr *makeexpr_hat(a, check) +Expr *a; +int check; +{ + Expr *ex; + + if (debug>2) { fprintf(outf,"makeexpr_hat("); dumpexpr(a); fprintf(outf,")\n"); } + if (isfiletype(a->val.type, -1)) { + requirefilebuffer(a); + if (*chargetfbufname && + filebasetype(a->val.type)->kind == TK_CHAR) + return makeexpr_bicall_1(chargetfbufname, + filebasetype(a->val.type), + filebasename(a)); + else if (*arraygetfbufname && + filebasetype(a->val.type)->kind == TK_ARRAY) + return makeexpr_bicall_2(arraygetfbufname, + filebasetype(a->val.type), + filebasename(a), + makeexpr_type(filebasetype(a->val.type))); + else + return makeexpr_bicall_2(getfbufname, + filebasetype(a->val.type), + filebasename(a), + makeexpr_type(filebasetype(a->val.type))); + } + if (a->kind == EK_PLUS && + (ex = a->args[0])->val.type->kind == TK_POINTER && + (ex->val.type->basetype->kind == TK_ARRAY || + ex->val.type->basetype->kind == TK_STRING || + ex->val.type->basetype->kind == TK_SET)) { + ex->val.type = ex->val.type->basetype; /* convert *(a+n) to a[n] */ + deletearg(&a, 0); + if (a->nargs == 1) + a = grabarg(a, 0); + return makeexpr_bin(EK_INDEX, ex->val.type->basetype, ex, a); + } + if (a->val.type->kind == TK_STRING || + a->val.type->kind == TK_ARRAY || + a->val.type->kind == TK_SET) { + if (starindex == 0) + return makeexpr_bin(EK_INDEX, a->val.type->basetype, a, makeexpr_long(0)); + else + return makeexpr_un(EK_HAT, a->val.type->basetype, a); + } + if (a->val.type->kind != TK_POINTER || !a->val.type->basetype) { + warning("bad pointer dereference [165]"); + return a; + } + if (a->kind == EK_CAST && + a->val.type->basetype->kind == TK_POINTER && + a->args[0]->val.type->kind == TK_POINTER && + a->args[0]->val.type->basetype->kind == TK_POINTER) { + return makeexpr_cast(makeexpr_hat(a->args[0], 0), + a->val.type->basetype); + } + switch (a->val.type->basetype->kind) { + + case TK_ARRAY: + case TK_STRING: + case TK_SET: + if (a->kind != EK_HAT || 1 || + a->val.type == a->args[0]->val.type->basetype) { + a->val.type = a->val.type->basetype; + return a; + } + + default: + if (a->kind == EK_ADDR) { + ex = a->args[0]; + FREE(a); + return ex; + } else { + if (check) + ex = checknil(a); + else + ex = a; + return makeexpr_un(EK_HAT, a->val.type->basetype, ex); + } + } +} + + + +Expr *un_sign_extend(a) +Expr *a; +{ + if (a->kind == EK_BICALL && + !strcmp(a->val.s, signextname) && *signextname) { + return grabarg(a, 0); + } + return a; +} + + + +Expr *makeexpr_addr(a) +Expr *a; +{ + Expr *ex; + Type *type; + Meaning *mp; + + a = un_sign_extend(a); + type = makepointertype(a->val.type); + if (debug>2) { fprintf(outf,"makeexpr_addr("); dumpexpr(a); fprintf(outf,", "); dumptypename(type, 1); fprintf(outf,")\n"); } + if (a->kind == EK_CONST && a->val.type->kind == TK_STRING) { + return a; /* kludge to help assignments */ + } else if (a->kind == EK_INDEX && + (a->val.type->kind != TK_ARRAY && + a->val.type->kind != TK_SET && + a->val.type->kind != TK_STRING) && + (addindex == 1 || + (addindex != 0 && checkconst(a->args[1], 0)))) { + ex = makeexpr_plus(makeexpr_addr(a->args[0]), a->args[1]); + FREE(a); + ex->val.type = type; + return ex; + } else if (a->kind == EK_CAST) { + return makeexpr_cast(makeexpr_addr(a->args[0]), type); + } else if (a->kind == EK_ACTCAST) { + return makeexpr_actcast(makeexpr_addr(a->args[0]), type); + } else if (a->kind == EK_LITCAST) { + if (a->args[0]->kind == EK_NAME) { + if (my_strchr(a->args[0]->val.s, '(') || + my_strchr(a->args[0]->val.s, '[')) + note("Constructing pointer type by adding '*' may be incorrect [322]"); + return makeexpr_bin(EK_LITCAST, tp_integer, + makeexpr_name(format_s("%s*", + a->args[0]->val.s), + tp_integer), + makeexpr_addr(a->args[1])); + } else + return makeexpr_bin(EK_LITCAST, tp_integer, makeexpr_type(type), + makeexpr_addr(a->args[1])); + } else { + switch (a->val.type->kind) { + + case TK_ARRAY: + case TK_STRING: + case TK_SET: + if (a->val.type->smin) { + return makeexpr_un(EK_ADDR, type, + makeexpr_index(a, + copyexpr(a->val.type->smin), + NULL)); + } + a->val.type = type; + return a; + + default: + if (a->kind == EK_HAT) { + ex = a->args[0]; + FREE(a); + return ex; + } else if (a->kind == EK_ACTCAST) + return makeexpr_actcast(makeexpr_addr(grabarg(a, 0)), type); + else if (a->kind == EK_CAST) + return makeexpr_cast(makeexpr_addr(grabarg(a, 0)), type); + else { + if (a->kind == EK_VAR && + (mp = (Meaning *)a->val.i)->kind == MK_PARAM && + mp->type != promote_type(mp->type) && + fixpromotedargs) { + note(format_s("Taking & of possibly promoted param %s [324]", + mp->name)); + if (fixpromotedargs == 1) { + mp->varstructflag = 1; + mp->ctx->varstructflag = 1; + } + } + return makeexpr_un(EK_ADDR, type, a); + } + } + } +} + + + +Expr *makeexpr_addrstr(a) +Expr *a; +{ + if (debug>2) { fprintf(outf,"makeexpr_addrstr("); dumpexpr(a); fprintf(outf,")\n"); } + if (a->val.type->kind == TK_POINTER) + return a; + return makeexpr_addr(a); +} + + + +Expr *makeexpr_addrf(a) +Expr *a; +{ + Meaning *mp, *tvar; + + mp = (Meaning *)a->val.i; + if (is_std_file(a)) { + if (addrstdfiles == 0) { + note(format_s("Taking address of %s; consider setting VarFiles = 0 [144]", + (a->kind == EK_VAR) ? ((Meaning *)a->val.i)->name + : a->val.s)); + tvar = makestmttempvar(tp_text, name_TEMP); + return makeexpr_comma(makeexpr_assign(makeexpr_var(tvar), a), + makeexpr_addr(makeexpr_var(tvar))); + } + } + if ((a->kind == EK_VAR && + mp->kind == MK_FIELD && mp->val.i) || + (a->kind == EK_BICALL && + !strcmp(a->val.s, getbitsname))) { + warning("Can't take the address of a bit-field [166]"); + } + return makeexpr_addr(a); +} + + + +Expr *makeexpr_index(a, b, offset) +Expr *a, *b, *offset; +{ + Type *indextype, *btype; + + if (debug>2) { fprintf(outf,"makeexpr_index("); dumpexpr(a); fprintf(outf,", "); dumpexpr(b); + fprintf(outf,", "); dumpexpr(offset); fprintf(outf,")\n"); } + indextype = (a->val.type->kind == TK_ARRAY) ? a->val.type->indextype + : tp_integer; + b = gentle_cast(b, indextype); + if (!offset) + offset = makeexpr_long(0); + b = makeexpr_minus(b, gentle_cast(offset, indextype)); + btype = a->val.type; + if (btype->basetype) + btype = btype->basetype; + if (checkconst(b, 0) && starindex == 1) + return makeexpr_un(EK_HAT, btype, a); + else + return makeexpr_bin(EK_INDEX, btype, a, + gentle_cast(b, indextype)); +} + + + +Expr *makeexpr_type(type) +Type *type; +{ + Expr *ex; + + ex = makeexpr(EK_TYPENAME, 0); + ex->val.type = type; + return ex; +} + + +Expr *makeexpr_sizeof(ex, incskipped) +Expr *ex; +int incskipped; +{ + Expr *ex2, *ex3; + Type *btype; + char *name; + + if (ex->val.type->meaning) { + name = find_special_variant(ex->val.type->meaning->name, + "SpecialSizeOf", specialsizeofs, 1); + if (name) { + freeexpr(ex); + return pc_expr_str(name); + } + } + switch (ex->val.type->kind) { + + case TK_CHAR: + case TK_BOOLEAN: + freeexpr(ex); + return makeexpr_long(1); + + case TK_SUBR: + btype = findbasetype(ex->val.type, ODECL_NOPRES); + if (btype->kind == TK_CHAR || btype == tp_abyte) { + freeexpr(ex); + return makeexpr_long(1); + } + break; + + case TK_STRING: + case TK_ARRAY: + if (!ex->val.type->meaning || ex->val.type->kind == TK_STRING || + (!incskipped && ex->val.type->smin)) { + ex3 = arraysize(ex->val.type, incskipped); + return makeexpr_times(ex3, + makeexpr_sizeof(makeexpr_type( + ex->val.type->basetype), 1)); + } + break; + + case TK_SET: + ord_range_expr(ex->val.type->indextype, NULL, &ex2); + freeexpr(ex); + return makeexpr_times(makeexpr_plus(makeexpr_div(copyexpr(ex2), + makeexpr_setbits()), + makeexpr_long(2)), + makeexpr_sizeof(makeexpr_type(tp_integer), 0)); + + default: + break; + } + if (ex->kind != EK_CONST && + (findbasetype(ex->val.type,0)->meaning || /* if type has a name... */ + ex->val.type->kind == TK_STRING || /* if C sizeof(expr) will give wrong answer */ + ex->val.type->kind == TK_ARRAY || + ex->val.type->kind == TK_SET)) { + ex2 = makeexpr_type(ex->val.type); + freeexpr(ex); + ex = ex2; + } + return makeexpr_un(EK_SIZEOF, tp_integer, ex); +} + + + + +/* Compute a measure of how fast or slow the expression is likely to be. + 0 is a constant, 1 is a variable, extra points added per "operation". */ + +int exprspeed(ex) +Expr *ex; +{ + Meaning *mp, *mp2; + int i, cost, speed; + + switch (ex->kind) { + + case EK_VAR: + mp = (Meaning *)ex->val.i; + if (mp->kind == MK_CONST) + return 0; + if (!mp->ctx || mp->ctx->kind == MK_FUNCTION) + return 1; + i = 1; + for (mp2 = curctx; mp2 && mp2 != mp->ctx; mp2 = mp2->ctx) + i++; /* cost of following static links */ + return (i); + + case EK_CONST: + case EK_LONGCONST: + case EK_SIZEOF: + return 0; + + case EK_ADDR: + speed = exprspeed(ex->args[0]); + return (speed > 1) ? speed : 0; + + case EK_DOT: + return exprspeed(ex->args[0]); + + case EK_NEG: + return exprspeed(ex->args[0]) + 1; + + case EK_CAST: + case EK_ACTCAST: + i = (ord_type(ex->val.type)->kind == TK_REAL) != + (ord_type(ex->args[0]->val.type)->kind == TK_REAL); + return (i + exprspeed(ex->args[0])); + + case EK_COND: + return 2 + exprspeed(ex->args[0]) + + MAX(exprspeed(ex->args[1]), exprspeed(ex->args[2])); + + case EK_AND: + case EK_OR: + case EK_COMMA: + speed = 2; + for (i = 0; i < ex->nargs; i++) + speed += exprspeed(ex->args[i]); + return speed; + + case EK_FUNCTION: + case EK_BICALL: + case EK_SPCALL: + return 1000; + + case EK_ASSIGN: + case EK_POSTINC: + case EK_POSTDEC: + return 100 + exprspeed(ex->args[0]) + exprspeed(ex->args[1]); + + default: + cost = (ex->kind == EK_PLUS) ? 1 : 2; + if (ex->val.type->kind == TK_REAL) + cost *= 2; + speed = -cost; + for (i = 0; i < ex->nargs; i++) { + if (!isliteralconst(ex->args[i], NULL) || + ex->val.type->kind == TK_REAL) + speed += exprspeed(ex->args[i]) + cost; + } + return MAX(speed, 0); + } +} + + + + +int noargdependencies(ex, vars) +Expr *ex; +int vars; +{ + int i; + + for (i = 0; i < ex->nargs; i++) { + if (!nodependencies(ex->args[i], vars)) + return 0; + } + return 1; +} + + +int nodependencies(ex, vars) +Expr *ex; +int vars; /* 1 if explicit dependencies on vars count as dependencies */ +{ /* 2 if global but not local vars count as dependencies */ + Meaning *mp; + + if (debug>2) { fprintf(outf,"nodependencies("); dumpexpr(ex); fprintf(outf,")\n"); } + if (!noargdependencies(ex, vars)) + return 0; + switch (ex->kind) { + + case EK_VAR: + mp = (Meaning *)ex->val.i; + if (mp->kind == MK_CONST) + return 1; + if (vars == 2 && + mp->ctx == curctx && + mp->ctx->kind == MK_FUNCTION && + !mp->varstructflag) + return 1; + return (mp->kind == MK_CONST || + (!vars && + (mp->kind == MK_VAR || mp->kind == MK_VARREF || + mp->kind == MK_PARAM || mp->kind == MK_VARPARAM))); + + case EK_BICALL: + return nosideeffects_func(ex); + + case EK_FUNCTION: + case EK_SPCALL: + case EK_ASSIGN: + case EK_POSTINC: + case EK_POSTDEC: + case EK_HAT: + case EK_INDEX: + return 0; + + default: + return 1; + } +} + + + +int exprdependsvar(ex, mp) +Expr *ex; +Meaning *mp; +{ + int i; + + i = ex->nargs; + while (--i >= 0) + if (exprdependsvar(ex->args[i], mp)) + return 1; + switch (ex->kind) { + + case EK_VAR: + return ((Meaning *)ex->val.i == mp); + + case EK_BICALL: + if (nodependencies(ex, 1)) + return 0; + + /* fall through */ + case EK_FUNCTION: + case EK_SPCALL: + return (mp->ctx != curctx || + mp->ctx->kind != MK_FUNCTION || + mp->varstructflag); + + case EK_HAT: + return 1; + + default: + return 0; + } +} + + +int exprdepends(ex, ex2) +Expr *ex, *ex2; /* Expression ex somehow depends on value of ex2 */ +{ + switch (ex2->kind) { + + case EK_VAR: + return exprdependsvar(ex, (Meaning *)ex2->val.i); + + case EK_CONST: + case EK_LONGCONST: + return 0; + + case EK_INDEX: + case EK_DOT: + return exprdepends(ex, ex2->args[0]); + + default: + return !nodependencies(ex, 1); + } +} + + +int nosideeffects_func(ex) +Expr *ex; +{ + Meaning *mp; + Symbol *sp; + + switch (ex->kind) { + + case EK_FUNCTION: + mp = (Meaning *)ex->val.i; + sp = findsymbol_opt(mp->name); + return sp && (sp->flags & (NOSIDEEFF|DETERMF)); + + case EK_BICALL: + sp = findsymbol_opt(ex->val.s); + return sp && (sp->flags & (NOSIDEEFF|DETERMF)); + + default: + return 0; + } +} + + + +int deterministic_func(ex) +Expr *ex; +{ + Meaning *mp; + Symbol *sp; + + switch (ex->kind) { + + case EK_FUNCTION: + mp = (Meaning *)ex->val.i; + sp = findsymbol_opt(mp->name); + return sp && (sp->flags & DETERMF); + + case EK_BICALL: + sp = findsymbol_opt(ex->val.s); + return sp && (sp->flags & DETERMF); + + default: + return 0; + } +} + + + + +int noargsideeffects(ex, mode) +Expr *ex; +int mode; +{ + int i; + + for (i = 0; i < ex->nargs; i++) { + if (!nosideeffects(ex->args[i], mode)) + return 0; + } + return 1; +} + + +/* mode=0: liberal about bicall's: safe unless sideeffects_bicall() */ +/* mode=1: conservative about bicall's: must be explicitly NOSIDEEFF */ + +int nosideeffects(ex, mode) +Expr *ex; +int mode; +{ + if (debug>2) { fprintf(outf,"nosideeffects("); dumpexpr(ex); fprintf(outf,")\n"); } + if (!noargsideeffects(ex, mode)) + return 0; + switch (ex->kind) { + + case EK_BICALL: + if (mode == 0) + return !sideeffects_bicall(ex->val.s); + + /* fall through */ + case EK_FUNCTION: + return nosideeffects_func(ex); + + case EK_SPCALL: + case EK_ASSIGN: + case EK_POSTINC: + case EK_POSTDEC: + return 0; + + default: + return 1; + } +} + + + +int exproccurs(ex, ex2) +Expr *ex, *ex2; +{ + int i, count = 0; + + if (debug>2) { fprintf(outf,"exproccurs("); dumpexpr(ex); fprintf(outf,", "); dumpexpr(ex2); fprintf(outf,")\n"); } + for (i = 0; i < ex->nargs; i++) + count += exproccurs(ex->args[i], ex2); + if (exprsame(ex, ex2, 0)) + count++; + return count; +} + + + +Expr *singlevar(ex) +Expr *ex; +{ + if (debug>2) { fprintf(outf,"singlevar("); dumpexpr(ex); fprintf(outf,")\n"); } + switch (ex->kind) { + + case EK_VAR: + case EK_MACARG: + return ex; + + case EK_HAT: + case EK_ADDR: + case EK_DOT: + return singlevar(ex->args[0]); + + case EK_INDEX: +#if 0 + if (!nodependencies(ex->args[1], 1)) + return NULL; +#endif + return singlevar(ex->args[0]); + + default: + return NULL; + } +} + + + +/* Is "ex" a function which takes a return buffer pointer as its + first argument, and returns a copy of that pointer? */ + +int structuredfunc(ex) +Expr *ex; +{ + Meaning *mp; + Symbol *sp; + + if (debug>2) { fprintf(outf,"structuredfunc("); dumpexpr(ex); fprintf(outf,")\n"); } + switch (ex->kind) { + + case EK_FUNCTION: + mp = (Meaning *)ex->val.i; + if (mp->isfunction && mp->cbase && mp->cbase->kind == MK_VARPARAM) + return 1; + sp = findsymbol_opt(mp->name); + return sp && (sp->flags & (STRUCTF|STRLAPF)); + + case EK_BICALL: + sp = findsymbol_opt(ex->val.s); + return sp && (sp->flags & (STRUCTF|STRLAPF)); + + default: + return 0; + } +} + + + +int strlapfunc(ex) +Expr *ex; +{ + Meaning *mp; + Symbol *sp; + + switch (ex->kind) { + + case EK_FUNCTION: + mp = (Meaning *)ex->val.i; + sp = findsymbol_opt(mp->name); + return sp && (sp->flags & STRLAPF); + + case EK_BICALL: + sp = findsymbol_opt(ex->val.s); + return sp && (sp->flags & STRLAPF); + + default: + return 0; + } +} + + + +Meaning *istempvar(ex) +Expr *ex; +{ + Meaning *mp; + + if (debug>2) { fprintf(outf,"istempvar("); dumpexpr(ex); fprintf(outf,")\n"); } + if (ex->kind == EK_VAR) { + mp = (Meaning *)ex->val.i; + if (mp->istemporary) + return mp; + else + return NULL; + } + return NULL; +} + + +Meaning *totempvar(ex) +Expr *ex; +{ + while (structuredfunc(ex)) + ex = ex->args[0]; + return istempvar(ex); +} + + + +Meaning *isretvar(ex) +Expr *ex; +{ + Meaning *mp; + + if (debug>2) { fprintf(outf,"isretvar("); dumpexpr(ex); fprintf(outf,")\n"); } + if (ex->kind == EK_HAT) + ex = ex->args[0]; + if (ex->kind == EK_VAR) { + mp = (Meaning *)ex->val.i; + if (mp->ctx && mp->ctx->kind == MK_FUNCTION && + mp->ctx->isfunction && mp == mp->ctx->cbase) + return mp; + else + return NULL; + } + return NULL; +} + + + +Expr *bumpstring(ex, index, offset) +Expr *ex, *index; +int offset; +{ + if (checkconst(index, offset)) { + freeexpr(index); + return ex; + } + if (addindex != 0) + ex = makeexpr_plus(makeexpr_addrstr(ex), + makeexpr_minus(index, makeexpr_long(offset))); + else + ex = makeexpr_addr(makeexpr_index(ex, index, makeexpr_long(offset))); + ex->val.type = tp_str255; + return ex; +} + + + +long po2m1(n) +int n; +{ + if (n == 32) + return -1; + else if (n == 31) + return 0x7fffffff; + else + return (1<<n) - 1; +} + + + +int isarithkind(kind) +enum exprkind kind; +{ + return (kind == EK_EQ || kind == EK_LT || kind == EK_GT || + kind == EK_NE || kind == EK_LE || kind == EK_GE || + kind == EK_PLUS || kind == EK_TIMES || kind == EK_DIVIDE || + kind == EK_DIV || kind == EK_MOD || kind == EK_NEG || + kind == EK_AND || kind == EK_OR || kind == EK_NOT || + kind == EK_BAND || kind == EK_BOR || kind == EK_BXOR || + kind == EK_LSH || kind == EK_RSH || kind == EK_BNOT || + kind == EK_FUNCTION || kind == EK_BICALL); +} + + +Expr *makeexpr_assign(a, b) +Expr *a, *b; +{ + int i, j; + Expr *ex, *ex2, *ex3, **ep; + Meaning *mp; + Type *tp; + + if (debug>2) { fprintf(outf,"makeexpr_assign("); dumpexpr(a); fprintf(outf,", "); dumpexpr(b); fprintf(outf,")\n"); } + if (stringtrunclimit > 0 && + a->val.type->kind == TK_STRING && + (i = strmax(a)) <= stringtrunclimit && + strmax(b) > i) { + note("Possible string truncation in assignment [145]"); + } + a = un_sign_extend(a); + b = gentle_cast(b, a->val.type); + if (b->kind == EK_BICALL && !strcmp(b->val.s, "sprintf") && + (mp = istempvar(b->args[0])) != NULL && + b->nargs >= 2 && + b->args[1]->kind == EK_CONST && /* all this handles string appending */ + b->args[1]->val.i > 2 && /* of the form, "s := s + ..." */ + !strncmp(b->args[1]->val.s, "%s", 2) && + exprsame(a, b->args[2], 1) && + nosideeffects(a, 0) && + (ex = singlevar(a)) != NULL) { + ex2 = copyexpr(b); + delfreearg(&ex2, 2); + freeexpr(ex2->args[1]); + ex2->args[1] = makeexpr_lstring(b->args[1]->val.s+2, + b->args[1]->val.i-2); + if (/*(ex = singlevar(a)) != NULL && */ + /* noargdependencies(ex2) && */ !exproccurs(ex2, ex)) { + freeexpr(b); + if (ex2->args[1]->val.i == 2 && /* s := s + s2 */ + !strncmp(ex2->args[1]->val.s, "%s", 2)) { + canceltempvar(mp); + tp = ex2->val.type; + return makeexpr_bicall_2("strcat", tp, + makeexpr_addrstr(a), grabarg(ex2, 2)); + } else if (sprintflength(ex2, 0) >= 0) { /* s := s + 's2' */ + tp = ex2->val.type; + return makeexpr_bicall_2("strcat", tp, + makeexpr_addrstr(a), + makeexpr_unsprintfify(ex2)); + } else { /* general case */ + canceltempvar(mp); + freeexpr(ex2->args[0]); + ex = makeexpr_bicall_1("strlen", tp_int, copyexpr(a)); + ex2->args[0] = bumpstring(a, ex, 0); + return ex2; + } + } else + freeexpr(ex2); + } + if (b->kind == EK_BICALL && !strcmp(b->val.s, "sprintf") && + istempvar(b->args[0]) && + (ex = singlevar(a)) != NULL) { + j = -1; /* does lhs var appear exactly once on rhs? */ + for (i = 2; i < b->nargs; i++) { + if (exprsame(b->args[i], ex, 1) && j < 0) + j = i; + else if (exproccurs(b->args[i], ex)) + break; + } + if (i == b->nargs && j > 0) { + b->args[j] = makeexpr_bicall_2("strcpy", tp_str255, + makeexpr_addrstr(b->args[0]), + makeexpr_addrstr(b->args[j])); + b->args[0] = makeexpr_addrstr(a); + return b; + } + } + if (structuredfunc(b) && (ex2 = singlevar(a)) != NULL) { + ep = &b->args[0]; + i = strlapfunc(b); + while (structuredfunc((ex = *ep))) { + i = i && strlapfunc(ex); + ep = &ex->args[0]; + } + if ((mp = istempvar(ex)) != NULL && + (i || !exproccurs(b, ex2))) { + canceltempvar(mp); + freeexpr(*ep); + *ep = makeexpr_addrstr(a); + return b; + } + } + if (a->val.type->kind == TK_PROCPTR && + (mp = istempprocptr(b)) != NULL && + nosideeffects(a, 0)) { + freeexpr(b->args[0]->args[0]->args[0]); + b->args[0]->args[0]->args[0] = copyexpr(a); + if (b->nargs == 3) { + freeexpr(b->args[1]->args[0]->args[0]); + b->args[1]->args[0]->args[0] = a; + delfreearg(&b, 2); + } else { + freeexpr(b->args[1]); + b->args[1] = makeexpr_assign(makeexpr_dotq(a, "link", tp_anyptr), + makeexpr_nil()); + } + canceltempvar(mp); + return b; + } + if (a->val.type->kind == TK_PROCPTR && + (b->val.type->kind == TK_CPROCPTR || + checkconst(b, 0))) { + ex = makeexpr_dotq(copyexpr(a), "proc", tp_anyptr); + b = makeexpr_comma(makeexpr_assign(ex, b), + makeexpr_assign(makeexpr_dotq(a, "link", tp_anyptr), + makeexpr_nil())); + return b; + } + if (a->val.type->kind == TK_CPROCPTR && + (mp = istempprocptr(b)) != NULL && + nosideeffects(a, 0)) { + freeexpr(b->args[0]->args[0]); + b->args[0]->args[0] = a; + if (b->nargs == 3) + delfreearg(&b, 1); + delfreearg(&b, 1); + canceltempvar(mp); + return b; + } + if (a->val.type->kind == TK_CPROCPTR && + b->val.type->kind == TK_PROCPTR) { + b = makeexpr_dotq(b, "proc", tp_anyptr); + } + if (a->val.type->kind == TK_STRING) { + if (b->kind == EK_CONST && b->val.i == 0 && !isretvar(a)) { + /* optimizing retvar would mess up "return" optimization */ + return makeexpr_assign(makeexpr_hat(a, 0), + makeexpr_char(0)); + } + a = makeexpr_addrstr(a); + b = makeexpr_addrstr(b); + return makeexpr_bicall_2("strcpy", a->val.type, a, b); + } + if (a->kind == EK_BICALL && !strcmp(a->val.s, "strlen")) { + if (b->kind == EK_CAST && + ord_type(b->args[0]->val.type)->kind == TK_INTEGER) { + b = grabarg(b, 0); + } + j = (b->kind == EK_PLUS && /* handle "s[0] := xxx" */ + b->args[0]->kind == EK_BICALL && + !strcmp(b->args[0]->val.s, "strlen") && + exprsame(a->args[0], b->args[0]->args[0], 0) && + isliteralconst(b->args[1], NULL) == 2); + if (j && b->args[1]->val.i > 0 && + b->args[1]->val.i <= 5) { /* lengthening the string */ + a = grabarg(a, 0); + i = b->args[1]->val.i; + freeexpr(b); + if (i == 1) + b = makeexpr_string(" "); + else + b = makeexpr_lstring("12345", i); + return makeexpr_bicall_2("strcat", a->val.type, a, b); + } else { /* maybe shortening the string */ + if (!j && !isconstexpr(b, NULL)) + note("Modification of string length may translate incorrectly [146]"); + a = grabarg(a, 0); + b = makeexpr_ord(b); + return makeexpr_assign(makeexpr_index(a, b, NULL), + makeexpr_char(0)); + } + } + if (a->val.type->kind == TK_ARRAY || + (a->val.type->kind == TK_PROCPTR && copystructs < 1) || + (a->val.type->kind == TK_RECORD && + (copystructs < 1 || a->val.type != b->val.type))) { + ex = makeexpr_sizeof(copyexpr(a), 0); + ex2 = makeexpr_sizeof(copyexpr(b), 0); + if (!exprsame(ex, ex2, 1)) { + if (a->val.type->kind == TK_ARRAY && + b->val.type->kind == TK_ARRAY && + a->val.type->basetype->kind == TK_CHAR && + (!ISCONST(ex->kind) || !ISCONST(ex2->kind) || + ex->val.i > ex2->val.i)) { + ex = makeexpr_arglong(ex, (size_t_long != 0)); + ex2 = makeexpr_arglong(ex2, (size_t_long != 0)); + a = makeexpr_addrstr(a); + b = makeexpr_addrstr(b); + b = makeexpr_bicall_3("memcpy", a->val.type, + copyexpr(a), b, copyexpr(ex2)); + ex3 = copyexpr(ex2); + return makeexpr_comma(b, + makeexpr_bicall_3("memset", a->val.type, + makeexpr_plus(a, ex3), + makeexpr_char(' '), + makeexpr_minus(ex, + ex2))); + } else if (!(a->val.type->kind == TK_ARRAY && + b->val.type->kind != TK_ARRAY)) + warning("Incompatible types or sizes [167]"); + } + freeexpr(ex2); + ex = makeexpr_arglong(ex, (size_t_long != 0)); + a = makeexpr_addrstr(a); + b = makeexpr_addrstr(b); + return makeexpr_bicall_3("memcpy", a->val.type, a, b, ex); + } + if (a->val.type->kind == TK_SET) { + a = makeexpr_addrstr(a); + b = makeexpr_addrstr(b); + return makeexpr_bicall_2(setcopyname, a->val.type, a, b); + } + for (ep = &a; (ex3 = *ep); ) { + if (ex3->kind == EK_COMMA) + ep = &ex3->args[ex3->nargs-1]; + else if (ex3->kind == EK_CAST || ex3->kind == EK_ACTCAST) + ep = &ex3->args[0]; + else + break; + } + if (ex3->kind == EK_BICALL) { + if (!strcmp(ex3->val.s, getbitsname)) { + tp = ex3->args[0]->val.type; + if (tp->kind == TK_ARRAY) + ex3->args[0] = makeexpr_addr(ex3->args[0]); + ex3->val.type = tp_void; + if (checkconst(b, 0) && *clrbitsname) { + strchange(&ex3->val.s, clrbitsname); + } else if (*putbitsname && + ((ISCONST(b->kind) && + (b->val.i | ~((1 << (1 << tp->escale)) - 1)) == -1) || + checkconst(b, (1 << (1 << tp->escale)) - 1))) { + strchange(&ex3->val.s, putbitsname); + insertarg(ep, 2, makeexpr_arglong(makeexpr_ord(b), 0)); + } else { + b = makeexpr_arglong(makeexpr_ord(b), 0); + if (*storebitsname) { + strchange(&ex3->val.s, storebitsname); + insertarg(ep, 2, b); + } else { + if (exproccurs(b, ex3->args[0])) { + mp = makestmttempvar(b->val.type, name_TEMP); + ex2 = makeexpr_assign(makeexpr_var(mp), b); + b = makeexpr_var(mp); + } else + ex2 = NULL; + ex = copyexpr(ex3); + strchange(&ex3->val.s, putbitsname); + insertarg(&ex3, 2, b); + strchange(&ex->val.s, clrbitsname); + *ep = makeexpr_comma(ex2, makeexpr_comma(ex, ex3)); + } + } + return a; + } else if (!strcmp(ex3->val.s, getfbufname)) { + ex3->val.type = tp_void; + strchange(&ex3->val.s, putfbufname); + insertarg(ep, 2, b); + return a; + } else if (!strcmp(ex3->val.s, chargetfbufname)) { + ex3->val.type = tp_void; + if (*charputfbufname) { + strchange(&ex3->val.s, charputfbufname); + insertarg(ep, 1, b); + } else { + strchange(&ex3->val.s, putfbufname); + insertarg(ep, 1, makeexpr_type(ex3->val.type->basetype->basetype)); + insertarg(ep, 2, b); + } + return a; + } else if (!strcmp(ex3->val.s, arraygetfbufname)) { + ex3->val.type = tp_void; + if (*arrayputfbufname) { + strchange(&ex3->val.s, arrayputfbufname); + insertarg(ep, 1, b); + } else { + strchange(&ex3->val.s, putfbufname); + insertarg(ep, 1, makeexpr_type(ex3->val.type->basetype->basetype)); + insertarg(ep, 2, b); + } + return a; + } + } + while (a->kind == EK_CAST || a->kind == EK_ACTCAST || + a->kind == EK_LITCAST) { + if (a->kind == EK_LITCAST) { + b = makeexpr_cast(b, a->args[1]->val.type); + a = grabarg(a, 1); + } else if (ansiC < 2 || /* in GNU C, a cast is an lvalue */ + isarithkind(a->args[0]->kind) || + (a->val.type->kind == TK_POINTER && + a->args[0]->val.type->kind == TK_POINTER)) { + if (a->kind == EK_CAST) + b = makeexpr_cast(b, a->args[0]->val.type); + else + b = makeexpr_actcast(b, a->args[0]->val.type); + a = grabarg(a, 0); + } else + break; + } + if (a->kind == EK_NEG) + return makeexpr_assign(grabarg(a, 0), makeexpr_neg(b)); + if (a->kind == EK_NOT) + return makeexpr_assign(grabarg(a, 0), makeexpr_not(b)); + if (a->kind == EK_BNOT) + return makeexpr_assign(grabarg(a, 0), + makeexpr_un(EK_BNOT, b->val.type, b)); + if (a->kind == EK_PLUS) { + for (i = 0; i < a->nargs && a->nargs > 1; ) { + if (isconstantexpr(a->args[i])) { + b = makeexpr_minus(b, a->args[i]); + deletearg(&a, i); + } else + i++; + } + if (a->nargs == 1) + return makeexpr_assign(grabarg(a, 0), b); + } + if (a->kind == EK_TIMES) { + for (i = 0; i < a->nargs && a->nargs > 1; ) { + if (isconstantexpr(a->args[i])) { + if (a->val.type->kind == TK_REAL) + b = makeexpr_divide(b, a->args[i]); + else { + if (ISCONST(b->kind) && ISCONST(a->args[i]->kind) && + (b->val.i % a->args[i]->val.i) != 0) { + break; + } + b = makeexpr_div(b, a->args[i]); + } + deletearg(&a, i); + } else + i++; + } + if (a->nargs == 1) + return makeexpr_assign(grabarg(a, 0), b); + } + if ((a->kind == EK_DIVIDE || a->kind == EK_DIV) && + isconstantexpr(a->args[1])) { + b = makeexpr_times(b, a->args[1]); + return makeexpr_assign(a->args[0], b); + } + if (a->kind == EK_LSH && isconstantexpr(a->args[1])) { + if (ISCONST(b->kind) && ISCONST(a->args[1]->kind)) { + if ((b->val.i & ((1L << a->args[1]->val.i)-1)) == 0) { + b->val.i >>= a->args[1]->val.i; + return makeexpr_assign(grabarg(a, 0), b); + } + } else { + b = makeexpr_bin(EK_RSH, b->val.type, b, a->args[1]); + return makeexpr_assign(a->args[0], b); + } + } + if (a->kind == EK_RSH && isconstantexpr(a->args[1])) { + if (ISCONST(b->kind) && ISCONST(a->args[1]->kind)) + b->val.i <<= a->args[1]->val.i; + else + b = makeexpr_bin(EK_LSH, b->val.type, b, a->args[1]); + return makeexpr_assign(a->args[0], b); + } + if (isarithkind(a->kind)) + warning("Invalid assignment [168]"); + return makeexpr_bin(EK_ASSIGN, a->val.type, a, makeexpr_unlongcast(b)); +} + + + + +Expr *makeexpr_comma(a, b) +Expr *a, *b; +{ + Type *type; + + if (!a || nosideeffects(a, 1)) + return b; + if (!b) + return a; + type = b->val.type; + a = commute(a, b, EK_COMMA); + a->val.type = type; + return a; +} + + + + +int strmax(ex) +Expr *ex; +{ + Meaning *mp; + long smin, smax; + Value val; + Type *type; + + type = ex->val.type; + if (type->kind == TK_POINTER) + type = type->basetype; + if (type->kind == TK_CHAR) + return 1; + if (type->kind == TK_ARRAY && type->basetype->kind == TK_CHAR) { + if (ord_range(type->indextype, &smin, &smax)) + return smax - smin + 1; + else + return stringceiling; + } + if (type->kind != TK_STRING) { + intwarning("strmax", "strmax encountered a non-string value [169]"); + return stringceiling; + } + if (ex->kind == EK_CONST) + return ex->val.i; + if (ex->kind == EK_VAR && foldstrconsts != 0 && + (mp = (Meaning *)(ex->val.i))->kind == MK_CONST && mp->val.type) + return mp->val.i; + if (ex->kind == EK_BICALL) { + if (!strcmp(ex->val.s, strsubname)) { + if (isliteralconst(ex->args[3], &val) && val.type) + return val.i; + } + } + if (ord_range(type->indextype, NULL, &smax)) + return smax; + else + return stringceiling; +} + + + + +int strhasnull(val) +Value val; +{ + int i; + + for (i = 0; i < val.i; i++) { + if (!val.s[i]) + return (i == val.i-1) ? 1 : 2; + } + return 0; +} + + + +int istempsprintf(ex) +Expr *ex; +{ + return (ex->kind == EK_BICALL && !strcmp(ex->val.s, "sprintf") && + ex->nargs >= 2 && + istempvar(ex->args[0]) && + ex->args[1]->kind == EK_CONST && + ex->args[1]->val.type->kind == TK_STRING); +} + + + +Expr *makeexpr_sprintfify(ex) +Expr *ex; +{ + Meaning *tvar; + char stringbuf[500]; + char *cp, ch; + int j, nnulls; + Expr *ex2; + + if (debug>2) { fprintf(outf,"makeexpr_sprintfify("); dumpexpr(ex); fprintf(outf,")\n"); } + if (istempsprintf(ex)) + return ex; + ex = makeexpr_stringcast(ex); + tvar = makestmttempvar(tp_str255, name_STRING); + if (ex->kind == EK_CONST && ex->val.type->kind == TK_STRING) { + cp = stringbuf; + nnulls = 0; + for (j = 0; j < ex->val.i; j++) { + ch = ex->val.s[j]; + if (!ch) { + if (j < ex->val.i-1) + note("Null character in sprintf control string [147]"); + else + note("Null character at end of sprintf control string [148]"); + if (keepnulls) { + *cp++ = '%'; + *cp++ = 'c'; + nnulls++; + } + } else { + *cp++ = ch; + if (ch == '%') + *cp++ = ch; + } + } + *cp = 0; + ex = makeexpr_bicall_2("sprintf", tp_str255, + makeexpr_var(tvar), + makeexpr_string(stringbuf)); + while (--nnulls >= 0) + insertarg(&ex, 2, makeexpr_char(0)); + return ex; + } else if (ex->val.type->kind == TK_ARRAY && + ex->val.type->basetype->kind == TK_CHAR) { + ex2 = arraysize(ex->val.type, 0); + return cleansprintf( + makeexpr_bicall_4("sprintf", tp_str255, + makeexpr_var(tvar), + makeexpr_string("%.*s"), + ex2, + makeexpr_addrstr(ex))); + } else { + if (ord_type(ex->val.type)->kind == TK_CHAR) + cp = "%c"; + else if (ex->val.type->kind == TK_STRING) + cp = "%s"; + else { + warning("Mixing non-strings with strings [170]"); + return ex; + } + return makeexpr_bicall_3("sprintf", tp_str255, + makeexpr_var(tvar), + makeexpr_string(cp), + ex); + } +} + + + +Expr *makeexpr_unsprintfify(ex) +Expr *ex; +{ + char stringbuf[500]; + char *cp, ch; + int i; + + if (debug>2) { fprintf(outf,"makeexpr_unsprintfify("); dumpexpr(ex); fprintf(outf,")\n"); } + if (!istempsprintf(ex)) + return ex; + canceltempvar(istempvar(ex->args[0])); + for (i = 2; i < ex->nargs; i++) { + if (ex->args[i]->val.type->kind != TK_CHAR || + !checkconst(ex, 0)) + return ex; + } + cp = stringbuf; + for (i = 0; i < ex->args[1]->val.i; i++) { + ch = ex->args[1]->val.s[i]; + *cp++ = ch; + if (ch == '%') { + if (++i == ex->args[1]->val.i) + return ex; + ch = ex->args[1]->val.s[i]; + if (ch == 'c') + cp[-1] = 0; + else if (ch != '%') + return ex; + } + } + freeexpr(ex); + return makeexpr_lstring(stringbuf, cp - stringbuf); +} + + + +/* Returns >= 0 iff unsprintfify would return a string constant */ + +int sprintflength(ex, allownulls) +Expr *ex; +int allownulls; +{ + int i, len; + + if (!istempsprintf(ex)) + return -1; + for (i = 2; i < ex->nargs; i++) { + if (!allownulls || + ex->args[i]->val.type->kind != TK_CHAR || + !checkconst(ex, 0)) + return -1; + } + len = 0; + for (i = 0; i < ex->args[1]->val.i; i++) { + len++; + if (ex->args[1]->val.s[i] == '%') { + if (++i == ex->args[1]->val.i) + return -1; + if (ex->args[1]->val.s[i] != 'c' && + ex->args[1]->val.s[i] != '%') + return -1; + } + } + return len; +} + + + +Expr *makeexpr_concat(a, b, usesprintf) +Expr *a, *b; +int usesprintf; +{ + int i, ii, j, len, nargs; + Type *type; + Meaning *mp, *tvar; + Expr *ex, *args[2]; + int akind[2]; + Value val, val1, val2; + char formatstr[300]; + + if (debug>2) { fprintf(outf,"makeexpr_concat("); dumpexpr(a); fprintf(outf,", "); dumpexpr(b); fprintf(outf,")\n"); } + if (!a) + return b; + if (!b) + return a; + a = makeexpr_stringcast(a); + b = makeexpr_stringcast(b); + if (checkconst(a, 0)) { + freeexpr(a); + return b; + } + if (checkconst(b, 0)) { + freeexpr(b); + return a; + } + len = strmax(a) + strmax(b); + type = makestringtype(len); + if (a->kind == EK_CONST && b->kind == EK_CONST) { + val1 = a->val; + val2 = b->val; + val.i = val1.i + val2.i; + val.s = ALLOC(val.i+1, char, literals); + val.s[val.i] = 0; + val.type = type; + memcpy(val.s, val1.s, val1.i); + memcpy(val.s + val1.i, val2.s, val2.i); + freeexpr(a); + freeexpr(b); + return makeexpr_val(val); + } + tvar = makestmttempvar(type, name_STRING); + if (sprintf_value != 2 || usesprintf) { + nargs = 2; /* Generate a call to sprintf(), unfolding */ + args[0] = a; /* nested sprintf()'s. */ + args[1] = b; + *formatstr = 0; + for (i = 0; i < 2; i++) { +#if 1 + ex = args[i] = makeexpr_sprintfify(args[i]); + if (!ex->args[1] || !ex->args[1]->val.s) + intwarning("makeexpr_concat", "NULL in ex->args[1]"); + else + strncat(formatstr, ex->args[1]->val.s, ex->args[1]->val.i); + canceltempvar(istempvar(ex->args[0])); + nargs += (ex->nargs - 2); + akind[i] = 0; /* now obsolete */ +#else + ex = args[i]; + if (ex->kind == EK_CONST) + ex = makeexpr_sprintfify(ex); + if (istempsprintf(ex)) { + strncat(formatstr, ex->args[1]->val.s, ex->args[1]->val.i); + canceltempvar(istempvar(ex->args[0])); + nargs += (ex->nargs - 2); + akind[i] = 0; + } else { + strcat(formatstr, "%s"); + nargs++; + akind[i] = 1; + } +#endif + } + ex = makeexpr(EK_BICALL, nargs); + ex->val.type = type; + ex->val.s = stralloc("sprintf"); + ex->args[0] = makeexpr_var(tvar); + ex->args[1] = makeexpr_string(formatstr); + j = 2; + for (i = 0; i < 2; i++) { + switch (akind[i]) { + case 0: /* flattened sub-sprintf */ + for (ii = 2; ii < args[i]->nargs; ii++) + ex->args[j++] = copyexpr(args[i]->args[ii]); + freeexpr(args[i]); + break; + case 1: /* included string expr */ + ex->args[j++] = args[i]; + break; + } + } + } else { + ex = a; + while (ex->kind == EK_BICALL && !strcmp(ex->val.s, "strcat")) + ex = ex->args[0]; + if (ex->kind == EK_BICALL && !strcmp(ex->val.s, "strcpy") && + (mp = istempvar(ex->args[0])) != NULL) { + canceltempvar(mp); + freeexpr(ex->args[0]); + ex->args[0] = makeexpr_var(tvar); + } else { + a = makeexpr_bicall_2("strcpy", type, makeexpr_var(tvar), a); + } + ex = makeexpr_bicall_2("strcat", type, a, b); + } + if (debug>2) { fprintf(outf,"makeexpr_concat returns "); dumpexpr(ex); fprintf(outf,"\n"); } + return ex; +} + + + +Expr *cleansprintf(ex) +Expr *ex; +{ + int fidx, i, j, k, len, changed = 0; + char *cp, *bp; + char fmtbuf[300]; + + if (ex->kind != EK_BICALL) + return ex; + if (!strcmp(ex->val.s, "printf")) + fidx = 0; + else if (!strcmp(ex->val.s, "sprintf") || + !strcmp(ex->val.s, "fprintf")) + fidx = 1; + else + return ex; + len = ex->args[fidx]->val.i; + cp = ex->args[fidx]->val.s; /* printf("%*d",17,x) => printf("%17d",x) */ + bp = fmtbuf; + j = fidx + 1; + for (i = 0; i < len; i++) { + *bp++ = cp[i]; + if (cp[i] == '%') { + if (cp[i+1] == 's' && ex->args[j]->kind == EK_CONST) { + bp--; + for (k = 0; k < ex->args[j]->val.i; k++) + *bp++ = ex->args[j]->val.s[k]; + delfreearg(&ex, j); + changed = 1; + i++; + continue; + } + for (i++; i < len && + !(isalpha(cp[i]) && cp[i] != 'l'); i++) { + if (cp[i] == '*') { + if (isliteralconst(ex->args[j], NULL) == 2) { + sprintf(bp, "%ld", ex->args[j]->val.i); + bp += strlen(bp); + delfreearg(&ex, j); + changed = 1; + } else { + *bp++ = cp[i]; + j++; + } + } else + *bp++ = cp[i]; + } + if (i < len) + *bp++ = cp[i]; + j++; + } + } + *bp = 0; + if (changed) { + freeexpr(ex->args[fidx]); + ex->args[fidx] = makeexpr_string(fmtbuf); + } + return ex; +} + + + +Expr *makeexpr_substring(vex, ex, exi, exj) +Expr *vex, *ex, *exi, *exj; +{ + exi = makeexpr_unlongcast(exi); + exj = makeexpr_longcast(exj, 0); + ex = bumpstring(ex, exi, 1); + return cleansprintf(makeexpr_bicall_4("sprintf", tp_str255, + vex, + makeexpr_string("%.*s"), + exj, + ex)); +} + + + + +Expr *makeexpr_dot(ex, mp) +Expr *ex; +Meaning *mp; +{ + Type *ot1, *ot2; + Expr *ex2, *ex3, *nex; + Meaning *tvar; + + if (ex->kind == EK_FUNCTION && copystructfuncs > 0) { + tvar = makestmttempvar(ex->val.type, name_TEMP); + ex2 = makeexpr_assign(makeexpr_var(tvar), ex); + ex = makeexpr_var(tvar); + } else + ex2 = NULL; + if (mp->constdefn) { + nex = makeexpr(EK_MACARG, 0); + nex->val.type = tp_integer; + ex3 = replaceexprexpr(copyexpr(mp->constdefn), nex, ex, 0); + freeexpr(ex); + freeexpr(nex); + ex = gentle_cast(ex3, mp->val.type); + } else { + ex = makeexpr_un(EK_DOT, mp->type, ex); + ex->val.i = (long)mp; + ot1 = ord_type(mp->type); + ot2 = ord_type(mp->val.type); + if (ot1->kind != ot2->kind && ot2->kind == TK_ENUM && ot2->meaning && useenum) + ex = makeexpr_cast(ex, mp->val.type); + else if (mp->val.i && !hassignedchar && + (mp->type == tp_sint || mp->type == tp_abyte)) { + if (*signextname) { + ex = makeexpr_bicall_2(signextname, tp_integer, + ex, makeexpr_long(mp->val.i)); + } else + note(format_s("Unable to sign-extend field %s [149]", mp->name)); + } + } + ex->val.type = mp->val.type; + return makeexpr_comma(ex2, ex); +} + + + +Expr *makeexpr_dotq(ex, name, type) +Expr *ex; +char *name; +Type *type; +{ + ex = makeexpr_un(EK_DOT, type, ex); + ex->val.s = stralloc(name); + return ex; +} + + + +Expr *strmax_func(ex) +Expr *ex; +{ + Meaning *mp; + Expr *ex2; + Type *type; + + type = ex->val.type; + if (type->kind == TK_POINTER) { + intwarning("strmax_func", "got a pointer instead of a string [171]"); + type = type->basetype; + } + if (type->kind == TK_CHAR) + return makeexpr_long(1); + if (type->kind != TK_STRING) { + warning("STRMAX of non-string value [172]"); + return makeexpr_long(stringceiling); + } + if (ex->kind == EK_CONST) + return makeexpr_long(ex->val.i); + if (ex->kind == EK_VAR && + (mp = (Meaning *)ex->val.i)->kind == MK_CONST && + mp->type == tp_str255 && mp->val.type) + return makeexpr_long(mp->val.i); + if (ex->kind == EK_VAR && + (mp = (Meaning *)ex->val.i)->kind == MK_VARPARAM && + mp->type == tp_strptr) { + if (mp->anyvarflag) { + if (mp->ctx != curctx && mp->ctx->kind == MK_FUNCTION) + note(format_s("Reference to STRMAX of parent proc's \"%s\" must be fixed [150]", + mp->name)); + return makeexpr_name(format_s(name_STRMAX, mp->name), tp_int); + } else + note(format_s("STRMAX of \"%s\" wants VarStrings=1 [151]", mp->name)); + } + ord_range_expr(type->indextype, NULL, &ex2); + return copyexpr(ex2); +} + + + + +Expr *makeexpr_nil() +{ + Expr *ex; + + ex = makeexpr(EK_CONST, 0); + ex->val.type = tp_anyptr; + ex->val.i = 0; + ex->val.s = NULL; + return ex; +} + + + +Expr *makeexpr_ctx(ctx) +Meaning *ctx; +{ + Expr *ex; + + ex = makeexpr(EK_CTX, 0); + ex->val.type = tp_text; /* handy pointer type */ + ex->val.i = (long)ctx; + return ex; +} + + + + +Expr *force_signed(ex) +Expr *ex; +{ + Type *tp; + + if (isliteralconst(ex, NULL) == 2 && ex->nargs == 0) + return ex; + tp = true_type(ex); + if (tp == tp_ushort || tp == tp_ubyte || tp == tp_uchar) + return makeexpr_cast(ex, tp_sshort); + else if (tp == tp_unsigned || tp == tp_uint) { + if (exprlongness(ex) < 0) + return makeexpr_cast(ex, tp_sint); + else + return makeexpr_cast(ex, tp_integer); + } + return ex; +} + + + +Expr *force_unsigned(ex) +Expr *ex; +{ + Type *tp; + + if (isliteralconst(ex, NULL) == 2 && !expr_is_neg(ex)) + return ex; + tp = true_type(ex); + if (tp == tp_unsigned || tp == tp_uint || tp == tp_ushort || + tp == tp_ubyte || tp == tp_uchar) + return ex; + if (tp->kind == TK_CHAR) + return makeexpr_actcast(ex, tp_uchar); + else if (exprlongness(ex) < 0) + return makeexpr_cast(ex, tp_uint); + else + return makeexpr_cast(ex, tp_unsigned); +} + + + + +#define CHECKSIZE(size) (((size) > 0 && (size)%charsize == 0) ? (size)/charsize : 0) + +long type_sizeof(type, pasc) +Type *type; +int pasc; +{ + long s1, smin, smax; + int charsize = (sizeof_char) ? sizeof_char : CHAR_BIT; /* from <limits.h> */ + + switch (type->kind) { + + case TK_INTEGER: + if (type == tp_integer || + type == tp_unsigned) + return pasc ? 4 : CHECKSIZE(sizeof_integer); + else + return pasc ? 2 : CHECKSIZE(sizeof_short); + + case TK_CHAR: + case TK_BOOLEAN: + return 1; + + case TK_SUBR: + type = findbasetype(type, ODECL_NOPRES); + if (pasc) { + if (type == tp_integer || type == tp_unsigned) + return 4; + else + return 2; + } else { + if (type == tp_abyte || type == tp_ubyte || type == tp_sbyte) + return 1; + else if (type == tp_ushort || type == tp_sshort) + return CHECKSIZE(sizeof_short); + else + return CHECKSIZE(sizeof_integer); + } + + case TK_POINTER: + return pasc ? 4 : CHECKSIZE(sizeof_pointer); + + case TK_REAL: + if (type == tp_longreal) + return pasc ? (which_lang == LANG_TURBO ? 6 : 8) : CHECKSIZE(sizeof_double); + else + return pasc ? 4 : CHECKSIZE(sizeof_float); + + case TK_ENUM: + if (!pasc) + return CHECKSIZE(sizeof_enum); + type = findbasetype(type, ODECL_NOPRES); + return type->kind != TK_ENUM ? type_sizeof(type, pasc) + : CHECKSIZE(pascalenumsize); + + case TK_SMALLSET: + case TK_SMALLARRAY: + return pasc ? 0 : type_sizeof(type->basetype, pasc); + + case TK_ARRAY: + s1 = type_sizeof(type->basetype, pasc); + if (s1 && ord_range(type->indextype, &smin, &smax)) + return s1 * (smax - smin + 1); + else + return 0; + + case TK_RECORD: + if (pasc && type->meaning) { + if (!strcmp(type->meaning->sym->name, "NA_WORD")) + return 2; + else if (!strcmp(type->meaning->sym->name, "NA_LONGWORD")) + return 4; + else if (!strcmp(type->meaning->sym->name, "NA_QUADWORD")) + return 8; + else + return 0; + } else + return 0; + + default: + return 0; + } +} + + + +Static Value eval_expr_either(ex, pasc) +Expr *ex; +int pasc; +{ + Value val, val2; + Meaning *mp; + int i; + + if (debug>2) { fprintf(outf,"eval_expr("); dumpexpr(ex); fprintf(outf,")\n"); } + switch (ex->kind) { + + case EK_CONST: + case EK_LONGCONST: + return ex->val; + + case EK_VAR: + mp = (Meaning *) ex->val.i; + if (mp->kind == MK_CONST && + (foldconsts != 0 || + mp == mp_maxint || mp == mp_minint)) + return mp->val; + break; + + case EK_SIZEOF: + i = type_sizeof(ex->args[0]->val.type, pasc); + if (i) + return make_ord(tp_integer, i); + break; + + case EK_PLUS: + val = eval_expr_either(ex->args[0], pasc); + if (!val.type || ord_type(val.type)->kind != TK_INTEGER) + val.type = NULL; + for (i = 1; val.type && i < ex->nargs; i++) { + val2 = eval_expr_either(ex->args[i], pasc); + if (!val2.type || ord_type(val2.type)->kind != TK_INTEGER) + val.type = NULL; + else { + val.i += val2.i; + val.type = tp_integer; + } + } + return val; + + case EK_TIMES: + val = eval_expr_either(ex->args[0], pasc); + if (!val.type || ord_type(val.type)->kind != TK_INTEGER) + val.type = NULL; + for (i = 1; val.type && i < ex->nargs; i++) { + val2 = eval_expr_either(ex->args[i], pasc); + if (!val2.type || ord_type(val2.type)->kind != TK_INTEGER) + val.type = NULL; + else { + val.i *= val2.i; + val.type = tp_integer; + } + } + return val; + + case EK_DIV: + val = eval_expr_either(ex->args[0], pasc); + val2 = eval_expr_either(ex->args[1], pasc); + if (val.type && ord_type(val.type)->kind == TK_INTEGER && + val2.type && ord_type(val2.type)->kind == TK_INTEGER && + val2.i) { + val.i /= val2.i; + val.type = tp_integer; + return val; + } + break; + + case EK_MOD: + val = eval_expr_either(ex->args[0], pasc); + val2 = eval_expr_either(ex->args[1], pasc); + if (val.type && ord_type(val.type)->kind == TK_INTEGER && + val2.type && ord_type(val2.type)->kind == TK_INTEGER && + val2.i) { + val.i %= val2.i; + val.type = tp_integer; + return val; + } + break; + + case EK_NEG: + val = eval_expr_either(ex->args[0], pasc); + if (val.type) { + val.i = -val.i; + return val; + } + break; + + case EK_LSH: + val = eval_expr_either(ex->args[0], pasc); + val2 = eval_expr_either(ex->args[1], pasc); + if (val.type && val2.type) { + val.i <<= val2.i; + return val; + } + break; + + case EK_RSH: + val = eval_expr_either(ex->args[0], pasc); + val2 = eval_expr_either(ex->args[1], pasc); + if (val.type && val2.type) { + val.i >>= val2.i; + return val; + } + break; + + case EK_BAND: + val = eval_expr_either(ex->args[0], pasc); + val2 = eval_expr_either(ex->args[1], pasc); + if (val.type && val2.type) { + val.i &= val2.i; + return val; + } + break; + + case EK_BOR: + val = eval_expr_either(ex->args[0], pasc); + val2 = eval_expr_either(ex->args[1], pasc); + if (val.type && val2.type) { + val.i |= val2.i; + return val; + } + break; + + case EK_BXOR: + val = eval_expr_either(ex->args[0], pasc); + val2 = eval_expr_either(ex->args[1], pasc); + if (val.type && val2.type) { + val.i ^= val2.i; + return val; + } + break; + + case EK_BNOT: + val = eval_expr_either(ex->args[0], pasc); + if (val.type) { + val.i = ~val.i; + return val; + } + break; + + case EK_EQ: + case EK_NE: + case EK_GT: + case EK_LT: + case EK_GE: + case EK_LE: + val = eval_expr_either(ex->args[0], pasc); + val2 = eval_expr_either(ex->args[1], pasc); + if (val.type) { + if (val.i == val2.i) + val.i = (ex->kind == EK_EQ || ex->kind == EK_GE || ex->kind == EK_LE); + else if (val.i < val2.i) + val.i = (ex->kind == EK_LT || ex->kind == EK_LE || ex->kind == EK_NE); + else + val.i = (ex->kind == EK_GT || ex->kind == EK_GE || ex->kind == EK_NE); + val.type = tp_boolean; + return val; + } + break; + + case EK_NOT: + val = eval_expr_either(ex->args[0], pasc); + if (val.type) + val.i = !val.i; + return val; + + case EK_AND: + for (i = 0; i < ex->nargs; i++) { + val = eval_expr_either(ex->args[i], pasc); + if (!val.type || !val.i) + return val; + } + return val; + + case EK_OR: + for (i = 0; i < ex->nargs; i++) { + val = eval_expr_either(ex->args[i], pasc); + if (!val.type || val.i) + return val; + } + return val; + + case EK_COMMA: + return eval_expr_either(ex->args[ex->nargs-1], pasc); + + default: + break; + } + val.type = NULL; + return val; +} + + +Value eval_expr(ex) +Expr *ex; +{ + return eval_expr_either(ex, 0); +} + + +Value eval_expr_consts(ex) +Expr *ex; +{ + Value val; + short save_fold = foldconsts; + + foldconsts = 1; + val = eval_expr_either(ex, 0); + foldconsts = save_fold; + return val; +} + + +Value eval_expr_pasc(ex) +Expr *ex; +{ + return eval_expr_either(ex, 1); +} + + + +int expr_is_const(ex) +Expr *ex; +{ + int i; + + switch (ex->kind) { + + case EK_CONST: + case EK_LONGCONST: + case EK_SIZEOF: + return 1; + + case EK_VAR: + return (((Meaning *)ex->val.i)->kind == MK_CONST); + + case EK_HAT: + case EK_ASSIGN: + case EK_POSTINC: + case EK_POSTDEC: + return 0; + + case EK_ADDR: + if (ex->args[0]->kind == EK_VAR) + return 1; + return 0; /* conservative */ + + case EK_FUNCTION: + if (!nosideeffects_func(ex)) + return 0; + break; + + case EK_BICALL: + if (!nosideeffects_func(ex)) + return 0; + break; + + default: + break; + } + for (i = 0; i < ex->nargs; i++) { + if (!expr_is_const(ex->args[i])) + return 0; + } + return 1; +} + + + + + +Expr *eatcasts(ex) +Expr *ex; +{ + while (ex->kind == EK_CAST) + ex = grabarg(ex, 0); + return ex; +} + + + + + +/* End. */ + + + diff --git a/MultiSource/Benchmarks/MallocBench/p2c/funcs.c b/MultiSource/Benchmarks/MallocBench/p2c/funcs.c new file mode 100644 index 00000000..5ec410d7 --- /dev/null +++ b/MultiSource/Benchmarks/MallocBench/p2c/funcs.c @@ -0,0 +1,5405 @@ +/* "p2c", a Pascal to C translator. + Copyright (C) 1989, 1990, 1991 Free Software Foundation. + Author's address: daveg@csvax.caltech.edu; 256-80 Caltech/Pasadena CA 91125. + +This program is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation (any version). + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; see the file COPYING. If not, write to +the Free Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ + + + +#define PROTO_FUNCS_C +#include "trans.h" + + + + +Static Strlist *enumnames; +Static int enumnamecount; + + + +void setup_funcs() +{ + enumnames = NULL; + enumnamecount = 0; +} + + + + + +int isvar(ex, mp) +Expr *ex; +Meaning *mp; +{ + return (ex->kind == EK_VAR && (Meaning *)ex->val.i == mp); +} + + + + +char *getstring(ex) +Expr *ex; +{ + ex = makeexpr_stringify(ex); + if (ex->kind != EK_CONST || ex->val.type->kind != TK_STRING) { + intwarning("getstring", "Not a string literal [206]"); + return ""; + } + return ex->val.s; +} + + + + +Expr *p_parexpr(target) +Type *target; +{ + Expr *ex; + + if (wneedtok(TOK_LPAR)) { + ex = p_expr(target); + if (!wneedtok(TOK_RPAR)) + skippasttotoken(TOK_RPAR, TOK_SEMI); + } else + ex = p_expr(target); + return ex; +} + + + +Type *argbasetype(ex) +Expr *ex; +{ + if (ex->kind == EK_CAST) + ex = ex->args[0]; + if (ex->val.type->kind == TK_POINTER) + return ex->val.type->basetype; + else + return ex->val.type; +} + + + +Type *choosetype(t1, t2) +Type *t1, *t2; +{ + if (t1 == tp_void || + (type_sizeof(t2, 1) && !type_sizeof(t1, 1))) + return t2; + else + return t1; +} + + + +Expr *convert_offset(type, ex2) +Type *type; +Expr *ex2; +{ + long size; + int i; + Value val; + Expr *ex3; + + if (type->kind == TK_POINTER || + type->kind == TK_ARRAY || + type->kind == TK_SET || + type->kind == TK_STRING) + type = type->basetype; + size = type_sizeof(type, 1); + if (size == 1) + return ex2; + val = eval_expr_pasc(ex2); + if (val.type) { + if (val.i == 0) + return ex2; + if (size && val.i % size == 0) { + freeexpr(ex2); + return makeexpr_long(val.i / size); + } + } else { /* look for terms like "n*sizeof(foo)" */ + while (ex2->kind == EK_CAST || ex2->kind == EK_ACTCAST) + ex2 = ex2->args[0]; + if (ex2->kind == EK_TIMES) { + for (i = 0; i < ex2->nargs; i++) { + ex3 = convert_offset(type, ex2->args[i]); + if (ex3) { + ex2->args[i] = ex3; + return resimplify(ex2); + } + } + for (i = 0; + i < ex2->nargs && ex2->args[i]->kind != EK_SIZEOF; + i++) ; + if (i < ex2->nargs) { + if (ex2->args[i]->args[0]->val.type == type) { + delfreearg(&ex2, i); + if (ex2->nargs == 1) + return ex2->args[0]; + else + return ex2; + } + } + } else if (ex2->kind == EK_PLUS) { + ex3 = copyexpr(ex2); + for (i = 0; i < ex2->nargs; i++) { + ex3->args[i] = convert_offset(type, ex3->args[i]); + if (!ex3->args[i]) { + freeexpr(ex3); + return NULL; + } + } + freeexpr(ex2); + return resimplify(ex3); + } else if (ex2->kind == EK_SIZEOF) { + if (ex2->args[0]->val.type == type) { + freeexpr(ex2); + return makeexpr_long(1); + } + } else if (ex2->kind == EK_NEG) { + ex3 = convert_offset(type, ex2->args[0]); + if (ex3) + return makeexpr_neg(ex3); + } + } + return NULL; +} + + + +Expr *convert_size(type, ex, name) +Type *type; +Expr *ex; +char *name; +{ + long size; + Expr *ex2; + int i, okay; + Value val; + + if (debug>2) { fprintf(outf,"convert_size("); dumpexpr(ex); fprintf(outf,")\n"); } + while (type->kind == TK_ARRAY || type->kind == TK_STRING) + type = type->basetype; + if (type == tp_void) + return ex; + size = type_sizeof(type, 1); + if (size == 1) + return ex; + while (ex->kind == EK_CAST || ex->kind == EK_ACTCAST) + ex = ex->args[0]; + switch (ex->kind) { + + case EK_TIMES: + for (i = 0; i < ex->nargs; i++) { + ex2 = convert_size(type, ex->args[i], NULL); + if (ex2) { + ex->args[i] = ex2; + return resimplify(ex); + } + } + break; + + case EK_PLUS: + okay = 1; + for (i = 0; i < ex->nargs; i++) { + ex2 = convert_size(type, ex->args[i], NULL); + if (ex2) + ex->args[i] = ex2; + else + okay = 0; + } + ex = distribute_plus(ex); + if ((ex->kind != EK_TIMES || !okay) && name) + note(format_s("Suspicious mixture of sizes in %s [173]", name)); + return ex; + + case EK_SIZEOF: + return ex; + + default: + break; + } + val = eval_expr_pasc(ex); + if (val.type) { + if (val.i == 0) + return ex; + if (size && val.i % size == 0) { + freeexpr(ex); + return makeexpr_times(makeexpr_long(val.i / size), + makeexpr_sizeof(makeexpr_type(type), 0)); + } + } + if (name) { + note(format_s("Can't interpret size in %s [174]", name)); + return ex; + } else + return NULL; +} + + + + + + + + + + + + +Static Expr *func_abs() +{ + Expr *ex; + Meaning *tvar; + int lness; + + ex = p_parexpr(tp_integer); + if (ex->val.type->kind == TK_REAL) + return makeexpr_bicall_1("fabs", tp_longreal, ex); + else { + lness = exprlongness(ex); + if (lness < 0) + return makeexpr_bicall_1("abs", tp_int, ex); + else if (lness > 0 && *absname) { + if (ansiC > 0) { + return makeexpr_bicall_1("labs", tp_integer, ex); + } else if (*absname == '*' && (exprspeed(ex) >= 5 || !nosideeffects(ex, 0))) { + tvar = makestmttempvar(tp_integer, name_TEMP); + return makeexpr_comma(makeexpr_assign(makeexpr_var(tvar), + ex), + makeexpr_bicall_1(absname, tp_integer, + makeexpr_var(tvar))); + } else { + return makeexpr_bicall_1(absname, tp_integer, ex); + } + } else if (exprspeed(ex) < 5 && nosideeffects(ex, 0)) { + return makeexpr_cond(makeexpr_rel(EK_LT, copyexpr(ex), + makeexpr_long(0)), + makeexpr_neg(copyexpr(ex)), + ex); + } else { + tvar = makestmttempvar(tp_integer, name_TEMP); + return makeexpr_cond(makeexpr_rel(EK_LT, makeexpr_assign(makeexpr_var(tvar), + ex), + makeexpr_long(0)), + makeexpr_neg(makeexpr_var(tvar)), + makeexpr_var(tvar)); + } + } +} + + + +Static Expr *func_addr() +{ + Expr *ex, *ex2, *ex3; + Type *type, *tp2; + int haspar; + + haspar = wneedtok(TOK_LPAR); + ex = p_expr(tp_proc); + if (curtok == TOK_COMMA) { + gettok(); + ex2 = p_expr(tp_integer); + ex3 = convert_offset(ex->val.type, ex2); + if (checkconst(ex3, 0)) { + ex = makeexpr_addrf(ex); + } else { + ex = makeexpr_addrf(ex); + if (ex3) { + ex = makeexpr_plus(ex, ex3); + } else { + note("Don't know how to reduce offset for ADDR [175]"); + type = makepointertype(tp_abyte); + tp2 = ex->val.type; + ex = makeexpr_cast(makeexpr_plus(makeexpr_cast(ex, type), ex2), tp2); + } + } + } else { + if ((ex->val.type->kind != TK_PROCPTR && + ex->val.type->kind != TK_CPROCPTR) || + (ex->kind == EK_VAR && + ex->val.type == ((Meaning *)ex->val.i)->type)) + ex = makeexpr_addrf(ex); + } + if (haspar) { + if (!wneedtok(TOK_RPAR)) + skippasttotoken(TOK_RPAR, TOK_SEMI); + } + return ex; +} + + +Static Expr *func_iaddress() +{ + return makeexpr_cast(func_addr(), tp_integer); +} + + + +Static Expr *func_addtopointer() +{ + Expr *ex, *ex2, *ex3; + Type *type, *tp2; + + if (!skipopenparen()) + return NULL; + ex = p_expr(tp_anyptr); + if (skipcomma()) { + ex2 = p_expr(tp_integer); + } else + ex2 = makeexpr_long(0); + skipcloseparen(); + ex3 = convert_offset(ex->val.type, ex2); + if (!checkconst(ex3, 0)) { + if (ex3) { + ex = makeexpr_plus(ex, ex3); + } else { + note("Don't know how to reduce offset for ADDTOPOINTER [175]"); + type = makepointertype(tp_abyte); + tp2 = ex->val.type; + ex = makeexpr_cast(makeexpr_plus(makeexpr_cast(ex, type), ex2), tp2); + } + } + return ex; +} + + + +Stmt *proc_assert() +{ + Expr *ex; + + ex = p_parexpr(tp_boolean); + return makestmt_call(makeexpr_bicall_1("assert", tp_void, ex)); +} + + + +Stmt *wrapopencheck(sp, fex) +Stmt *sp; +Expr *fex; +{ + Stmt *sp2; + + if (FCheck(checkfileisopen) && !is_std_file(fex)) { + sp2 = makestmt(SK_IF); + sp2->exp1 = makeexpr_rel(EK_NE, filebasename(fex), makeexpr_nil()); + sp2->stm1 = sp; + if (iocheck_flag) { + sp2->stm2 = makestmt_call(makeexpr_bicall_1(name_ESCIO, tp_integer, + makeexpr_name(filenotopenname, tp_int))); + } else { + sp2->stm2 = makestmt_assign(makeexpr_var(mp_ioresult), + makeexpr_name(filenotopenname, tp_int)); + } + return sp2; + } else { + freeexpr(fex); + return sp; + } +} + + + +Static Expr *checkfilename(nex) +Expr *nex; +{ + Expr *ex; + + nex = makeexpr_stringcast(nex); + if (nex->kind == EK_CONST && nex->val.type->kind == TK_STRING) { + switch (which_lang) { + + case LANG_HP: + if (!strncmp(nex->val.s, "#1:", 3) || + !strncmp(nex->val.s, "console:", 8) || + !strncmp(nex->val.s, "CONSOLE:", 8)) { + freeexpr(nex); + nex = makeexpr_string("/dev/tty"); + } else if (!strncmp(nex->val.s, "#2:", 3) || + !strncmp(nex->val.s, "systerm:", 8) || + !strncmp(nex->val.s, "SYSTERM:", 8)) { + freeexpr(nex); + nex = makeexpr_string("/dev/tty"); /* should do more? */ + } else if (!strncmp(nex->val.s, "#6:", 3) || + !strncmp(nex->val.s, "printer:", 8) || + !strncmp(nex->val.s, "PRINTER:", 8)) { + note("Opening a file named PRINTER: [176]"); + } else if (my_strchr(nex->val.s, ':')) { + note("Opening a file whose name contains a ':' [177]"); + } + break; + + case LANG_TURBO: + if (checkstring(nex, "con") || + checkstring(nex, "CON") || + checkstring(nex, "")) { + freeexpr(nex); + nex = makeexpr_string("/dev/tty"); + } else if (checkstring(nex, "nul") || + checkstring(nex, "NUL")) { + freeexpr(nex); + nex = makeexpr_string("/dev/null"); + } else if (checkstring(nex, "lpt1") || + checkstring(nex, "LPT1") || + checkstring(nex, "lpt2") || + checkstring(nex, "LPT2") || + checkstring(nex, "lpt3") || + checkstring(nex, "LPT3") || + checkstring(nex, "com1") || + checkstring(nex, "COM1") || + checkstring(nex, "com2") || + checkstring(nex, "COM2")) { + note("Opening a DOS device file name [178]"); + } + break; + + default: + break; + } + } else { + if (*filenamefilter && strcmp(filenamefilter, "0")) { + ex = makeexpr_sizeof(copyexpr(nex), 0); + nex = makeexpr_bicall_2(filenamefilter, tp_str255, nex, ex); + } else + nex = makeexpr_stringify(nex); + } + return nex; +} + + + +Static Stmt *assignfilename(fex, nex) +Expr *fex, *nex; +{ + Meaning *mp; + Expr *nvex; + + nvex = filenamepart(fex); + if (nvex) { + freeexpr(fex); + return makestmt_call(makeexpr_assign(nvex, nex)); + } else { + mp = isfilevar(fex); + if (mp) + warning("Don't know how to ASSIGN to a non-explicit file variable [207]"); + else + note("Encountered an ASSIGN statement [179]"); + return makestmt_call(makeexpr_bicall_2("assign", tp_void, fex, nex)); + } +} + + + +Static Stmt *proc_assign() +{ + Expr *fex, *nex; + + if (!skipopenparen()) + return NULL; + fex = p_expr(tp_text); + if (!skipcomma()) + return NULL; + nex = checkfilename(p_expr(tp_str255)); + skipcloseparen(); + return assignfilename(fex, nex); +} + + + +Static Stmt *handleopen(code) +int code; +{ + Stmt *sp, *sp1, *sp2, *spassign; + Expr *fex, *nex, *ex, *truenex, *nvex; + Meaning *fmp; + int needcheckopen = 1; + char modebuf[5], *cp; + + if (!skipopenparen()) + return NULL; + fex = p_expr(tp_text); + fmp = isfilevar(fex); + nvex = filenamepart(fex); + truenex = NULL; + spassign = NULL; + if (curtok == TOK_COMMA) { + gettok(); + ex = p_expr(tp_str255); + } else + ex = NULL; + if (ex && (ex->val.type->kind == TK_STRING || + ex->val.type->kind == TK_ARRAY)) { + nex = checkfilename(ex); + if (nvex) { + spassign = assignfilename(copyexpr(fex), nex); + nex = nvex; + } + truenex = nex; + if (curtok == TOK_COMMA) { + gettok(); + ex = p_expr(tp_str255); + } else + ex = NULL; + } else if (nvex) { + nex = nvex; + } else { + switch (code) { + case 0: + if (ex) + note("Can't interpret name argument in RESET [180]"); + break; + case 1: + note("REWRITE does not specify a name [181]"); + break; + case 2: + note("OPEN does not specify a name [181]"); + break; + case 3: + note("APPEND does not specify a name [181]"); + break; + } + nex = NULL; + } + if (ex) { + if (ord_type(ex->val.type)->kind == TK_INTEGER) { + if (!checkconst(ex, 1)) + note("Ignoring block size in binary file [182]"); + freeexpr(ex); + } else { + if (ex->kind == EK_CONST && ex->val.type->kind == TK_STRING) { + cp = getstring(ex); + if (strcicmp(cp, "SHARED")) + note(format_s("Ignoring option string \"%s\" in open [183]", cp)); + } else + note("Ignoring option string in open [183]"); + } + } + switch (code) { + + case 0: /* reset */ + strcpy(modebuf, "r"); + break; + + case 1: /* rewrite */ + strcpy(modebuf, "w"); + break; + + case 2: /* open */ + strcpy(modebuf, openmode); + break; + + case 3: /* append */ + strcpy(modebuf, "a"); + break; + + } + if (!*modebuf) { + strcpy(modebuf, "r+"); + } + if (readwriteopen == 2 || + (readwriteopen && + fex->val.type != tp_text && + fex->val.type != tp_bigtext)) { + if (!my_strchr(modebuf, '+')) + strcat(modebuf, "+"); + } + if (fex->val.type != tp_text && + fex->val.type != tp_bigtext && + binarymode != 0) { + if (binarymode == 1) + strcat(modebuf, "b"); + else + note("Opening a binary file [184]"); + } + if (!nex && fmp && + !is_std_file(fex) && + literalfilesflag > 0 && + (literalfilesflag == 1 || + strlist_cifind(literalfiles, fmp->name))) { + nex = makeexpr_string(fmp->name); + } + sp1 = NULL; + sp2 = NULL; + if (!nex || (isfiletype(fex->val.type, 1) && !truenex)) { + if (isvar(fex, mp_output)) { + note("RESET/REWRITE ignored for file OUTPUT [319]"); + } else { + sp1 = makestmt_call(makeexpr_bicall_1("rewind", tp_void, + filebasename(copyexpr(fex)))); + if (code == 0 || is_std_file(fex)) { + sp1 = wrapopencheck(sp1, copyexpr(fex)); + needcheckopen = 0; + } else + sp1 = makestmt_if(makeexpr_rel(EK_NE, + filebasename(copyexpr(fex)), + makeexpr_nil()), + sp1, + makestmt_assign(filebasename(copyexpr(fex)), + makeexpr_bicall_0("tmpfile", + tp_text))); + } + } + if (nex || isfiletype(fex->val.type, 1)) { + needcheckopen = 1; + if (!strcmp(freopenname, "fclose") || + !strcmp(freopenname, "fopen")) { + sp2 = makestmt_assign(filebasename(copyexpr(fex)), + makeexpr_bicall_2("fopen", tp_text, + copyexpr(nex), + makeexpr_string(modebuf))); + if (!strcmp(freopenname, "fclose")) { + sp2 = makestmt_seq(makestmt_if(makeexpr_rel(EK_NE, + filebasename(copyexpr(fex)), + makeexpr_nil()), + makestmt_call(makeexpr_bicall_1("fclose", tp_void, + filebasename(copyexpr(fex)))), + NULL), + sp2); + } + } else { + sp2 = makestmt_assign(filebasename(copyexpr(fex)), + makeexpr_bicall_3((*freopenname) ? freopenname : "freopen", + tp_text, + copyexpr(nex), + makeexpr_string(modebuf), + filebasename(copyexpr(fex)))); + if (!*freopenname) { + sp2 = makestmt_if(makeexpr_rel(EK_NE, filebasename(copyexpr(fex)), + makeexpr_nil()), + sp2, + makestmt_assign(filebasename(copyexpr(fex)), + makeexpr_bicall_2("fopen", tp_text, + copyexpr(nex), + makeexpr_string(modebuf)))); + } + } + } + if (!sp1) + sp = sp2; + else if (!sp2) + sp = sp1; + else { + sp = makestmt_if(makeexpr_rel(EK_NE, copyexpr(nex), + makeexpr_string("")), + sp2, sp1); + } + if (code == 2 && !*openmode && nex) { + sp = makestmt_seq(sp, makestmt_if(makeexpr_rel(EK_EQ, + filebasename(copyexpr(fex)), + makeexpr_nil()), + makestmt_assign(filebasename(copyexpr(fex)), + makeexpr_bicall_2("fopen", tp_text, + copyexpr(nex), + makeexpr_string("w+"))), + NULL)); + } + if (nex) + freeexpr(nex); + if (FCheck(checkfileopen) && needcheckopen) { + sp = makestmt_seq(sp, makestmt_call(makeexpr_bicall_2("~SETIO", tp_void, + makeexpr_rel(EK_NE, filebasename(copyexpr(fex)), makeexpr_nil()), + makeexpr_name(filenotfoundname, tp_int)))); + } + sp = makestmt_seq(spassign, sp); + cp = (code == 0) ? resetbufname : setupbufname; + if (*cp && /* (may be eaten later, if buffering isn't needed) */ + fileisbuffered(fex, 1)) + sp = makestmt_seq(sp, + makestmt_call( + makeexpr_bicall_2(cp, tp_void, filebasename(fex), + makeexpr_type(filebasetype(fex->val.type))))); + else + freeexpr(fex); + skipcloseparen(); + return sp; +} + + + +Static Stmt *proc_append() +{ + return handleopen(3); +} + + + +Static Expr *func_arccos(ex) +Expr *ex; +{ + return makeexpr_bicall_1("acos", tp_longreal, grabarg(ex, 0)); +} + + +Static Expr *func_arcsin(ex) +Expr *ex; +{ + return makeexpr_bicall_1("asin", tp_longreal, grabarg(ex, 0)); +} + + +Static Expr *func_arctan(ex) +Expr *ex; +{ + ex = grabarg(ex, 0); + if (atan2flag && ex->kind == EK_DIVIDE) + return makeexpr_bicall_2("atan2", tp_longreal, + ex->args[0], ex->args[1]); + return makeexpr_bicall_1("atan", tp_longreal, ex); +} + + +Static Expr *func_arctanh(ex) +Expr *ex; +{ + return makeexpr_bicall_1("atanh", tp_longreal, grabarg(ex, 0)); +} + + + +Static Stmt *proc_argv() +{ + Expr *ex, *aex, *lex; + + if (!skipopenparen()) + return NULL; + ex = p_expr(tp_integer); + if (skipcomma()) { + aex = p_expr(tp_str255); + } else + return NULL; + skipcloseparen(); + lex = makeexpr_sizeof(copyexpr(aex), 0); + aex = makeexpr_addrstr(aex); + return makestmt_call(makeexpr_bicall_3("P_sun_argv", tp_void, + aex, lex, makeexpr_arglong(ex, 0))); +} + + +Static Expr *func_asr() +{ + Expr *ex; + + if (!skipopenparen()) + return NULL; + ex = p_expr(tp_integer); + if (skipcomma()) { + if (signedshift == 0 || signedshift == 2) { + ex = makeexpr_bicall_2("P_asr", ex->val.type, ex, + p_expr(tp_unsigned)); + } else { + ex = force_signed(ex); + ex = makeexpr_bin(EK_RSH, ex->val.type, ex, p_expr(tp_unsigned)); + if (signedshift != 1) + note("Assuming >> is an arithmetic shift [320]"); + } + skipcloseparen(); + } + return ex; +} + + +Static Expr *func_lsl() +{ + Expr *ex; + + if (!skipopenparen()) + return NULL; + ex = p_expr(tp_integer); + if (skipcomma()) { + ex = makeexpr_bin(EK_LSH, ex->val.type, ex, p_expr(tp_unsigned)); + skipcloseparen(); + } + return ex; +} + + +Static Expr *func_lsr() +{ + Expr *ex; + + if (!skipopenparen()) + return NULL; + ex = p_expr(tp_integer); + if (skipcomma()) { + ex = force_unsigned(ex); + ex = makeexpr_bin(EK_RSH, ex->val.type, ex, p_expr(tp_unsigned)); + skipcloseparen(); + } + return ex; +} + + + +Static Expr *func_bin() +{ + note("Using %b for binary printf format [185]"); + return handle_vax_hex(NULL, "b", 1); +} + + + +Static Expr *func_binary(ex) +Expr *ex; +{ + char *cp; + + ex = grabarg(ex, 0); + if (ex->kind == EK_CONST) { + cp = getstring(ex); + ex = makeexpr_long(my_strtol(cp, NULL, 2)); + insertarg(&ex, 0, makeexpr_name("%#lx", tp_integer)); + return ex; + } else { + return makeexpr_bicall_3("strtol", tp_integer, + ex, makeexpr_nil(), makeexpr_long(2)); + } +} + + + +Static Expr *handle_bitsize(next) +int next; +{ + Expr *ex; + Type *type; + int lpar; + long psize; + + lpar = (curtok == TOK_LPAR); + if (lpar) + gettok(); + if (curtok == TOK_IDENT && curtokmeaning && + curtokmeaning->kind == MK_TYPE) { + ex = makeexpr_type(curtokmeaning->type); + gettok(); + } else + ex = p_expr(NULL); + type = ex->val.type; + if (lpar) + skipcloseparen(); + psize = 0; + packedsize(NULL, &type, &psize, 0); + if (psize > 0 && psize < 32 && next) { + if (psize > 16) + psize = 32; + else if (psize > 8) + psize = 16; + else if (psize > 4) + psize = 8; + else if (psize > 2) + psize = 4; + else if (psize > 1) + psize = 2; + else + psize = 1; + } + if (psize) + return makeexpr_long(psize); + else + return makeexpr_times(makeexpr_sizeof(ex, 0), + makeexpr_long(sizeof_char ? sizeof_char : 8)); +} + + +Static Expr *func_bitsize() +{ + return handle_bitsize(0); +} + + +Static Expr *func_bitnext() +{ + return handle_bitsize(1); +} + + + +Static Expr *func_blockread() +{ + Expr *ex, *ex2, *vex, *sex, *fex; + Type *type; + + if (!skipopenparen()) + return NULL; + fex = p_expr(tp_text); + if (!skipcomma()) + return NULL; + vex = p_expr(NULL); + if (!skipcomma()) + return NULL; + ex2 = p_expr(tp_integer); + if (curtok == TOK_COMMA) { + gettok(); + sex = p_expr(tp_integer); + sex = doseek(copyexpr(fex), + makeexpr_times(sex, makeexpr_long(512)))->exp1; + } else + sex = NULL; + skipcloseparen(); + type = vex->val.type; + ex = makeexpr_bicall_4("fread", tp_integer, + makeexpr_addr(vex), + makeexpr_long(512), + convert_size(type, ex2, "BLOCKREAD"), + filebasename(copyexpr(fex))); + return makeexpr_comma(sex, ex); +} + + + +Static Expr *func_blockwrite() +{ + Expr *ex, *ex2, *vex, *sex, *fex; + Type *type; + + if (!skipopenparen()) + return NULL; + fex = p_expr(tp_text); + if (!skipcomma()) + return NULL; + vex = p_expr(NULL); + if (!skipcomma()) + return NULL; + ex2 = p_expr(tp_integer); + if (curtok == TOK_COMMA) { + gettok(); + sex = p_expr(tp_integer); + sex = doseek(copyexpr(fex), + makeexpr_times(sex, makeexpr_long(512)))->exp1; + } else + sex = NULL; + skipcloseparen(); + type = vex->val.type; + ex = makeexpr_bicall_4("fwrite", tp_integer, + makeexpr_addr(vex), + makeexpr_long(512), + convert_size(type, ex2, "BLOCKWRITE"), + filebasename(copyexpr(fex))); + return makeexpr_comma(sex, ex); +} + + + + +Static Stmt *proc_blockread() +{ + Expr *ex, *ex2, *vex, *rex, *fex; + Type *type; + + if (!skipopenparen()) + return NULL; + fex = p_expr(tp_text); + if (!skipcomma()) + return NULL; + vex = p_expr(NULL); + if (!skipcomma()) + return NULL; + ex2 = p_expr(tp_integer); + if (curtok == TOK_COMMA) { + gettok(); + rex = p_expr(tp_integer); + } else + rex = NULL; + skipcloseparen(); + type = vex->val.type; + if (rex) { + ex = makeexpr_bicall_4("fread", tp_integer, + makeexpr_addr(vex), + makeexpr_long(1), + convert_size(type, ex2, "BLOCKREAD"), + filebasename(copyexpr(fex))); + ex = makeexpr_assign(rex, ex); + if (!iocheck_flag) + ex = makeexpr_comma(ex, + makeexpr_assign(makeexpr_var(mp_ioresult), + makeexpr_long(0))); + } else { + ex = makeexpr_bicall_4("fread", tp_integer, + makeexpr_addr(vex), + convert_size(type, ex2, "BLOCKREAD"), + makeexpr_long(1), + filebasename(copyexpr(fex))); + if (checkeof(fex)) { + ex = makeexpr_bicall_2(name_SETIO, tp_void, + makeexpr_rel(EK_EQ, ex, makeexpr_long(1)), + makeexpr_name(endoffilename, tp_int)); + } + } + return wrapopencheck(makestmt_call(ex), fex); +} + + + + +Static Stmt *proc_blockwrite() +{ + Expr *ex, *ex2, *vex, *rex, *fex; + Type *type; + + if (!skipopenparen()) + return NULL; + fex = p_expr(tp_text); + if (!skipcomma()) + return NULL; + vex = p_expr(NULL); + if (!skipcomma()) + return NULL; + ex2 = p_expr(tp_integer); + if (curtok == TOK_COMMA) { + gettok(); + rex = p_expr(tp_integer); + } else + rex = NULL; + skipcloseparen(); + type = vex->val.type; + if (rex) { + ex = makeexpr_bicall_4("fwrite", tp_integer, + makeexpr_addr(vex), + makeexpr_long(1), + convert_size(type, ex2, "BLOCKWRITE"), + filebasename(copyexpr(fex))); + ex = makeexpr_assign(rex, ex); + if (!iocheck_flag) + ex = makeexpr_comma(ex, + makeexpr_assign(makeexpr_var(mp_ioresult), + makeexpr_long(0))); + } else { + ex = makeexpr_bicall_4("fwrite", tp_integer, + makeexpr_addr(vex), + convert_size(type, ex2, "BLOCKWRITE"), + makeexpr_long(1), + filebasename(copyexpr(fex))); + if (FCheck(checkfilewrite)) { + ex = makeexpr_bicall_2(name_SETIO, tp_void, + makeexpr_rel(EK_EQ, ex, makeexpr_long(1)), + makeexpr_name(filewriteerrorname, tp_int)); + } + } + return wrapopencheck(makestmt_call(ex), fex); +} + + + +Static Stmt *proc_bclr() +{ + Expr *ex, *ex2; + + if (!skipopenparen()) + return NULL; + ex = p_expr(tp_integer); + if (!skipcomma()) + return NULL; + ex2 = p_expr(tp_integer); + skipcloseparen(); + return makestmt_assign(ex, + makeexpr_bin(EK_BAND, ex->val.type, + copyexpr(ex), + makeexpr_un(EK_BNOT, ex->val.type, + makeexpr_bin(EK_LSH, tp_integer, + makeexpr_arglong( + makeexpr_long(1), 1), + ex2)))); +} + + + +Static Stmt *proc_bset() +{ + Expr *ex, *ex2; + + if (!skipopenparen()) + return NULL; + ex = p_expr(tp_integer); + if (!skipcomma()) + return NULL; + ex2 = p_expr(tp_integer); + skipcloseparen(); + return makestmt_assign(ex, + makeexpr_bin(EK_BOR, ex->val.type, + copyexpr(ex), + makeexpr_bin(EK_LSH, tp_integer, + makeexpr_arglong( + makeexpr_long(1), 1), + ex2))); +} + + + +Static Expr *func_bsl() +{ + Expr *ex, *ex2; + + if (!skipopenparen()) + return NULL; + ex = p_expr(tp_integer); + if (!skipcomma()) + return NULL; + ex2 = p_expr(tp_integer); + skipcloseparen(); + return makeexpr_bin(EK_LSH, tp_integer, ex, ex2); +} + + + +Static Expr *func_bsr() +{ + Expr *ex, *ex2; + + if (!skipopenparen()) + return NULL; + ex = p_expr(tp_integer); + if (!skipcomma()) + return NULL; + ex2 = p_expr(tp_integer); + skipcloseparen(); + return makeexpr_bin(EK_RSH, tp_integer, force_unsigned(ex), ex2); +} + + + +Static Expr *func_btst() +{ + Expr *ex, *ex2; + + if (!skipopenparen()) + return NULL; + ex = p_expr(tp_integer); + if (!skipcomma()) + return NULL; + ex2 = p_expr(tp_integer); + skipcloseparen(); + return makeexpr_rel(EK_NE, + makeexpr_bin(EK_BAND, tp_integer, + ex, + makeexpr_bin(EK_LSH, tp_integer, + makeexpr_arglong( + makeexpr_long(1), 1), + ex2)), + makeexpr_long(0)); +} + + + +Static Expr *func_byteread() +{ + Expr *ex, *ex2, *vex, *sex, *fex; + Type *type; + + if (!skipopenparen()) + return NULL; + fex = p_expr(tp_text); + if (!skipcomma()) + return NULL; + vex = p_expr(NULL); + if (!skipcomma()) + return NULL; + ex2 = p_expr(tp_integer); + if (curtok == TOK_COMMA) { + gettok(); + sex = p_expr(tp_integer); + sex = doseek(copyexpr(fex), sex)->exp1; + } else + sex = NULL; + skipcloseparen(); + type = vex->val.type; + ex = makeexpr_bicall_4("fread", tp_integer, + makeexpr_addr(vex), + makeexpr_long(1), + convert_size(type, ex2, "BYTEREAD"), + filebasename(copyexpr(fex))); + return makeexpr_comma(sex, ex); +} + + + +Static Expr *func_bytewrite() +{ + Expr *ex, *ex2, *vex, *sex, *fex; + Type *type; + + if (!skipopenparen()) + return NULL; + fex = p_expr(tp_text); + if (!skipcomma()) + return NULL; + vex = p_expr(NULL); + if (!skipcomma()) + return NULL; + ex2 = p_expr(tp_integer); + if (curtok == TOK_COMMA) { + gettok(); + sex = p_expr(tp_integer); + sex = doseek(copyexpr(fex), sex)->exp1; + } else + sex = NULL; + skipcloseparen(); + type = vex->val.type; + ex = makeexpr_bicall_4("fwrite", tp_integer, + makeexpr_addr(vex), + makeexpr_long(1), + convert_size(type, ex2, "BYTEWRITE"), + filebasename(copyexpr(fex))); + return makeexpr_comma(sex, ex); +} + + + +Static Expr *func_byte_offset() +{ + Type *tp; + Meaning *mp; + Expr *ex; + + if (!skipopenparen()) + return NULL; + tp = p_type(NULL); + if (!skipcomma()) + return NULL; + if (!wexpecttok(TOK_IDENT)) + return NULL; + mp = curtoksym->fbase; + while (mp && mp->rectype != tp) + mp = mp->snext; + if (!mp) + ex = makeexpr_name(curtokcase, tp_integer); + else + ex = makeexpr_name(mp->name, tp_integer); + gettok(); + skipcloseparen(); + return makeexpr_bicall_2("OFFSETOF", (size_t_long) ? tp_integer : tp_int, + makeexpr_type(tp), ex); +} + + + +Static Stmt *proc_call() +{ + Expr *ex, *ex2, *ex3; + Type *type, *tp; + Meaning *mp; + + if (!skipopenparen()) + return NULL; + ex2 = p_expr(tp_proc); + type = ex2->val.type; + if (type->kind != TK_PROCPTR && type->kind != TK_CPROCPTR) { + warning("CALL requires a procedure variable [208]"); + type = tp_proc; + } + ex = makeexpr(EK_SPCALL, 1); + ex->val.type = tp_void; + ex->args[0] = copyexpr(ex2); + if (type->escale != 0) + ex->args[0] = makeexpr_cast(makeexpr_dotq(ex2, "proc", tp_anyptr), + makepointertype(type->basetype)); + mp = type->basetype->fbase; + if (mp) { + if (wneedtok(TOK_COMMA)) + ex = p_funcarglist(ex, mp, 0, 0); + } + skipcloseparen(); + if (type->escale != 1 || hasstaticlinks == 2) { + freeexpr(ex2); + return makestmt_call(ex); + } + ex2 = makeexpr_dotq(ex2, "link", tp_anyptr), + ex3 = copyexpr(ex); + insertarg(&ex3, ex3->nargs, copyexpr(ex2)); + tp = maketype(TK_FUNCTION); + tp->basetype = type->basetype->basetype; + tp->fbase = type->basetype->fbase; + tp->issigned = 1; + ex3->args[0]->val.type = makepointertype(tp); + return makestmt_if(makeexpr_rel(EK_NE, ex2, makeexpr_nil()), + makestmt_call(ex3), + makestmt_call(ex)); +} + + + +Static Expr *func_chr() +{ + Expr *ex; + + ex = p_expr(tp_integer); + if ((exprlongness(ex) < 0 || ex->kind == EK_CAST) && ex->kind != EK_ACTCAST) + ex->val.type = tp_char; + else + ex = makeexpr_cast(ex, tp_char); + return ex; +} + + + +Static Stmt *proc_close() +{ + Stmt *sp; + Expr *fex, *ex; + char *opt; + + if (!skipopenparen()) + return NULL; + fex = p_expr(tp_text); + sp = makestmt_if(makeexpr_rel(EK_NE, filebasename(copyexpr(fex)), + makeexpr_nil()), + makestmt_call(makeexpr_bicall_1("fclose", tp_void, + filebasename(copyexpr(fex)))), + (FCheck(checkfileisopen)) + ? makestmt_call( + makeexpr_bicall_1(name_ESCIO, + tp_integer, + makeexpr_name(filenotopenname, + tp_int))) + : NULL); + if (curtok == TOK_COMMA) { + gettok(); + opt = ""; + if (curtok == TOK_IDENT && + (!strcicmp(curtokbuf, "LOCK") || + !strcicmp(curtokbuf, "PURGE") || + !strcicmp(curtokbuf, "NORMAL") || + !strcicmp(curtokbuf, "CRUNCH"))) { + opt = stralloc(curtokbuf); + gettok(); + } else { + ex = p_expr(tp_str255); + if (ex->kind == EK_CONST && ex->val.type->kind == TK_STRING) + opt = ex->val.s; + } + if (!strcicmp(opt, "PURGE")) { + note("File is being closed with PURGE option [186]"); + } + } + sp = makestmt_seq(sp, makestmt_assign(filebasename(fex), makeexpr_nil())); + skipcloseparen(); + return sp; +} + + + +Static Expr *func_concat() +{ + Expr *ex; + + if (!skipopenparen()) + return makeexpr_string("oops"); + ex = p_expr(tp_str255); + while (curtok == TOK_COMMA) { + gettok(); + ex = makeexpr_concat(ex, p_expr(tp_str255), 0); + } + skipcloseparen(); + return ex; +} + + + +Static Expr *func_copy(ex) +Expr *ex; +{ + if (isliteralconst(ex->args[3], NULL) == 2 && + ex->args[3]->val.i >= stringceiling) { + return makeexpr_bicall_3("sprintf", ex->val.type, + ex->args[0], + makeexpr_string("%s"), + bumpstring(ex->args[1], + makeexpr_unlongcast(ex->args[2]), 1)); + } + if (checkconst(ex->args[2], 1)) { + return makeexpr_addr(makeexpr_substring(ex->args[0], ex->args[1], + ex->args[2], ex->args[3])); + } + return makeexpr_bicall_4(strsubname, ex->val.type, + ex->args[0], + ex->args[1], + makeexpr_arglong(ex->args[2], 0), + makeexpr_arglong(ex->args[3], 0)); +} + + + +Static Expr *func_cos(ex) +Expr *ex; +{ + return makeexpr_bicall_1("cos", tp_longreal, grabarg(ex, 0)); +} + + +Static Expr *func_cosh(ex) +Expr *ex; +{ + return makeexpr_bicall_1("cosh", tp_longreal, grabarg(ex, 0)); +} + + + +Static Stmt *proc_cycle() +{ + return makestmt(SK_CONTINUE); +} + + + +Static Stmt *proc_date() +{ + Expr *ex; + + if (!skipopenparen()) + return NULL; + ex = p_expr(tp_str255); + skipcloseparen(); + return makestmt_call(makeexpr_bicall_1("VAXdate", tp_integer, ex)); +} + + +Static Stmt *proc_dec() +{ + Expr *vex, *ex; + + if (!skipopenparen()) + return NULL; + vex = p_expr(NULL); + if (curtok == TOK_COMMA) { + gettok(); + ex = p_expr(tp_integer); + } else + ex = makeexpr_long(1); + skipcloseparen(); + return makestmt_assign(vex, makeexpr_minus(copyexpr(vex), ex)); +} + + + +Static Expr *func_dec() +{ + return handle_vax_hex(NULL, "d", 0); +} + + + +Static Stmt *proc_delete(ex) +Expr *ex; +{ + if (ex->nargs == 1) /* Kludge for Oregon Software Pascal's delete(f) */ + return makestmt_call(makeexpr_bicall_1(strdeletename, tp_void, ex->args[0])); + return makestmt_call(makeexpr_bicall_3(strdeletename, tp_void, + ex->args[0], + makeexpr_arglong(ex->args[1], 0), + makeexpr_arglong(ex->args[2], 0))); +} + + + +void parse_special_variant(tp, buf) +Type *tp; +char *buf; +{ + char *cp; + Expr *ex; + + if (!tp) + intwarning("parse_special_variant", "tp == NULL"); + if (!tp || tp->meaning == NULL) { + *buf = 0; + if (curtok == TOK_COMMA) { + skiptotoken(TOK_RPAR); + } + return; + } + strcpy(buf, tp->meaning->name); + while (curtok == TOK_COMMA) { + gettok(); + cp = buf + strlen(buf); + *cp++ = '.'; + if (curtok == TOK_MINUS) { + *cp++ = '-'; + gettok(); + } + if (curtok == TOK_INTLIT || + curtok == TOK_HEXLIT || + curtok == TOK_OCTLIT) { + sprintf(cp, "%ld", curtokint); + gettok(); + } else if (curtok == TOK_HAT || curtok == TOK_STRLIT) { + ex = makeexpr_charcast(accumulate_strlit()); + if (ex->kind == EK_CONST) { + if (ex->val.i <= 32 || ex->val.i > 126 || + ex->val.i == '\'' || ex->val.i == '\\' || + ex->val.i == '=' || ex->val.i == '}') + sprintf(cp, "%ld", ex->val.i); + else + strcpy(cp, makeCchar(ex->val.i)); + } else { + *buf = 0; + *cp = 0; + } + freeexpr(ex); + } else { + if (!wexpecttok(TOK_IDENT)) { + skiptotoken(TOK_RPAR); + return; + } + if (curtokmeaning) + strcpy(cp, curtokmeaning->name); + else + strcpy(cp, curtokbuf); + gettok(); + } + } +} + + +char *find_special_variant(buf, spname, splist, need) +char *buf, *spname; +Strlist *splist; +int need; +{ + Strlist *best = NULL; + int len, bestlen = -1; + char *cp, *cp2; + + if (!*buf) + return NULL; + while (splist) { + cp = splist->s; + cp2 = buf; + while (*cp && toupper(*cp) == toupper(*cp2)) + cp++, cp2++; + len = cp2 - buf; + if (!*cp && (!*cp2 || *cp2 == '.') && len > bestlen) { + best = splist; + bestlen = len; + } + splist = splist->next; + } + if (bestlen != strlen(buf) && my_strchr(buf, '.')) { + if ((need & 1) || bestlen >= 0) { + if (need & 2) + return NULL; + if (spname) + note(format_ss("No %s form known for %s [187]", + spname, strupper(buf))); + } + } + if (bestlen >= 0) + return (char *)best->value; + else + return NULL; +} + + + +Static char *choose_free_func(ex) +Expr *ex; +{ + if (!*freename) { + if (!*freervaluename) + return "free"; + else + return freervaluename; + } + if (!*freervaluename) + return freervaluename; + if (expr_is_lvalue(ex)) + return freename; + else + return freervaluename; +} + + +Static Stmt *proc_dispose() +{ + Expr *ex; + Type *type; + char *name, vbuf[1000]; + + if (!skipopenparen()) + return NULL; + ex = p_expr(tp_anyptr); + type = ex->val.type->basetype; + parse_special_variant(type, vbuf); + skipcloseparen(); + name = find_special_variant(vbuf, "SpecialFree", specialfrees, 0); + if (!name) + name = choose_free_func(ex); + return makestmt_call(makeexpr_bicall_1(name, tp_void, ex)); +} + + + +Static Expr *func_exp(ex) +Expr *ex; +{ + return makeexpr_bicall_1("exp", tp_longreal, grabarg(ex, 0)); +} + + + +Static Expr *func_expo(ex) +Expr *ex; +{ + Meaning *tvar; + + tvar = makestmttempvar(tp_int, name_TEMP); + return makeexpr_comma(makeexpr_bicall_2("frexp", tp_longreal, + grabarg(ex, 0), + makeexpr_addr(makeexpr_var(tvar))), + makeexpr_var(tvar)); +} + + + +int is_std_file(ex) +Expr *ex; +{ + return isvar(ex, mp_input) || isvar(ex, mp_output) || + isvar(ex, mp_stderr); +} + + + +Static Expr *iofunc(ex, code) +Expr *ex; +int code; +{ + Expr *ex2 = NULL, *ex3 = NULL; + Meaning *tvar = NULL; + + if (FCheck(checkfileisopen) && !is_std_file(ex)) { + if (isfiletype(ex->val.type, 1) || + (exprspeed(ex) < 5 && nosideeffects(ex, 0))) { + ex2 = filebasename(copyexpr(ex)); + } else { + ex3 = ex; + tvar = makestmttempvar(ex->val.type, name_TEMP); + ex2 = makeexpr_var(tvar); + ex = makeexpr_var(tvar); + } + } + ex = filebasename(ex); + switch (code) { + + case 0: /* eof */ + if (fileisbuffered(ex, 0) && *eofbufname) + ex = makeexpr_bicall_1(eofbufname, tp_boolean, ex); + else if (*eofname) + ex = makeexpr_bicall_1(eofname, tp_boolean, ex); + else + ex = makeexpr_rel(EK_NE, makeexpr_bicall_1("feof", tp_int, ex), + makeexpr_long(0)); + break; + + case 1: /* eoln */ + ex = makeexpr_bicall_1(eolnname, tp_boolean, ex); + break; + + case 2: /* position or filepos */ + if (fileisbuffered(ex, 0) && *fileposbufname) + ex = makeexpr_bicall_1(fileposbufname, tp_integer, ex); + else + ex = makeexpr_bicall_1(fileposname, tp_integer, ex); + break; + + case 3: /* maxpos or filesize */ + ex = makeexpr_bicall_1(maxposname, tp_integer, ex); + break; + + } + if (ex2) { + ex = makeexpr_bicall_4("~CHKIO", + (code == 0 || code == 1) ? tp_boolean : tp_integer, + makeexpr_rel(EK_NE, ex2, makeexpr_nil()), + makeexpr_name("FileNotOpen", tp_int), + ex, makeexpr_long(0)); + } + if (ex3) + ex = makeexpr_comma(makeexpr_assign(makeexpr_var(tvar), ex3), ex); + return ex; +} + + + +Static Expr *func_eof() +{ + Expr *ex; + + if (curtok == TOK_LPAR) + ex = p_parexpr(tp_text); + else + ex = makeexpr_var(mp_input); + return iofunc(ex, 0); +} + + + +Static Expr *func_eoln() +{ + Expr *ex; + + if (curtok == TOK_LPAR) + ex = p_parexpr(tp_text); + else + ex = makeexpr_var(mp_input); + return iofunc(ex, 1); +} + + + +Static Stmt *proc_escape() +{ + Expr *ex; + + if (curtok == TOK_LPAR) + ex = p_parexpr(tp_integer); + else + ex = makeexpr_long(0); + return makestmt_call(makeexpr_bicall_1(name_ESCAPE, tp_int, + makeexpr_arglong(ex, 0))); +} + + + +Static Stmt *proc_excl() +{ + Expr *vex, *ex; + + if (!skipopenparen()) + return NULL; + vex = p_expr(NULL); + if (!skipcomma()) + return NULL; + ex = p_expr(vex->val.type->indextype); + skipcloseparen(); + if (vex->val.type->kind == TK_SMALLSET) + return makestmt_assign(vex, makeexpr_bin(EK_BAND, vex->val.type, + copyexpr(vex), + makeexpr_un(EK_BNOT, vex->val.type, + makeexpr_bin(EK_LSH, vex->val.type, + makeexpr_longcast(makeexpr_long(1), 1), + ex)))); + else + return makestmt_call(makeexpr_bicall_2(setremname, tp_void, vex, + makeexpr_arglong(enum_to_int(ex), 0))); +} + + + +Stmt *proc_exit() +{ + Stmt *sp; + + if (modula2) { + return makestmt(SK_BREAK); + } + if (curtok == TOK_LPAR) { + gettok(); + if (curtok == TOK_PROGRAM || + (curtok == TOK_IDENT && curtokmeaning->kind == MK_MODULE)) { + gettok(); + skipcloseparen(); + return makestmt_call(makeexpr_bicall_1("exit", tp_void, + makeexpr_name("EXIT_SUCCESS", + tp_integer))); + } + if (curtok != TOK_IDENT || !curtokmeaning || curtokmeaning != curctx) + note("Attempting to EXIT beyond this function [188]"); + gettok(); + skipcloseparen(); + } + sp = makestmt(SK_RETURN); + if (curctx->kind == MK_FUNCTION && curctx->isfunction) { + sp->exp1 = makeexpr_var(curctx->cbase); + curctx->cbase->refcount++; + } + return sp; +} + + + +Static Expr *file_iofunc(code, base) +int code; +long base; +{ + Expr *ex; + Type *basetype; + + if (curtok == TOK_LPAR) + ex = p_parexpr(tp_text); + else + ex = makeexpr_var(mp_input); + if (!ex->val.type || !ex->val.type->basetype || + !filebasetype(ex->val.type)) + basetype = tp_char; + else + basetype = filebasetype(ex->val.type); + return makeexpr_plus(makeexpr_div(iofunc(ex, code), + makeexpr_sizeof(makeexpr_type(basetype), 0)), + makeexpr_long(base)); +} + + + +Static Expr *func_fcall() +{ + Expr *ex, *ex2, *ex3; + Type *type, *tp; + Meaning *mp, *tvar = NULL; + int firstarg = 0; + + if (!skipopenparen()) + return NULL; + ex2 = p_expr(tp_proc); + type = ex2->val.type; + if (type->kind != TK_PROCPTR && type->kind != TK_CPROCPTR) { + warning("FCALL requires a function variable [209]"); + type = tp_proc; + } + ex = makeexpr(EK_SPCALL, 1); + ex->val.type = type->basetype->basetype; + ex->args[0] = copyexpr(ex2); + if (type->escale != 0) + ex->args[0] = makeexpr_cast(makeexpr_dotq(ex2, "proc", tp_anyptr), + makepointertype(type->basetype)); + mp = type->basetype->fbase; + if (mp && mp->isreturn) { /* pointer to buffer for return value */ + tvar = makestmttempvar(ex->val.type->basetype, + (ex->val.type->basetype->kind == TK_STRING) ? name_STRING : name_TEMP); + insertarg(&ex, 1, makeexpr_addr(makeexpr_var(tvar))); + mp = mp->xnext; + firstarg++; + } + if (mp) { + if (wneedtok(TOK_COMMA)) + ex = p_funcarglist(ex, mp, 0, 0); + } + if (tvar) + ex = makeexpr_hat(ex, 0); /* returns pointer to structured result */ + skipcloseparen(); + if (type->escale != 1 || hasstaticlinks == 2) { + freeexpr(ex2); + return ex; + } + ex2 = makeexpr_dotq(ex2, "link", tp_anyptr), + ex3 = copyexpr(ex); + insertarg(&ex3, ex3->nargs, copyexpr(ex2)); + tp = maketype(TK_FUNCTION); + tp->basetype = type->basetype->basetype; + tp->fbase = type->basetype->fbase; + tp->issigned = 1; + ex3->args[0]->val.type = makepointertype(tp); + return makeexpr_cond(makeexpr_rel(EK_NE, ex2, makeexpr_nil()), + ex3, ex); +} + + + +Static Expr *func_filepos() +{ + return file_iofunc(2, seek_base); +} + + + +Static Expr *func_filesize() +{ + return file_iofunc(3, 1L); +} + + + +Static Stmt *proc_fillchar() +{ + Expr *vex, *ex, *cex; + + if (!skipopenparen()) + return NULL; + vex = gentle_cast(makeexpr_addr(p_expr(NULL)), tp_anyptr); + if (!skipcomma()) + return NULL; + ex = convert_size(argbasetype(vex), p_expr(tp_integer), "FILLCHAR"); + if (!skipcomma()) + return NULL; + cex = makeexpr_charcast(p_expr(tp_integer)); + skipcloseparen(); + return makestmt_call(makeexpr_bicall_3("memset", tp_void, + vex, + makeexpr_arglong(cex, 0), + makeexpr_arglong(ex, (size_t_long != 0)))); +} + + + +Static Expr *func_sngl() +{ + Expr *ex; + + ex = p_parexpr(tp_real); + return makeexpr_cast(ex, tp_real); +} + + + +Static Expr *func_float() +{ + Expr *ex; + + ex = p_parexpr(tp_longreal); + return makeexpr_cast(ex, tp_longreal); +} + + + +Static Stmt *proc_flush() +{ + Expr *ex; + Stmt *sp; + + ex = p_parexpr(tp_text); + sp = makestmt_call(makeexpr_bicall_1("fflush", tp_void, filebasename(ex))); + if (iocheck_flag) + sp = makestmt_seq(sp, makestmt_assign(makeexpr_var(mp_ioresult), + makeexpr_long(0))); + return sp; +} + + + +Static Expr *func_frac(ex) +Expr *ex; +{ + Meaning *tvar; + + tvar = makestmttempvar(tp_longreal, name_DUMMY); + return makeexpr_bicall_2("modf", tp_longreal, + grabarg(ex, 0), + makeexpr_addr(makeexpr_var(tvar))); +} + + + +Static Stmt *proc_freemem(ex) +Expr *ex; +{ + Stmt *sp; + Expr *vex; + + vex = makeexpr_hat(eatcasts(ex->args[0]), 0); + sp = makestmt_call(makeexpr_bicall_1(choose_free_func(vex), + tp_void, copyexpr(vex))); + if (alloczeronil) { + sp = makestmt_if(makeexpr_rel(EK_NE, vex, makeexpr_nil()), + sp, NULL); + } else + freeexpr(vex); + return sp; +} + + + +Static Stmt *proc_get() +{ + Expr *ex; + Type *type; + + if (curtok == TOK_LPAR) + ex = p_parexpr(tp_text); + else + ex = makeexpr_var(mp_input); + requirefilebuffer(ex); + type = ex->val.type; + if (isfiletype(type, -1) && *chargetname && + filebasetype(type)->kind == TK_CHAR) + return makestmt_call(makeexpr_bicall_1(chargetname, tp_void, + filebasename(ex))); + else if (isfiletype(type, -1) && *arraygetname && + filebasetype(type)->kind == TK_ARRAY) + return makestmt_call(makeexpr_bicall_2(arraygetname, tp_void, + filebasename(ex), + makeexpr_type(filebasetype(type)))); + else + return makestmt_call(makeexpr_bicall_2(getname, tp_void, + filebasename(ex), + makeexpr_type(filebasetype(type)))); +} + + + +Static Stmt *proc_getmem(ex) +Expr *ex; +{ + Expr *vex, *ex2, *sz = NULL; + Stmt *sp; + + vex = makeexpr_hat(eatcasts(ex->args[0]), 0); + ex2 = ex->args[1]; + if (vex->val.type->kind == TK_POINTER) + ex2 = convert_size(vex->val.type->basetype, ex2, "GETMEM"); + if (alloczeronil) + sz = copyexpr(ex2); + ex2 = makeexpr_bicall_1(mallocname, tp_anyptr, ex2); + sp = makestmt_assign(copyexpr(vex), ex2); + if (malloccheck) { + sp = makestmt_seq(sp, makestmt_if(makeexpr_rel(EK_EQ, copyexpr(vex), makeexpr_nil()), + makestmt_call(makeexpr_bicall_0(name_OUTMEM, tp_int)), + NULL)); + } + if (sz && !isconstantexpr(sz)) { + if (alloczeronil == 2) + note("Called GETMEM with variable argument [189]"); + sp = makestmt_if(makeexpr_rel(EK_NE, sz, makeexpr_long(0)), + sp, + makestmt_assign(vex, makeexpr_nil())); + } else + freeexpr(vex); + return sp; +} + + + +Static Stmt *proc_gotoxy(ex) +Expr *ex; +{ + return makestmt_call(makeexpr_bicall_2("gotoxy", tp_void, + makeexpr_arglong(ex->args[0], 0), + makeexpr_arglong(ex->args[1], 0))); +} + + + +Static Expr *handle_vax_hex(ex, fmt, scale) +Expr *ex; +char *fmt; +int scale; +{ + Expr *lex, *dex, *vex; + Meaning *tvar; + Type *tp; + long smin, smax; + int bits; + + if (!ex) { + if (!skipopenparen()) + return NULL; + ex = p_expr(tp_integer); + } + tp = true_type(ex); + if (ord_range(tp, &smin, &smax)) + bits = typebits(smin, smax); + else + bits = 32; + if (curtok == TOK_COMMA) { + gettok(); + if (curtok != TOK_COMMA) + lex = makeexpr_arglong(p_expr(tp_integer), 0); + else + lex = NULL; + } else + lex = NULL; + if (!lex) { + if (!scale) + lex = makeexpr_long(11); + else + lex = makeexpr_long((bits+scale-1) / scale + 1); + } + if (curtok == TOK_COMMA) { + gettok(); + dex = makeexpr_arglong(p_expr(tp_integer), 0); + } else { + if (!scale) + dex = makeexpr_long(10); + else + dex = makeexpr_long((bits+scale-1) / scale); + } + if (lex->kind == EK_CONST && dex->kind == EK_CONST && + lex->val.i < dex->val.i) + lex = NULL; + skipcloseparen(); + tvar = makestmttempvar(tp_str255, name_STRING); + vex = makeexpr_var(tvar); + ex = makeexpr_forcelongness(ex); + if (exprlongness(ex) > 0) + fmt = format_s("l%s", fmt); + if (checkconst(lex, 0) || checkconst(lex, 1)) + lex = NULL; + if (checkconst(dex, 0) || checkconst(dex, 1)) + dex = NULL; + if (lex) { + if (dex) + ex = makeexpr_bicall_5("sprintf", tp_str255, vex, + makeexpr_string(format_s("%%*.*%s", fmt)), + lex, dex, ex); + else + ex = makeexpr_bicall_4("sprintf", tp_str255, vex, + makeexpr_string(format_s("%%*%s", fmt)), + lex, ex); + } else { + if (dex) + ex = makeexpr_bicall_4("sprintf", tp_str255, vex, + makeexpr_string(format_s("%%.*%s", fmt)), + dex, ex); + else + ex = makeexpr_bicall_3("sprintf", tp_str255, vex, + makeexpr_string(format_s("%%%s", fmt)), + ex); + } + return ex; +} + + + + +Static Expr *func_hex() +{ + Expr *ex; + char *cp; + + if (!skipopenparen()) + return NULL; + ex = makeexpr_stringcast(p_expr(tp_integer)); + if ((ex->val.type->kind == TK_STRING || + ex->val.type == tp_strptr) && + curtok != TOK_COMMA) { + skipcloseparen(); + if (ex->kind == EK_CONST) { /* HP Pascal */ + cp = getstring(ex); + ex = makeexpr_long(my_strtol(cp, NULL, 16)); + insertarg(&ex, 0, makeexpr_name("%#lx", tp_integer)); + return ex; + } else { + return makeexpr_bicall_3("strtol", tp_integer, + ex, makeexpr_nil(), makeexpr_long(16)); + } + } else { /* VAX Pascal */ + return handle_vax_hex(ex, "x", 4); + } +} + + + +Static Expr *func_hi() +{ + Expr *ex; + + ex = force_unsigned(p_parexpr(tp_integer)); + return makeexpr_bin(EK_RSH, tp_ubyte, + ex, makeexpr_long(8)); +} + + + +Static Expr *func_high() +{ + Expr *ex; + Type *type; + + ex = p_parexpr(tp_integer); + type = ex->val.type; + if (type->kind == TK_POINTER) + type = type->basetype; + if (type->kind == TK_ARRAY || + type->kind == TK_SMALLARRAY) { + ex = makeexpr_minus(copyexpr(type->indextype->smax), + copyexpr(type->indextype->smin)); + } else { + warning("HIGH requires an array name parameter [210]"); + ex = makeexpr_bicall_1("HIGH", tp_int, ex); + } + return ex; +} + + + +Static Expr *func_hiword() +{ + Expr *ex; + + ex = force_unsigned(p_parexpr(tp_unsigned)); + return makeexpr_bin(EK_RSH, tp_unsigned, + ex, makeexpr_long(16)); +} + + + +Static Stmt *proc_inc() +{ + Expr *vex, *ex; + + if (!skipopenparen()) + return NULL; + vex = p_expr(NULL); + if (curtok == TOK_COMMA) { + gettok(); + ex = p_expr(tp_integer); + } else + ex = makeexpr_long(1); + skipcloseparen(); + return makestmt_assign(vex, makeexpr_plus(copyexpr(vex), ex)); +} + + + +Static Stmt *proc_incl() +{ + Expr *vex, *ex; + + if (!skipopenparen()) + return NULL; + vex = p_expr(NULL); + if (!skipcomma()) + return NULL; + ex = p_expr(vex->val.type->indextype); + skipcloseparen(); + if (vex->val.type->kind == TK_SMALLSET) + return makestmt_assign(vex, makeexpr_bin(EK_BOR, vex->val.type, + copyexpr(vex), + makeexpr_bin(EK_LSH, vex->val.type, + makeexpr_longcast(makeexpr_long(1), 1), + ex))); + else + return makestmt_call(makeexpr_bicall_2(setaddname, tp_void, vex, + makeexpr_arglong(enum_to_int(ex), 0))); +} + + + +Static Stmt *proc_insert(ex) +Expr *ex; +{ + return makestmt_call(makeexpr_bicall_3(strinsertname, tp_void, + ex->args[0], + ex->args[1], + makeexpr_arglong(ex->args[2], 0))); +} + + + +Static Expr *func_int() +{ + Expr *ex; + Meaning *tvar; + + ex = p_parexpr(tp_integer); + if (ex->val.type->kind == TK_REAL) { /* Turbo Pascal INT */ + tvar = makestmttempvar(tp_longreal, name_TEMP); + return makeexpr_comma(makeexpr_bicall_2("modf", tp_longreal, + grabarg(ex, 0), + makeexpr_addr(makeexpr_var(tvar))), + makeexpr_var(tvar)); + } else { /* VAX Pascal INT */ + return makeexpr_ord(ex); + } +} + + +Static Expr *func_uint() +{ + Expr *ex; + + ex = p_parexpr(tp_integer); + return makeexpr_cast(ex, tp_unsigned); +} + + + +Static Stmt *proc_leave() +{ + return makestmt(SK_BREAK); +} + + + +Static Expr *func_lo() +{ + Expr *ex; + + ex = gentle_cast(p_parexpr(tp_integer), tp_ushort); + return makeexpr_bin(EK_BAND, tp_ubyte, + ex, makeexpr_long(255)); +} + + +Static Expr *func_loophole() +{ + Type *type; + Expr *ex; + + if (!skipopenparen()) + return NULL; + type = p_type(NULL); + if (!skipcomma()) + return NULL; + ex = p_expr(tp_integer); + skipcloseparen(); + return pascaltypecast(type, ex); +} + + + +Static Expr *func_lower() +{ + Expr *ex; + Value val; + + if (!skipopenparen()) + return NULL; + ex = p_expr(tp_integer); + if (curtok == TOK_COMMA) { + gettok(); + val = p_constant(tp_integer); + if (!val.type || val.i != 1) + note("LOWER(v,n) not supported for n>1 [190]"); + } + skipcloseparen(); + return copyexpr(ex->val.type->indextype->smin); +} + + + +Static Expr *func_loword() +{ + Expr *ex; + + ex = p_parexpr(tp_integer); + return makeexpr_bin(EK_BAND, tp_ushort, + ex, makeexpr_long(65535)); +} + + + +Static Expr *func_ln(ex) +Expr *ex; +{ + return makeexpr_bicall_1("log", tp_longreal, grabarg(ex, 0)); +} + + + +Static Expr *func_log(ex) +Expr *ex; +{ + return makeexpr_bicall_1("log10", tp_longreal, grabarg(ex, 0)); +} + + + +Static Expr *func_max() +{ + Type *tp; + Expr *ex, *ex2; + + if (!skipopenparen()) + return NULL; + if (curtok == TOK_IDENT && curtokmeaning && + curtokmeaning->kind == MK_TYPE) { + tp = curtokmeaning->type; + gettok(); + skipcloseparen(); + return copyexpr(tp->smax); + } + ex = p_expr(tp_integer); + while (curtok == TOK_COMMA) { + gettok(); + ex2 = p_expr(ex->val.type); + if (ex->val.type->kind == TK_REAL) { + tp = ex->val.type; + if (ex2->val.type->kind != TK_REAL) + ex2 = makeexpr_cast(ex2, tp); + } else { + tp = ex2->val.type; + if (ex->val.type->kind != TK_REAL) + ex = makeexpr_cast(ex, tp); + } + ex = makeexpr_bicall_2((tp->kind == TK_REAL) ? "P_rmax" : "P_imax", + tp, ex, ex2); + } + skipcloseparen(); + return ex; +} + + + +Static Expr *func_maxavail(ex) +Expr *ex; +{ + freeexpr(ex); + return makeexpr_bicall_0("maxavail", tp_integer); +} + + + +Static Expr *func_maxpos() +{ + return file_iofunc(3, seek_base); +} + + + +Static Expr *func_memavail(ex) +Expr *ex; +{ + freeexpr(ex); + return makeexpr_bicall_0("memavail", tp_integer); +} + + + +Static Expr *var_mem() +{ + Expr *ex, *ex2; + + if (!wneedtok(TOK_LBR)) + return makeexpr_name("MEM", tp_integer); + ex = p_expr(tp_integer); + if (curtok == TOK_COLON) { + gettok(); + ex2 = p_expr(tp_integer); + ex = makeexpr_bicall_2("MEM", tp_ubyte, ex, ex2); + } else { + ex = makeexpr_bicall_1("MEM", tp_ubyte, ex); + } + if (!wneedtok(TOK_RBR)) + skippasttotoken(TOK_RBR, TOK_SEMI); + note("Reference to MEM [191]"); + return ex; +} + + + +Static Expr *var_memw() +{ + Expr *ex, *ex2; + + if (!wneedtok(TOK_LBR)) + return makeexpr_name("MEMW", tp_integer); + ex = p_expr(tp_integer); + if (curtok == TOK_COLON) { + gettok(); + ex2 = p_expr(tp_integer); + ex = makeexpr_bicall_2("MEMW", tp_ushort, ex, ex2); + } else { + ex = makeexpr_bicall_1("MEMW", tp_ushort, ex); + } + if (!wneedtok(TOK_RBR)) + skippasttotoken(TOK_RBR, TOK_SEMI); + note("Reference to MEMW [191]"); + return ex; +} + + + +Static Expr *var_meml() +{ + Expr *ex, *ex2; + + if (!wneedtok(TOK_LBR)) + return makeexpr_name("MEML", tp_integer); + ex = p_expr(tp_integer); + if (curtok == TOK_COLON) { + gettok(); + ex2 = p_expr(tp_integer); + ex = makeexpr_bicall_2("MEML", tp_integer, ex, ex2); + } else { + ex = makeexpr_bicall_1("MEML", tp_integer, ex); + } + if (!wneedtok(TOK_RBR)) + skippasttotoken(TOK_RBR, TOK_SEMI); + note("Reference to MEML [191]"); + return ex; +} + + + +Static Expr *func_min() +{ + Type *tp; + Expr *ex, *ex2; + + if (!skipopenparen()) + return NULL; + if (curtok == TOK_IDENT && curtokmeaning && + curtokmeaning->kind == MK_TYPE) { + tp = curtokmeaning->type; + gettok(); + skipcloseparen(); + return copyexpr(tp->smin); + } + ex = p_expr(tp_integer); + while (curtok == TOK_COMMA) { + gettok(); + ex2 = p_expr(ex->val.type); + if (ex->val.type->kind == TK_REAL) { + tp = ex->val.type; + if (ex2->val.type->kind != TK_REAL) + ex2 = makeexpr_cast(ex2, tp); + } else { + tp = ex2->val.type; + if (ex->val.type->kind != TK_REAL) + ex = makeexpr_cast(ex, tp); + } + ex = makeexpr_bicall_2((tp->kind == TK_REAL) ? "P_rmin" : "P_imin", + tp, ex, ex2); + } + skipcloseparen(); + return ex; +} + + + +Static Stmt *proc_move(ex) +Expr *ex; +{ + ex->args[0] = gentle_cast(ex->args[0], tp_anyptr); /* source */ + ex->args[1] = gentle_cast(ex->args[1], tp_anyptr); /* dest */ + ex->args[2] = convert_size(choosetype(argbasetype(ex->args[0]), + argbasetype(ex->args[1])), ex->args[2], "MOVE"); + return makestmt_call(makeexpr_bicall_3("memmove", tp_void, + ex->args[1], + ex->args[0], + makeexpr_arglong(ex->args[2], (size_t_long != 0)))); +} + + + +Static Stmt *proc_move_fast() +{ + Expr *ex, *ex2, *ex3, *ex4; + + if (!skipopenparen()) + return NULL; + ex = p_expr(tp_integer); + if (!skipcomma()) + return NULL; + ex2 = p_expr(tp_integer); + if (!skipcomma()) + return NULL; + ord_range_expr(ex2->val.type->indextype, &ex4, NULL); + ex2 = makeexpr_index(ex2, p_expr(tp_integer), copyexpr(ex4)); + if (!skipcomma()) + return NULL; + ex3 = p_expr(tp_integer); + if (!skipcomma()) + return NULL; + ord_range_expr(ex3->val.type->indextype, &ex4, NULL); + ex3 = makeexpr_index(ex3, p_expr(tp_integer), copyexpr(ex4)); + skipcloseparen(); + ex = convert_size(choosetype(argbasetype(ex2), + argbasetype(ex3)), ex, "MOVE_FAST"); + return makestmt_call(makeexpr_bicall_3("memmove", tp_void, + makeexpr_addr(ex3), + makeexpr_addr(ex2), + makeexpr_arglong(ex, (size_t_long != 0)))); +} + + + +Static Stmt *proc_new() +{ + Expr *ex, *ex2; + Stmt *sp, **spp; + Type *type; + char *name, *name2 = NULL, vbuf[1000]; + + if (!skipopenparen()) + return NULL; + ex = p_expr(tp_anyptr); + type = ex->val.type; + if (type->kind == TK_POINTER) + type = type->basetype; + parse_special_variant(type, vbuf); + skipcloseparen(); + name = find_special_variant(vbuf, NULL, specialmallocs, 3); + if (!name) { + name2 = find_special_variant(vbuf, NULL, specialsizeofs, 3); + if (!name2) { + name = find_special_variant(vbuf, NULL, specialmallocs, 1); + name2 = find_special_variant(vbuf, NULL, specialsizeofs, 1); + if (name || !name2) + name = find_special_variant(vbuf, "SpecialMalloc", specialmallocs, 1); + else + name2 = find_special_variant(vbuf, "SpecialSizeOf", specialsizeofs, 1); + } + } + if (name) { + ex2 = makeexpr_bicall_0(name, ex->val.type); + } else if (name2) { + ex2 = makeexpr_bicall_1(mallocname, tp_anyptr, pc_expr_str(name2)); + } else { + ex2 = makeexpr_bicall_1(mallocname, tp_anyptr, + makeexpr_sizeof(makeexpr_type(type), 1)); + } + sp = makestmt_assign(copyexpr(ex), ex2); + if (malloccheck) { + sp = makestmt_seq(sp, makestmt_if(makeexpr_rel(EK_EQ, + copyexpr(ex), + makeexpr_nil()), + makestmt_call(makeexpr_bicall_0(name_OUTMEM, tp_int)), + NULL)); + } + spp = &sp->next; + while (*spp) + spp = &(*spp)->next; + if (type->kind == TK_RECORD) + initfilevars(type->fbase, &spp, makeexpr_hat(ex, 0)); + else if (isfiletype(type, -1)) + sp = makestmt_seq(sp, makestmt_call(initfilevar(makeexpr_hat(ex, 0)))); + else + freeexpr(ex); + return sp; +} + + + +Static Expr *func_oct() +{ + return handle_vax_hex(NULL, "o", 3); +} + + + +Static Expr *func_octal(ex) +Expr *ex; +{ + char *cp; + + ex = grabarg(ex, 0); + if (ex->kind == EK_CONST) { + cp = getstring(ex); + ex = makeexpr_long(my_strtol(cp, NULL, 8)); + insertarg(&ex, 0, makeexpr_name("0%lo", tp_integer)); + return ex; + } else { + return makeexpr_bicall_3("strtol", tp_integer, + ex, makeexpr_nil(), makeexpr_long(8)); + } +} + + + +Static Expr *func_odd(ex) +Expr *ex; +{ + ex = makeexpr_unlongcast(grabarg(ex, 0)); + if (*oddname) + return makeexpr_bicall_1(oddname, tp_boolean, ex); + else + return makeexpr_bin(EK_BAND, tp_boolean, ex, makeexpr_long(1)); +} + + + +Static Stmt *proc_open() +{ + return handleopen(2); +} + + + +Static Expr *func_ord() +{ + Expr *ex; + + if (wneedtok(TOK_LPAR)) { + ex = p_ord_expr(); + skipcloseparen(); + } else + ex = p_ord_expr(); + return makeexpr_ord(ex); +} + + + +Static Expr *func_ord4() +{ + Expr *ex; + + if (wneedtok(TOK_LPAR)) { + ex = p_ord_expr(); + skipcloseparen(); + } else + ex = p_ord_expr(); + return makeexpr_longcast(makeexpr_ord(ex), 1); +} + + + +Static Stmt *proc_pack() +{ + Expr *exs, *exd, *exi, *mind; + Meaning *tvar; + Stmt *sp; + + if (!skipopenparen()) + return NULL; + exs = p_expr(NULL); + if (!skipcomma()) + return NULL; + exi = p_ord_expr(); + if (!skipcomma()) + return NULL; + exd = p_expr(NULL); + skipcloseparen(); + if (exs->val.type->kind != TK_ARRAY || + (exd->val.type->kind != TK_ARRAY && + exd->val.type->kind != TK_SMALLARRAY)) { + warning("Bad argument types for PACK/UNPACK [325]"); + return makestmt_call(makeexpr_bicall_3("pack", tp_void, + exs, exi, exd)); + } + if (exs->val.type->smax || exd->val.type->smax) { + tvar = makestmttempvar(exd->val.type->indextype, name_TEMP); + sp = makestmt(SK_FOR); + if (exd->val.type->smin) + mind = exd->val.type->smin; + else + mind = exd->val.type->indextype->smin; + sp->exp1 = makeexpr_assign(makeexpr_var(tvar), + copyexpr(mind)); + sp->exp2 = makeexpr_rel(EK_LE, makeexpr_var(tvar), + copyexpr(exd->val.type->indextype->smax)); + sp->exp3 = makeexpr_assign(makeexpr_var(tvar), + makeexpr_plus(makeexpr_var(tvar), + makeexpr_long(1))); + exi = makeexpr_minus(exi, copyexpr(mind)); + sp->stm1 = makestmt_assign(p_index(exd, makeexpr_var(tvar)), + p_index(exs, + makeexpr_plus(makeexpr_var(tvar), + exi))); + return sp; + } else { + exi = gentle_cast(exi, exs->val.type->indextype); + return makestmt_call(makeexpr_bicall_3("memcpy", exd->val.type, + exd, + makeexpr_addr(p_index(exs, exi)), + makeexpr_sizeof(copyexpr(exd), 0))); + } +} + + + +Static Expr *func_pad(ex) +Expr *ex; +{ + if (checkconst(ex->args[1], 0) || /* "s" is null string */ + checkconst(ex->args[2], ' ')) { + return makeexpr_bicall_4("sprintf", tp_strptr, ex->args[0], + makeexpr_string("%*s"), + makeexpr_longcast(ex->args[3], 0), + makeexpr_string("")); + } + return makeexpr_bicall_4(strpadname, tp_strptr, + ex->args[0], ex->args[1], ex->args[2], + makeexpr_arglong(ex->args[3], 0)); +} + + + +Static Stmt *proc_page() +{ + Expr *fex, *ex; + + if (curtok == TOK_LPAR) { + fex = p_parexpr(tp_text); + ex = makeexpr_bicall_2("fprintf", tp_int, + filebasename(copyexpr(fex)), + makeexpr_string("\f")); + } else { + fex = makeexpr_var(mp_output); + ex = makeexpr_bicall_1("printf", tp_int, + makeexpr_string("\f")); + } + if (FCheck(checkfilewrite)) { + ex = makeexpr_bicall_2("~SETIO", tp_void, + makeexpr_rel(EK_GE, ex, makeexpr_long(0)), + makeexpr_name(filewriteerrorname, tp_int)); + } + return wrapopencheck(makestmt_call(ex), fex); +} + + + +Static Expr *func_paramcount(ex) +Expr *ex; +{ + freeexpr(ex); + return makeexpr_minus(makeexpr_name(name_ARGC, tp_int), + makeexpr_long(1)); +} + + + +Static Expr *func_paramstr(ex) +Expr *ex; +{ + Expr *ex2; + + ex2 = makeexpr_index(makeexpr_name(name_ARGV, + makepointertype(tp_strptr)), + makeexpr_unlongcast(ex->args[1]), + makeexpr_long(0)); + ex2->val.type = tp_str255; + return makeexpr_bicall_3("sprintf", tp_strptr, + ex->args[0], + makeexpr_string("%s"), + ex2); +} + + + +Static Expr *func_pi() +{ + return makeexpr_name("M_PI", tp_longreal); +} + + + +Static Expr *var_port() +{ + Expr *ex; + + if (!wneedtok(TOK_LBR)) + return makeexpr_name("PORT", tp_integer); + ex = p_expr(tp_integer); + if (!wneedtok(TOK_RBR)) + skippasttotoken(TOK_RBR, TOK_SEMI); + note("Reference to PORT [191]"); + return makeexpr_bicall_1("PORT", tp_ubyte, ex); +} + + + +Static Expr *var_portw() +{ + Expr *ex; + + if (!wneedtok(TOK_LBR)) + return makeexpr_name("PORTW", tp_integer); + ex = p_expr(tp_integer); + if (!wneedtok(TOK_RBR)) + skippasttotoken(TOK_RBR, TOK_SEMI); + note("Reference to PORTW [191]"); + return makeexpr_bicall_1("PORTW", tp_ushort, ex); +} + + + +Static Expr *func_pos(ex) +Expr *ex; +{ + char *cp; + + cp = strposname; + if (!*cp) { + note("POS function used [192]"); + cp = "POS"; + } + return makeexpr_bicall_3(cp, tp_int, + ex->args[1], + ex->args[0], + makeexpr_long(1)); +} + + + +Static Expr *func_ptr(ex) +Expr *ex; +{ + note("PTR function was used [193]"); + return ex; +} + + + +Static Expr *func_position() +{ + return file_iofunc(2, seek_base); +} + + + +Static Expr *func_pred() +{ + Expr *ex; + + if (wneedtok(TOK_LPAR)) { + ex = p_ord_expr(); + skipcloseparen(); + } else + ex = p_ord_expr(); +#if 1 + ex = makeexpr_inc(ex, makeexpr_long(-1)); +#else + ex = makeexpr_cast(makeexpr_plus(ex, makeexpr_long(-1)), ex->val.type); +#endif + return ex; +} + + + +Static Stmt *proc_put() +{ + Expr *ex; + Type *type; + + if (curtok == TOK_LPAR) + ex = p_parexpr(tp_text); + else + ex = makeexpr_var(mp_output); + requirefilebuffer(ex); + type = ex->val.type; + if (isfiletype(type, -1) && *charputname && + filebasetype(type)->kind == TK_CHAR) + return makestmt_call(makeexpr_bicall_1(charputname, tp_void, + filebasename(ex))); + else if (isfiletype(type, -1) && *arrayputname && + filebasetype(type)->kind == TK_ARRAY) + return makestmt_call(makeexpr_bicall_2(arrayputname, tp_void, + filebasename(ex), + makeexpr_type(filebasetype(type)))); + else + return makestmt_call(makeexpr_bicall_2(putname, tp_void, + filebasename(ex), + makeexpr_type(filebasetype(type)))); +} + + + +Static Expr *func_pwroften(ex) +Expr *ex; +{ + return makeexpr_bicall_2("pow", tp_longreal, + makeexpr_real("10.0"), grabarg(ex, 0)); +} + + + +Static Stmt *proc_reset() +{ + return handleopen(0); +} + + + +Static Stmt *proc_rewrite() +{ + return handleopen(1); +} + + + + +Stmt *doseek(fex, ex) +Expr *fex, *ex; +{ + Expr *ex2; + Type *basetype = filebasetype(fex->val.type); + + if (ansiC == 1) + ex2 = makeexpr_name("SEEK_SET", tp_int); + else + ex2 = makeexpr_long(0); + ex = makeexpr_bicall_3("fseek", tp_int, + filebasename(copyexpr(fex)), + makeexpr_arglong( + makeexpr_times(makeexpr_minus(ex, + makeexpr_long(seek_base)), + makeexpr_sizeof(makeexpr_type(basetype), 0)), + 1), + ex2); + if (FCheck(checkfileseek)) { + ex = makeexpr_bicall_2("~SETIO", tp_void, + makeexpr_rel(EK_EQ, ex, makeexpr_long(0)), + makeexpr_name(endoffilename, tp_int)); + } + return makestmt_call(ex); +} + + + + +Static Expr *makegetchar(fex) +Expr *fex; +{ + if (isvar(fex, mp_input)) + return makeexpr_bicall_0("getchar", tp_char); + else + return makeexpr_bicall_1("getc", tp_char, filebasename(copyexpr(fex))); +} + + + +Static Stmt *fixscanf(sp, fex) +Stmt *sp; +Expr *fex; +{ + int nargs, i, isstrread; + char *cp; + Expr *ex; + Stmt *sp2; + + isstrread = (fex->val.type->kind == TK_STRING); + if (sp->kind == SK_ASSIGN && sp->exp1->kind == EK_BICALL && + !strcmp(sp->exp1->val.s, "scanf")) { + if (sp->exp1->args[0]->kind == EK_CONST && + !(sp->exp1->args[0]->val.i&1) && !isstrread) { + cp = sp->exp1->args[0]->val.s; /* scanf("%c%c") -> getchar;getchar */ + for (i = 0; cp[i] == '%' && cp[i+1] == 'c'; ) { + i += 2; + if (i == sp->exp1->args[0]->val.i) { + sp2 = NULL; + for (i = 1; i < sp->exp1->nargs; i++) { + ex = makeexpr_hat(sp->exp1->args[i], 0); + sp2 = makestmt_seq(sp2, + makestmt_assign(copyexpr(ex), + makegetchar(fex))); + if (checkeof(fex)) { + sp2 = makestmt_seq(sp2, + makestmt_call(makeexpr_bicall_2("~SETIO", tp_void, + makeexpr_rel(EK_NE, + ex, + makeexpr_name("EOF", tp_char)), + makeexpr_name(endoffilename, tp_int)))); + } else + freeexpr(ex); + } + return sp2; + } + } + } + nargs = sp->exp1->nargs - 1; + if (isstrread) { + strchange(&sp->exp1->val.s, "sscanf"); + insertarg(&sp->exp1, 0, copyexpr(fex)); + } else if (!isvar(fex, mp_input)) { + strchange(&sp->exp1->val.s, "fscanf"); + insertarg(&sp->exp1, 0, filebasename(copyexpr(fex))); + } + if (FCheck(checkreadformat)) { + if (checkeof(fex) && !isstrread) + ex = makeexpr_cond(makeexpr_rel(EK_NE, + makeexpr_bicall_1("feof", + tp_int, + filebasename(copyexpr(fex))), + makeexpr_long(0)), + makeexpr_name(endoffilename, tp_int), + makeexpr_name(badinputformatname, tp_int)); + else + ex = makeexpr_name(badinputformatname, tp_int); + sp->exp1 = makeexpr_bicall_2("~SETIO", tp_void, + makeexpr_rel(EK_EQ, + sp->exp1, + makeexpr_long(nargs)), + ex); + } else if (checkeof(fex) && !isstrread) { + sp->exp1 = makeexpr_bicall_2("~SETIO", tp_void, + makeexpr_rel(EK_NE, + sp->exp1, + makeexpr_name("EOF", tp_int)), + makeexpr_name(endoffilename, tp_int)); + } + } + return sp; +} + + + +Static Expr *makefgets(vex, lex, fex) +Expr *vex, *lex, *fex; +{ + Expr *ex; + + ex = makeexpr_bicall_3("fgets", tp_strptr, + vex, + lex, + filebasename(copyexpr(fex))); + if (checkeof(fex)) { + ex = makeexpr_bicall_2("~SETIO", tp_void, + makeexpr_rel(EK_NE, ex, makeexpr_nil()), + makeexpr_name(endoffilename, tp_int)); + } + return ex; +} + + + +Static Stmt *skipeoln(fex) +Expr *fex; +{ + Meaning *tvar; + Expr *ex; + + if (!strcmp(readlnname, "fgets")) { + tvar = makestmttempvar(tp_str255, name_STRING); + return makestmt_call(makefgets(makeexpr_var(tvar), + makeexpr_long(stringceiling+1), + filebasename(fex))); + } else if (!strcmp(readlnname, "scanf") || !*readlnname) { + if (checkeof(fex)) + ex = makeexpr_bicall_2("~SETIO", tp_void, + makeexpr_rel(EK_NE, + makegetchar(fex), + makeexpr_name("EOF", tp_char)), + makeexpr_name(endoffilename, tp_int)); + else + ex = makegetchar(fex); + return makestmt_seq(fixscanf( + makestmt_call(makeexpr_bicall_1("scanf", tp_int, + makeexpr_string("%*[^\n]"))), fex), + makestmt_call(ex)); + } else { + return makestmt_call(makeexpr_bicall_1(readlnname, tp_void, + filebasename(copyexpr(fex)))); + } +} + + + +Static Stmt *handleread_text(fex, var, isreadln) +Expr *fex, *var; +int isreadln; +{ + Stmt *spbase, *spafter, *sp; + Expr *ex = NULL, *exj = NULL; + Type *type; + Meaning *tvar, *tempcp, *mp; + int i, isstrread, scanfmode, readlnflag, varstring, maxstring; + int longstrsize = (longstringsize > 0) ? longstringsize : stringceiling; + long rmin, rmax; + char *fmt; + + spbase = NULL; + spafter = NULL; + sp = NULL; + tempcp = NULL; + if (fex->val.type->kind == TK_ARRAY) + fex = makeexpr_sprintfify(fex); + isstrread = (fex->val.type->kind == TK_STRING); + if (isstrread) { + exj = var; + var = p_expr(NULL); + } + scanfmode = !strcmp(readlnname, "scanf") || !*readlnname || isstrread; + for (;;) { + readlnflag = isreadln && curtok == TOK_RPAR; + if (var->val.type->kind == TK_STRING && !isstrread) { + if (sp) + spbase = makestmt_seq(spbase, fixscanf(sp, fex)); + spbase = makestmt_seq(spbase, spafter); + varstring = (varstrings && var->kind == EK_VAR && + (mp = (Meaning *)var->val.i)->kind == MK_VARPARAM && + mp->type == tp_strptr); + maxstring = (strmax(var) >= longstrsize && !varstring); + if (isvar(fex, mp_input) && maxstring && usegets && readlnflag) { + spbase = makestmt_seq(spbase, + makestmt_call(makeexpr_bicall_1("gets", tp_str255, + makeexpr_addr(var)))); + isreadln = 0; + } else if (scanfmode && !varstring && + (*readlnname || !isreadln)) { + spbase = makestmt_seq(spbase, makestmt_assign(makeexpr_hat(copyexpr(var), 0), + makeexpr_char(0))); + if (maxstring && usegets) + ex = makeexpr_string("%[^\n]"); + else + ex = makeexpr_string(format_d("%%%d[^\n]", strmax(var))); + ex = makeexpr_bicall_2("scanf", tp_int, ex, makeexpr_addr(var)); + spbase = makestmt_seq(spbase, fixscanf(makestmt_call(ex), fex)); + if (readlnflag && maxstring && usegets) { + spbase = makestmt_seq(spbase, makestmt_call(makegetchar(fex))); + isreadln = 0; + } + } else { + ex = makeexpr_plus(strmax_func(var), makeexpr_long(1)); + spbase = makestmt_seq(spbase, + makestmt_call(makefgets(makeexpr_addr(copyexpr(var)), + ex, + fex))); + if (!tempcp) + tempcp = makestmttempvar(tp_charptr, name_TEMP); + spbase = makestmt_seq(spbase, + makestmt_assign(makeexpr_var(tempcp), + makeexpr_bicall_2("strchr", tp_charptr, + makeexpr_addr(copyexpr(var)), + makeexpr_char('\n')))); + sp = makestmt_assign(makeexpr_hat(makeexpr_var(tempcp), 0), + makeexpr_long(0)); + if (readlnflag) + isreadln = 0; + else + sp = makestmt_seq(sp, + makestmt_call(makeexpr_bicall_2("ungetc", tp_void, + makeexpr_char('\n'), + filebasename(copyexpr(fex))))); + spbase = makestmt_seq(spbase, makestmt_if(makeexpr_rel(EK_NE, + makeexpr_var(tempcp), + makeexpr_nil()), + sp, + NULL)); + } + sp = NULL; + spafter = NULL; + } else if (var->val.type->kind == TK_ARRAY && !isstrread) { + if (sp) + spbase = makestmt_seq(spbase, fixscanf(sp, fex)); + spbase = makestmt_seq(spbase, spafter); + ex = makeexpr_sizeof(copyexpr(var), 0); + if (readlnflag) { + spbase = makestmt_seq(spbase, + makestmt_call( + makeexpr_bicall_3("P_readlnpaoc", tp_void, + filebasename(copyexpr(fex)), + makeexpr_addr(var), + makeexpr_arglong(ex, 0)))); + isreadln = 0; + } else { + spbase = makestmt_seq(spbase, + makestmt_call( + makeexpr_bicall_3("P_readpaoc", tp_void, + filebasename(copyexpr(fex)), + makeexpr_addr(var), + makeexpr_arglong(ex, 0)))); + } + sp = NULL; + spafter = NULL; + } else { + switch (ord_type(var->val.type)->kind) { + + case TK_INTEGER: + fmt = "d"; + if (curtok == TOK_COLON) { + gettok(); + if (curtok == TOK_IDENT && + !strcicmp(curtokbuf, "HEX")) { + fmt = "x"; + } else if (curtok == TOK_IDENT && + !strcicmp(curtokbuf, "OCT")) { + fmt = "o"; + } else if (curtok == TOK_IDENT && + !strcicmp(curtokbuf, "BIN")) { + fmt = "b"; + note("Using %b for binary format in scanf [194]"); + } else + warning("Unrecognized format specified in READ [212]"); + gettok(); + } + type = findbasetype(var->val.type, ODECL_NOPRES); + if (exprlongness(var) > 0) + ex = makeexpr_string(format_s("%%l%s", fmt)); + else if (type == tp_integer || type == tp_int || + type == tp_uint || type == tp_sint) + ex = makeexpr_string(format_s("%%%s", fmt)); + else if (type == tp_sshort || type == tp_ushort) + ex = makeexpr_string(format_s("%%h%s", fmt)); + else { + tvar = makestmttempvar(tp_int, name_TEMP); + spafter = makestmt_seq(spafter, + makestmt_assign(var, + makeexpr_var(tvar))); + var = makeexpr_var(tvar); + ex = makeexpr_string(format_s("%%%s", fmt)); + } + break; + + case TK_CHAR: + ex = makeexpr_string("%c"); + if (newlinespace && !isstrread) { + spafter = makestmt_seq(spafter, + makestmt_if(makeexpr_rel(EK_EQ, + copyexpr(var), + makeexpr_char('\n')), + makestmt_assign(copyexpr(var), + makeexpr_char(' ')), + NULL)); + } + break; + + case TK_BOOLEAN: + tvar = makestmttempvar(tp_str255, name_STRING); + spafter = makestmt_seq(spafter, + makestmt_assign(var, + makeexpr_or(makeexpr_rel(EK_EQ, + makeexpr_hat(makeexpr_var(tvar), 0), + makeexpr_char('T')), + makeexpr_rel(EK_EQ, + makeexpr_hat(makeexpr_var(tvar), 0), + makeexpr_char('t'))))); + var = makeexpr_var(tvar); + ex = makeexpr_string(" %[a-zA-Z]"); + break; + + case TK_ENUM: + warning("READ on enumerated types not yet supported [213]"); + if (useenum) + ex = makeexpr_string("%d"); + else + ex = makeexpr_string("%hd"); + break; + + case TK_REAL: + if (var->val.type == tp_longreal) + ex = makeexpr_string("%lg"); + else + ex = makeexpr_string("%g"); + break; + + case TK_STRING: /* strread only */ + ex = makeexpr_string(format_d("%%%lds", strmax(fex))); + break; + + case TK_ARRAY: /* strread only */ + if (!ord_range(ex->val.type->indextype, &rmin, &rmax)) { + rmin = 1; + rmax = 1; + note("Can't determine length of packed array of chars [195]"); + } + ex = makeexpr_string(format_d("%%%ldc", rmax-rmin+1)); + break; + + default: + note("Element has wrong type for WRITE statement [196]"); + ex = NULL; + break; + + } + if (ex) { + var = makeexpr_addr(var); + if (sp) { + sp->exp1->args[0] = makeexpr_concat(sp->exp1->args[0], ex, 0); + insertarg(&sp->exp1, sp->exp1->nargs, var); + } else { + sp = makestmt_call(makeexpr_bicall_2("scanf", tp_int, ex, var)); + } + } + } + if (curtok == TOK_COMMA) { + gettok(); + var = p_expr(NULL); + } else + break; + } + if (sp) { + if (isstrread && !FCheck(checkreadformat) && + ((i=0, checkstring(sp->exp1->args[0], "%d")) || + (i++, checkstring(sp->exp1->args[0], "%ld")) || + (i++, checkstring(sp->exp1->args[0], "%hd")) || + (i++, checkstring(sp->exp1->args[0], "%lg")))) { + if (fullstrread != 0 && exj) { + tvar = makestmttempvar(tp_strptr, name_STRING); + sp->exp1 = makeexpr_assign(makeexpr_hat(sp->exp1->args[1], 0), + (i == 3) ? makeexpr_bicall_2("strtod", tp_longreal, + copyexpr(fex), + makeexpr_addr(makeexpr_var(tvar))) + : makeexpr_bicall_3("strtol", tp_integer, + copyexpr(fex), + makeexpr_addr(makeexpr_var(tvar)), + makeexpr_long(10))); + spafter = makestmt_seq(spafter, + makestmt_assign(copyexpr(exj), + makeexpr_minus(makeexpr_var(tvar), + makeexpr_addr(copyexpr(fex))))); + } else { + sp->exp1 = makeexpr_assign(makeexpr_hat(sp->exp1->args[1], 0), + makeexpr_bicall_1((i == 1) ? "atol" : (i == 3) ? "atof" : "atoi", + (i == 1) ? tp_integer : (i == 3) ? tp_longreal : tp_int, + copyexpr(fex))); + } + } else if (isstrread && fullstrread != 0 && exj) { + sp->exp1->args[0] = makeexpr_concat(sp->exp1->args[0], + makeexpr_string(sizeof_int >= 32 ? "%n" : "%ln"), 0); + insertarg(&sp->exp1, sp->exp1->nargs, makeexpr_addr(copyexpr(exj))); + } else if (isreadln && scanfmode && !FCheck(checkreadformat)) { + isreadln = 0; + sp->exp1->args[0] = makeexpr_concat(sp->exp1->args[0], + makeexpr_string("%*[^\n]"), 0); + spafter = makestmt_seq(makestmt_call(makegetchar(fex)), spafter); + } + spbase = makestmt_seq(spbase, fixscanf(sp, fex)); + } + spbase = makestmt_seq(spbase, spafter); + if (isreadln) + spbase = makestmt_seq(spbase, skipeoln(fex)); + return spbase; +} + + + +Static Stmt *handleread_bin(fex, var) +Expr *fex, *var; +{ + Type *basetype; + Stmt *sp; + Expr *ex, *tvardef = NULL; + + sp = NULL; + basetype = filebasetype(fex->val.type); + for (;;) { + ex = makeexpr_bicall_4("fread", tp_integer, makeexpr_addr(var), + makeexpr_sizeof(makeexpr_type(basetype), 0), + makeexpr_long(1), + filebasename(copyexpr(fex))); + if (checkeof(fex)) { + ex = makeexpr_bicall_2("~SETIO", tp_void, + makeexpr_rel(EK_EQ, ex, makeexpr_long(1)), + makeexpr_name(endoffilename, tp_int)); + } + sp = makestmt_seq(sp, makestmt_call(ex)); + if (curtok == TOK_COMMA) { + gettok(); + var = p_expr(NULL); + } else + break; + } + freeexpr(tvardef); + return sp; +} + + + +Static Stmt *proc_read() +{ + Expr *fex, *ex; + Stmt *sp; + + if (!skipopenparen()) + return NULL; + ex = p_expr(NULL); + if (isfiletype(ex->val.type, -1) && wneedtok(TOK_COMMA)) { + fex = ex; + ex = p_expr(NULL); + } else { + fex = makeexpr_var(mp_input); + } + if (fex->val.type == tp_text || fex->val.type == tp_bigtext) + sp = handleread_text(fex, ex, 0); + else + sp = handleread_bin(fex, ex); + skipcloseparen(); + return wrapopencheck(sp, fex); +} + + + +Static Stmt *proc_readdir() +{ + Expr *fex, *ex; + Stmt *sp; + + if (!skipopenparen()) + return NULL; + fex = p_expr(tp_text); + if (!skipcomma()) + return NULL; + ex = p_expr(tp_integer); + sp = doseek(fex, ex); + if (!skipopenparen()) + return sp; + sp = makestmt_seq(sp, handleread_bin(fex, p_expr(NULL))); + skipcloseparen(); + return wrapopencheck(sp, fex); +} + + + +Static Stmt *proc_readln() +{ + Expr *fex, *ex; + Stmt *sp; + + if (curtok != TOK_LPAR) { + fex = makeexpr_var(mp_input); + return wrapopencheck(skipeoln(copyexpr(fex)), fex); + } else { + gettok(); + ex = p_expr(NULL); + if (isfiletype(ex->val.type, -1)) { + fex = ex; + if (curtok == TOK_RPAR || !wneedtok(TOK_COMMA)) { + skippasttotoken(TOK_RPAR, TOK_SEMI); + return wrapopencheck(skipeoln(copyexpr(fex)), fex); + } else { + ex = p_expr(NULL); + } + } else { + fex = makeexpr_var(mp_input); + } + sp = handleread_text(fex, ex, 1); + skipcloseparen(); + } + return wrapopencheck(sp, fex); +} + + + +Static Stmt *proc_readv() +{ + Expr *vex; + Stmt *sp; + + if (!skipopenparen()) + return NULL; + vex = p_expr(tp_str255); + if (!skipcomma()) + return NULL; + sp = handleread_text(vex, NULL, 0); + skipcloseparen(); + return sp; +} + + + +Static Stmt *proc_strread() +{ + Expr *vex, *exi, *exj, *exjj, *ex; + Stmt *sp, *sp2; + Meaning *tvar, *jvar; + + if (!skipopenparen()) + return NULL; + vex = p_expr(tp_str255); + if (vex->kind != EK_VAR) { + tvar = makestmttempvar(tp_str255, name_STRING); + sp = makestmt_assign(makeexpr_var(tvar), vex); + vex = makeexpr_var(tvar); + } else + sp = NULL; + if (!skipcomma()) + return NULL; + exi = p_expr(tp_integer); + if (!skipcomma()) + return NULL; + exj = p_expr(tp_integer); + if (!skipcomma()) + return NULL; + if (exprspeed(exi) >= 5 || !nosideeffects(exi, 0)) { + sp = makestmt_seq(sp, makestmt_assign(copyexpr(exj), exi)); + exi = copyexpr(exj); + } + if (fullstrread != 0 && + ((ex = singlevar(exj)) == NULL || exproccurs(exi, ex))) { + jvar = makestmttempvar(exj->val.type, name_TEMP); + exjj = makeexpr_var(jvar); + } else { + exjj = copyexpr(exj); + jvar = (exj->kind == EK_VAR) ? (Meaning *)exj->val.i : NULL; + } + sp2 = handleread_text(bumpstring(copyexpr(vex), + copyexpr(exi), 1), + exjj, 0); + sp = makestmt_seq(sp, sp2); + skipcloseparen(); + if (fullstrread == 0) { + sp = makestmt_seq(sp, makestmt_assign(exj, + makeexpr_plus(makeexpr_bicall_1("strlen", tp_int, + vex), + makeexpr_long(1)))); + freeexpr(exjj); + freeexpr(exi); + } else { + sp = makestmt_seq(sp, makestmt_assign(exj, + makeexpr_plus(exjj, exi))); + if (fullstrread == 2) + note("STRREAD was used [197]"); + freeexpr(vex); + } + return mixassignments(sp, jvar); +} + + + + +Static Expr *func_random() +{ + Expr *ex; + + if (curtok == TOK_LPAR) { + gettok(); + ex = p_expr(tp_integer); + skipcloseparen(); + return makeexpr_bicall_1(randintname, tp_integer, makeexpr_arglong(ex, 1)); + } else { + return makeexpr_bicall_0(randrealname, tp_longreal); + } +} + + + +Static Stmt *proc_randomize() +{ + if (*randomizename) + return makestmt_call(makeexpr_bicall_0(randomizename, tp_void)); + else + return NULL; +} + + + +Static Expr *func_round(ex) +Expr *ex; +{ + Meaning *tvar; + + ex = grabarg(ex, 0); + if (ex->val.type->kind != TK_REAL) + return ex; + if (*roundname) { + if (*roundname != '*' || (exprspeed(ex) < 5 && nosideeffects(ex, 0))) { + return makeexpr_bicall_1(roundname, tp_integer, ex); + } else { + tvar = makestmttempvar(tp_longreal, name_TEMP); + return makeexpr_comma(makeexpr_assign(makeexpr_var(tvar), ex), + makeexpr_bicall_1(roundname, tp_integer, makeexpr_var(tvar))); + } + } else { + return makeexpr_actcast(makeexpr_bicall_1("floor", tp_longreal, + makeexpr_plus(ex, makeexpr_real("0.5"))), + tp_integer); + } +} + + + +Static Stmt *proc_unpack() +{ + Expr *exs, *exd, *exi, *mins; + Meaning *tvar; + Stmt *sp; + + if (!skipopenparen()) + return NULL; + exs = p_expr(NULL); + if (!skipcomma()) + return NULL; + exd = p_expr(NULL); + if (!skipcomma()) + return NULL; + exi = p_ord_expr(); + skipcloseparen(); + if (exd->val.type->kind != TK_ARRAY || + (exs->val.type->kind != TK_ARRAY && + exs->val.type->kind != TK_SMALLARRAY)) { + warning("Bad argument types for PACK/UNPACK [325]"); + return makestmt_call(makeexpr_bicall_3("unpack", tp_void, + exs, exd, exi)); + } + if (exs->val.type->smax || exd->val.type->smax) { + tvar = makestmttempvar(exs->val.type->indextype, name_TEMP); + sp = makestmt(SK_FOR); + if (exs->val.type->smin) + mins = exs->val.type->smin; + else + mins = exs->val.type->indextype->smin; + sp->exp1 = makeexpr_assign(makeexpr_var(tvar), + copyexpr(mins)); + sp->exp2 = makeexpr_rel(EK_LE, makeexpr_var(tvar), + copyexpr(exs->val.type->indextype->smax)); + sp->exp3 = makeexpr_assign(makeexpr_var(tvar), + makeexpr_plus(makeexpr_var(tvar), + makeexpr_long(1))); + exi = makeexpr_minus(exi, copyexpr(mins)); + sp->stm1 = makestmt_assign(p_index(exd, + makeexpr_plus(makeexpr_var(tvar), + exi)), + p_index(exs, makeexpr_var(tvar))); + return sp; + } else { + exi = gentle_cast(exi, exs->val.type->indextype); + return makestmt_call(makeexpr_bicall_3("memcpy", exd->val.type, + exd, + makeexpr_addr(p_index(exs, exi)), + makeexpr_sizeof(copyexpr(exd), 0))); + } +} + + + +Static Expr *func_uround(ex) +Expr *ex; +{ + ex = grabarg(ex, 0); + if (ex->val.type->kind != TK_REAL) + return ex; + return makeexpr_actcast(makeexpr_bicall_1("floor", tp_longreal, + makeexpr_plus(ex, makeexpr_real("0.5"))), + tp_unsigned); +} + + + +Static Expr *func_scan() +{ + Expr *ex, *ex2, *ex3; + char *name; + + if (!skipopenparen()) + return NULL; + ex = p_expr(tp_integer); + if (!skipcomma()) + return NULL; + if (curtok == TOK_EQ) + name = "P_scaneq"; + else + name = "P_scanne"; + gettok(); + ex2 = p_expr(tp_char); + if (!skipcomma()) + return NULL; + ex3 = p_expr(tp_str255); + skipcloseparen(); + return makeexpr_bicall_3(name, tp_int, + makeexpr_arglong(ex, 0), + makeexpr_charcast(ex2), ex3); +} + + + +Static Expr *func_scaneq(ex) +Expr *ex; +{ + return makeexpr_bicall_3("P_scaneq", tp_int, + makeexpr_arglong(ex->args[0], 0), + makeexpr_charcast(ex->args[1]), + ex->args[2]); +} + + +Static Expr *func_scanne(ex) +Expr *ex; +{ + return makeexpr_bicall_3("P_scanne", tp_int, + makeexpr_arglong(ex->args[0], 0), + makeexpr_charcast(ex->args[1]), + ex->args[2]); +} + + + +Static Stmt *proc_seek() +{ + Expr *fex, *ex; + Stmt *sp; + + if (!skipopenparen()) + return NULL; + fex = p_expr(tp_text); + if (!skipcomma()) + return NULL; + ex = p_expr(tp_integer); + skipcloseparen(); + sp = wrapopencheck(doseek(fex, ex), copyexpr(fex)); + if (*setupbufname && fileisbuffered(fex, 1)) + sp = makestmt_seq(sp, + makestmt_call( + makeexpr_bicall_2(setupbufname, tp_void, + filebasename(fex), + makeexpr_type(filebasetype(fex->val.type))))); + else + freeexpr(fex); + return sp; +} + + + +Static Expr *func_seekeof() +{ + Expr *ex; + + if (curtok == TOK_LPAR) + ex = p_parexpr(tp_text); + else + ex = makeexpr_var(mp_input); + if (*skipspacename) + ex = makeexpr_bicall_1(skipspacename, tp_text, filebasename(ex)); + else + note("SEEKEOF was used [198]"); + return iofunc(ex, 0); +} + + + +Static Expr *func_seekeoln() +{ + Expr *ex; + + if (curtok == TOK_LPAR) + ex = p_parexpr(tp_text); + else + ex = makeexpr_var(mp_input); + if (*skipspacename) + ex = makeexpr_bicall_1(skipspacename, tp_text, filebasename(ex)); + else + note("SEEKEOLN was used [199]"); + return iofunc(ex, 1); +} + + + +Static Stmt *proc_setstrlen() +{ + Expr *ex, *ex2; + + if (!skipopenparen()) + return NULL; + ex = p_expr(tp_str255); + if (!skipcomma()) + return NULL; + ex2 = p_expr(tp_integer); + skipcloseparen(); + return makestmt_assign(makeexpr_bicall_1("strlen", tp_int, ex), + ex2); +} + + + +Static Stmt *proc_settextbuf() +{ + Expr *fex, *bex, *sex; + + if (!skipopenparen()) + return NULL; + fex = p_expr(tp_text); + if (!skipcomma()) + return NULL; + bex = p_expr(NULL); + if (curtok == TOK_COMMA) { + gettok(); + sex = p_expr(tp_integer); + } else + sex = makeexpr_sizeof(copyexpr(bex), 0); + skipcloseparen(); + note("Make sure setvbuf() call occurs when file is open [200]"); + return makestmt_call(makeexpr_bicall_4("setvbuf", tp_void, + filebasename(fex), + makeexpr_addr(bex), + makeexpr_name("_IOFBF", tp_integer), + sex)); +} + + + +Static Expr *func_sin(ex) +Expr *ex; +{ + return makeexpr_bicall_1("sin", tp_longreal, grabarg(ex, 0)); +} + + +Static Expr *func_sinh(ex) +Expr *ex; +{ + return makeexpr_bicall_1("sinh", tp_longreal, grabarg(ex, 0)); +} + + + +Static Expr *func_sizeof() +{ + Expr *ex; + Type *type; + char *name, vbuf[1000]; + int lpar; + + lpar = (curtok == TOK_LPAR); + if (lpar) + gettok(); + if (curtok == TOK_IDENT && curtokmeaning && curtokmeaning->kind == MK_TYPE) { + ex = makeexpr_type(curtokmeaning->type); + gettok(); + } else + ex = p_expr(NULL); + type = ex->val.type; + parse_special_variant(type, vbuf); + if (lpar) + skipcloseparen(); + name = find_special_variant(vbuf, "SpecialSizeOf", specialsizeofs, 1); + if (name) { + freeexpr(ex); + return pc_expr_str(name); + } else + return makeexpr_sizeof(ex, 0); +} + + + +Static Expr *func_statusv() +{ + return makeexpr_name(name_IORESULT, tp_integer); +} + + + +Static Expr *func_str_hp(ex) +Expr *ex; +{ + return makeexpr_addr(makeexpr_substring(ex->args[0], ex->args[1], + ex->args[2], ex->args[3])); +} + + + +Static Stmt *proc_strappend() +{ + Expr *ex, *ex2; + + if (!skipopenparen()) + return NULL; + ex = p_expr(tp_str255); + if (!skipcomma()) + return NULL; + ex2 = p_expr(tp_str255); + skipcloseparen(); + return makestmt_assign(ex, makeexpr_concat(copyexpr(ex), ex2, 0)); +} + + + +Static Stmt *proc_strdelete() +{ + Meaning *tvar = NULL, *tvari; + Expr *ex, *ex2, *ex3, *ex4, *exi, *exn; + Stmt *sp; + + if (!skipopenparen()) + return NULL; + ex = p_expr(tp_str255); + if (!skipcomma()) + return NULL; + exi = p_expr(tp_integer); + if (curtok == TOK_COMMA) { + gettok(); + exn = p_expr(tp_integer); + } else + exn = makeexpr_long(1); + skipcloseparen(); + if (exprspeed(exi) < 5 && nosideeffects(exi, 0)) + sp = NULL; + else { + tvari = makestmttempvar(tp_int, name_TEMP); + sp = makestmt_assign(makeexpr_var(tvari), exi); + exi = makeexpr_var(tvari); + } + ex3 = bumpstring(copyexpr(ex), copyexpr(exi), 1); + ex4 = bumpstring(copyexpr(ex), makeexpr_plus(exi, exn), 1); + if (strcpyleft) { + ex2 = ex3; + } else { + tvar = makestmttempvar(tp_str255, name_STRING); + ex2 = makeexpr_var(tvar); + } + sp = makestmt_seq(sp, makestmt_assign(ex2, ex4)); + if (!strcpyleft) + sp = makestmt_seq(sp, makestmt_assign(ex3, makeexpr_var(tvar))); + return sp; +} + + + +Static Stmt *proc_strinsert() +{ + Meaning *tvari; + Expr *exs, *exd, *exi; + Stmt *sp; + + if (!skipopenparen()) + return NULL; + exs = p_expr(tp_str255); + if (!skipcomma()) + return NULL; + exd = p_expr(tp_str255); + if (!skipcomma()) + return NULL; + exi = p_expr(tp_integer); + skipcloseparen(); +#if 0 + if (checkconst(exi, 1)) { + freeexpr(exi); + return makestmt_assign(exd, + makeexpr_concat(exs, copyexpr(exd))); + } +#endif + if (exprspeed(exi) < 5 && nosideeffects(exi, 0)) + sp = NULL; + else { + tvari = makestmttempvar(tp_int, name_TEMP); + sp = makestmt_assign(makeexpr_var(tvari), exi); + exi = makeexpr_var(tvari); + } + exd = bumpstring(exd, exi, 1); + sp = makestmt_seq(sp, makestmt_assign(exd, + makeexpr_concat(exs, copyexpr(exd), 0))); + return sp; +} + + + +Static Stmt *proc_strmove() +{ + Expr *exlen, *exs, *exsi, *exd, *exdi; + + if (!skipopenparen()) + return NULL; + exlen = p_expr(tp_integer); + if (!skipcomma()) + return NULL; + exs = p_expr(tp_str255); + if (!skipcomma()) + return NULL; + exsi = p_expr(tp_integer); + if (!skipcomma()) + return NULL; + exd = p_expr(tp_str255); + if (!skipcomma()) + return NULL; + exdi = p_expr(tp_integer); + skipcloseparen(); + exsi = makeexpr_arglong(exsi, 0); + exdi = makeexpr_arglong(exdi, 0); + return makestmt_call(makeexpr_bicall_5(strmovename, tp_str255, + exlen, exs, exsi, exd, exdi)); +} + + + +Static Expr *func_strlen(ex) +Expr *ex; +{ + return makeexpr_bicall_1("strlen", tp_int, grabarg(ex, 0)); +} + + + +Static Expr *func_strltrim(ex) +Expr *ex; +{ + return makeexpr_assign(makeexpr_hat(ex->args[0], 0), + makeexpr_bicall_1(strltrimname, tp_str255, ex->args[1])); +} + + + +Static Expr *func_strmax(ex) +Expr *ex; +{ + return strmax_func(grabarg(ex, 0)); +} + + + +Static Expr *func_strpos(ex) +Expr *ex; +{ + char *cp; + + if (!switch_strpos) + swapexprs(ex->args[0], ex->args[1]); + cp = strposname; + if (!*cp) { + note("STRPOS function used [201]"); + cp = "STRPOS"; + } + return makeexpr_bicall_3(cp, tp_int, + ex->args[0], + ex->args[1], + makeexpr_long(1)); +} + + + +Static Expr *func_strrpt(ex) +Expr *ex; +{ + if (ex->args[1]->kind == EK_CONST && + ex->args[1]->val.i == 1 && ex->args[1]->val.s[0] == ' ') { + return makeexpr_bicall_4("sprintf", tp_strptr, ex->args[0], + makeexpr_string("%*s"), + makeexpr_longcast(ex->args[2], 0), + makeexpr_string("")); + } else + return makeexpr_bicall_3(strrptname, tp_strptr, ex->args[0], ex->args[1], + makeexpr_arglong(ex->args[2], 0)); +} + + + +Static Expr *func_strrtrim(ex) +Expr *ex; +{ + return makeexpr_bicall_1(strrtrimname, tp_strptr, + makeexpr_assign(makeexpr_hat(ex->args[0], 0), + ex->args[1])); +} + + + +Static Expr *func_succ() +{ + Expr *ex; + + if (wneedtok(TOK_LPAR)) { + ex = p_ord_expr(); + skipcloseparen(); + } else + ex = p_ord_expr(); +#if 1 + ex = makeexpr_inc(ex, makeexpr_long(1)); +#else + ex = makeexpr_cast(makeexpr_plus(ex, makeexpr_long(1)), ex->val.type); +#endif + return ex; +} + + + +Static Expr *func_sqr() +{ + return makeexpr_sqr(p_parexpr(tp_integer), 0); +} + + + +Static Expr *func_sqrt(ex) +Expr *ex; +{ + return makeexpr_bicall_1("sqrt", tp_longreal, grabarg(ex, 0)); +} + + + +Static Expr *func_swap(ex) +Expr *ex; +{ + char *cp; + + ex = grabarg(ex, 0); + cp = swapname; + if (!*cp) { + note("SWAP function was used [202]"); + cp = "SWAP"; + } + return makeexpr_bicall_1(swapname, tp_int, ex); +} + + + +Static Expr *func_tan(ex) +Expr *ex; +{ + return makeexpr_bicall_1("tan", tp_longreal, grabarg(ex, 0)); +} + + +Static Expr *func_tanh(ex) +Expr *ex; +{ + return makeexpr_bicall_1("tanh", tp_longreal, grabarg(ex, 0)); +} + + + +Static Expr *func_trunc(ex) +Expr *ex; +{ + return makeexpr_actcast(grabarg(ex, 0), tp_integer); +} + + + +Static Expr *func_utrunc(ex) +Expr *ex; +{ + return makeexpr_actcast(grabarg(ex, 0), tp_unsigned); +} + + + +Static Expr *func_uand() +{ + Expr *ex; + + if (!skipopenparen()) + return NULL; + ex = p_expr(tp_unsigned); + if (skipcomma()) { + ex = makeexpr_bin(EK_BAND, ex->val.type, ex, p_expr(tp_unsigned)); + skipcloseparen(); + } + return ex; +} + + + +Static Expr *func_udec() +{ + return handle_vax_hex(NULL, "u", 0); +} + + + +Static Expr *func_unot() +{ + Expr *ex; + + if (!skipopenparen()) + return NULL; + ex = p_expr(tp_unsigned); + ex = makeexpr_un(EK_BNOT, ex->val.type, ex); + skipcloseparen(); + return ex; +} + + + +Static Expr *func_uor() +{ + Expr *ex; + + if (!skipopenparen()) + return NULL; + ex = p_expr(tp_unsigned); + if (skipcomma()) { + ex = makeexpr_bin(EK_BOR, ex->val.type, ex, p_expr(tp_unsigned)); + skipcloseparen(); + } + return ex; +} + + + +Static Expr *func_upcase(ex) +Expr *ex; +{ + return makeexpr_bicall_1("toupper", tp_char, grabarg(ex, 0)); +} + + + +Static Expr *func_upper() +{ + Expr *ex; + Value val; + + if (!skipopenparen()) + return NULL; + ex = p_expr(tp_integer); + if (curtok == TOK_COMMA) { + gettok(); + val = p_constant(tp_integer); + if (!val.type || val.i != 1) + note("UPPER(v,n) not supported for n>1 [190]"); + } + skipcloseparen(); + return copyexpr(ex->val.type->indextype->smax); +} + + + +Static Expr *func_uxor() +{ + Expr *ex; + + if (!skipopenparen()) + return NULL; + ex = p_expr(tp_unsigned); + if (skipcomma()) { + ex = makeexpr_bin(EK_BXOR, ex->val.type, ex, p_expr(tp_unsigned)); + skipcloseparen(); + } + return ex; +} + + + +Static Expr *func_val_modula() +{ + Expr *ex; + Type *tp; + + if (!skipopenparen()) + return NULL; + tp = p_type(NULL); + if (!skipcomma()) + return NULL; + ex = p_expr(tp); + skipcloseparen(); + return pascaltypecast(tp, ex); +} + + + +Static Stmt *proc_val_turbo() +{ + Expr *ex, *vex, *code, *fmt; + + if (!skipopenparen()) + return NULL; + ex = gentle_cast(p_expr(tp_str255), tp_str255); + if (!skipcomma()) + return NULL; + vex = p_expr(NULL); + if (curtok == TOK_COMMA) { + gettok(); + code = gentle_cast(p_expr(tp_integer), tp_integer); + } else + code = NULL; + skipcloseparen(); + if (vex->val.type->kind == TK_REAL) + fmt = makeexpr_string("%lg"); + else if (exprlongness(vex) > 0) + fmt = makeexpr_string("%ld"); + else + fmt = makeexpr_string("%d"); + ex = makeexpr_bicall_3("sscanf", tp_int, + ex, fmt, makeexpr_addr(vex)); + if (code) { + ex = makeexpr_rel(EK_EQ, ex, makeexpr_long(0)); + return makestmt_assign(code, makeexpr_ord(ex)); + } else + return makestmt_call(ex); +} + + + + + + + +Static Expr *writestrelement(ex, wid, vex, code, needboth) +Expr *ex, *wid, *vex; +int code, needboth; +{ + if (formatstrings && needboth) { + return makeexpr_bicall_5("sprintf", tp_str255, vex, + makeexpr_string(format_d("%%*.*%c", code)), + copyexpr(wid), + wid, + ex); + } else { + return makeexpr_bicall_4("sprintf", tp_str255, vex, + makeexpr_string(format_d("%%*%c", code)), + wid, + ex); + } +} + + + +Static char *makeenumnames(tp) +Type *tp; +{ + Strlist *sp; + char *name; + Meaning *mp; + int saveindent; + + for (sp = enumnames; sp && sp->value != (long)tp; sp = sp->next) ; + if (!sp) { + if (tp->meaning) + name = format_s(name_ENUM, tp->meaning->name); + else + name = format_s(name_ENUM, format_d("_%d", ++enumnamecount)); + sp = strlist_insert(&enumnames, name); + sp->value = (long)tp; + outsection(2); + output(format_s("static %s *", charname)); + output(sp->s); + output("[] = {\n"); + saveindent = outindent; + moreindent(tabsize); + moreindent(structinitindent); + for (mp = tp->fbase; mp; mp = mp->xnext) { + output(makeCstring(mp->sym->name, strlen(mp->sym->name))); + if (mp->xnext) + output(",\002 "); + } + outindent = saveindent; + output("\n} ;\n"); + outsection(2); + } + return sp->s; +} + + + + + +/* This function must return a "tempsprintf" */ + +Expr *writeelement(ex, wid, prec, base) +Expr *ex, *wid, *prec; +int base; +{ + Expr *vex, *ex1, *ex2; + Meaning *tvar; + char *fmtcode; + Type *type; + + ex = makeexpr_charcast(ex); + if (ex->val.type->kind == TK_POINTER) { + ex = makeexpr_hat(ex, 0); /* convert char *'s to strings */ + intwarning("writeelement", "got a char * instead of a string [214]"); + } + if ((ex->val.type->kind == TK_STRING && !wid) || + (ord_type(ex->val.type)->kind == TK_CHAR && (!wid || checkconst(wid, 1)))) { + return makeexpr_sprintfify(ex); + } + tvar = makestmttempvar(tp_str255, name_STRING); + vex = makeexpr_var(tvar); + if (wid) + wid = makeexpr_longcast(wid, 0); + if (prec) + prec = makeexpr_longcast(prec, 0); +#if 0 + if (wid && (wid->kind == EK_CONST && wid->val.i < 0 || + checkconst(wid, -1))) { + freeexpr(wid); /* P-system uses write(x:-1) to mean write(x) */ + wid = NULL; + } + if (prec && (prec->kind == EK_CONST && prec->val.i < 0 || + checkconst(prec, -1))) { + freeexpr(prec); + prec = NULL; + } +#endif + switch (ord_type(ex->val.type)->kind) { + + case TK_INTEGER: + if (!wid) { + if (integerwidth < 0) + integerwidth = (which_lang == LANG_TURBO) ? 1 : 12; + wid = makeexpr_long(integerwidth); + } + type = findbasetype(ex->val.type, ODECL_NOPRES); + if (base == 16) + fmtcode = "x"; + else if (base == 8) + fmtcode = "o"; + else if ((possiblesigns(wid) & (1|4)) == 1) { + wid = makeexpr_neg(wid); + fmtcode = "x"; + } else if (type == tp_unsigned || + type == tp_uint || + (type == tp_ushort && sizeof_int < 32)) + fmtcode = "u"; + else + fmtcode = "d"; + ex = makeexpr_forcelongness(ex); + if (checkconst(wid, 0) || checkconst(wid, 1)) { + ex = makeexpr_bicall_3("sprintf", tp_str255, vex, + makeexpr_string(format_ss("%%%s%s", + (exprlongness(ex) > 0) ? "l" : "", + fmtcode)), + ex); + } else { + ex = makeexpr_bicall_4("sprintf", tp_str255, vex, + makeexpr_string(format_ss("%%*%s%s", + (exprlongness(ex) > 0) ? "l" : "", + fmtcode)), + wid, + ex); + } + break; + + case TK_CHAR: + ex = writestrelement(ex, wid, vex, 'c', + (wid->kind != EK_CONST || wid->val.i < 1)); + break; + + case TK_BOOLEAN: + if (!wid) { + ex = makeexpr_bicall_3("sprintf", tp_str255, vex, + makeexpr_string("%s"), + makeexpr_cond(ex, + makeexpr_string(" TRUE"), + makeexpr_string("FALSE"))); + } else if (checkconst(wid, 1)) { + ex = makeexpr_bicall_3("sprintf", tp_str255, vex, + makeexpr_string("%c"), + makeexpr_cond(ex, + makeexpr_char('T'), + makeexpr_char('F'))); + } else { + ex = writestrelement(makeexpr_cond(ex, + makeexpr_string("TRUE"), + makeexpr_string("FALSE")), + wid, vex, 's', + (wid->kind != EK_CONST || wid->val.i < 5)); + } + break; + + case TK_ENUM: + ex = makeexpr_bicall_3("sprintf", tp_str255, vex, + makeexpr_string("%s"), + makeexpr_index(makeexpr_name(makeenumnames(ex->val.type), + tp_strptr), + ex, NULL)); + break; + + case TK_REAL: + if (!wid) + wid = makeexpr_long(realwidth); + if (prec && (possiblesigns(prec) & (1|4)) != 1) { + ex = makeexpr_bicall_5("sprintf", tp_str255, vex, + makeexpr_string("%*.*f"), + wid, + prec, + ex); + } else { + if (prec) + prec = makeexpr_neg(prec); + else + prec = makeexpr_minus(copyexpr(wid), + makeexpr_long(7)); + if (prec->kind == EK_CONST) { + if (prec->val.i <= 0) + prec = makeexpr_long(1); + } else { + prec = makeexpr_bicall_2("P_max", tp_integer, prec, + makeexpr_long(1)); + } + if (wid->kind == EK_CONST && wid->val.i > 21) { + ex = makeexpr_bicall_5("sprintf", tp_str255, vex, + makeexpr_string("%*.*E"), + wid, + prec, + ex); +#if 0 + } else if (checkconst(wid, 7)) { + ex = makeexpr_bicall_3("sprintf", tp_str255, vex, + makeexpr_string("%E"), + ex); +#endif + } else { + ex = makeexpr_bicall_4("sprintf", tp_str255, vex, + makeexpr_string("% .*E"), + prec, + ex); + } + } + break; + + case TK_STRING: + ex = writestrelement(ex, wid, vex, 's', 1); + break; + + case TK_ARRAY: /* assume packed array of char */ + ord_range_expr(ex->val.type->indextype, &ex1, &ex2); + ex1 = makeexpr_plus(makeexpr_minus(copyexpr(ex2), + copyexpr(ex1)), + makeexpr_long(1)); + ex1 = makeexpr_longcast(ex1, 0); + fmtcode = "%.*s"; + if (!wid) { + wid = ex1; + } else { + if (isliteralconst(wid, NULL) == 2 && + isliteralconst(ex1, NULL) == 2) { + if (wid->val.i > ex1->val.i) { + fmtcode = format_ds("%*s%%.*s", + wid->val.i - ex1->val.i, ""); + wid = ex1; + } + } else + note("Format for packed-array-of-char will work only if width < length [321]"); + } + ex = makeexpr_bicall_4("sprintf", tp_str255, vex, + makeexpr_string(fmtcode), + wid, + makeexpr_addr(ex)); + break; + + default: + note("Element has wrong type for WRITE statement [196]"); + ex = makeexpr_bicall_2("sprintf", tp_str255, vex, makeexpr_string("<meef>")); + break; + + } + return ex; +} + + + +Static Stmt *handlewrite_text(fex, ex, iswriteln) +Expr *fex, *ex; +int iswriteln; +{ + Expr *print, *wid, *prec; + unsigned char *ucp; + int i, done, base; + + print = NULL; + for (;;) { + wid = NULL; + prec = NULL; + base = 10; + if (curtok == TOK_COLON && iswriteln >= 0) { + gettok(); + wid = p_expr(tp_integer); + if (curtok == TOK_COLON) { + gettok(); + prec = p_expr(tp_integer); + } + } + if (curtok == TOK_IDENT && + !strcicmp(curtokbuf, "OCT")) { + base = 8; + gettok(); + } else if (curtok == TOK_IDENT && + !strcicmp(curtokbuf, "HEX")) { + base = 16; + gettok(); + } + ex = writeelement(ex, wid, prec, base); + print = makeexpr_concat(print, cleansprintf(ex), 1); + if (curtok == TOK_COMMA && iswriteln >= 0) { + gettok(); + ex = p_expr(NULL); + } else + break; + } + if (fex->val.type->kind != TK_STRING) { /* not strwrite */ + switch (iswriteln) { + case 1: + case -1: + print = makeexpr_concat(print, makeexpr_string("\n"), 1); + break; + case 2: + case -2: + print = makeexpr_concat(print, makeexpr_string("\r"), 1); + break; + } + if (isvar(fex, mp_output)) { + ucp = (unsigned char *)print->args[1]->val.s; + for (i = 0; i < print->args[1]->val.i; i++) { + if (ucp[i] >= 128 && ucp[i] < 144) { + note("WRITE statement contains color/attribute characters [203]"); + break; + } + } + } + if ((i = sprintflength(print, 0)) > 0 && print->nargs == 2 && printfonly != 1) { + print = makeexpr_unsprintfify(print); + done = 1; + if (isvar(fex, mp_output)) { + if (i == 1) { + print = makeexpr_bicall_1("putchar", tp_int, + makeexpr_charcast(print)); + } else { + if (printfonly == 0) { + if (print->val.s[print->val.i-1] == '\n') { + print->val.s[--(print->val.i)] = 0; + print = makeexpr_bicall_1("puts", tp_int, print); + } else { + print = makeexpr_bicall_2("fputs", tp_int, + print, + copyexpr(fex)); + } + } else { + print = makeexpr_sprintfify(print); + done = 0; + } + } + } else { + if (i == 1) { + print = makeexpr_bicall_2("putc", tp_int, + makeexpr_charcast(print), + filebasename(copyexpr(fex))); + } else if (printfonly == 0) { + print = makeexpr_bicall_2("fputs", tp_int, + print, + filebasename(copyexpr(fex))); + } else { + print = makeexpr_sprintfify(print); + done = 0; + } + } + } else + done = 0; + if (!done) { + canceltempvar(istempvar(print->args[0])); + if (checkstring(print->args[1], "%s") && printfonly != 1) { + print = makeexpr_bicall_2("fputs", tp_int, + grabarg(print, 2), + filebasename(copyexpr(fex))); + } else if (checkstring(print->args[1], "%c") && printfonly != 1 && + !nosideeffects(print->args[2], 0)) { + print = makeexpr_bicall_2("fputc", tp_int, + grabarg(print, 2), + filebasename(copyexpr(fex))); + } else if (isvar(fex, mp_output)) { + if (checkstring(print->args[1], "%s\n") && printfonly != 1) { + print = makeexpr_bicall_1("puts", tp_int, grabarg(print, 2)); + } else if (checkstring(print->args[1], "%c") && printfonly != 1) { + print = makeexpr_bicall_1("putchar", tp_int, grabarg(print, 2)); + } else { + strchange(&print->val.s, "printf"); + delfreearg(&print, 0); + print->val.type = tp_int; + } + } else { + if (checkstring(print->args[1], "%c") && printfonly != 1) { + print = makeexpr_bicall_2("putc", tp_int, + grabarg(print, 2), + filebasename(copyexpr(fex))); + } else { + strchange(&print->val.s, "fprintf"); + freeexpr(print->args[0]); + print->args[0] = filebasename(copyexpr(fex)); + print->val.type = tp_int; + } + } + } + if (FCheck(checkfilewrite)) { + print = makeexpr_bicall_2("~SETIO", tp_void, + makeexpr_rel(EK_GE, print, makeexpr_long(0)), + makeexpr_name(filewriteerrorname, tp_int)); + } + } + return makestmt_call(print); +} + + + +Static Stmt *handlewrite_bin(fex, ex) +Expr *fex, *ex; +{ + Type *basetype; + Stmt *sp; + Expr *tvardef = NULL; + Meaning *tvar = NULL; + + sp = NULL; + basetype = filebasetype(fex->val.type); + for (;;) { + if (!expr_has_address(ex) || ex->val.type != basetype) { + if (!tvar) + tvar = makestmttempvar(basetype, name_TEMP); + if (!tvardef || !exprsame(tvardef, ex, 1)) { + freeexpr(tvardef); + tvardef = copyexpr(ex); + sp = makestmt_seq(sp, makestmt_assign(makeexpr_var(tvar), + ex)); + } else + freeexpr(ex); + ex = makeexpr_var(tvar); + } + ex = makeexpr_bicall_4("fwrite", tp_integer, makeexpr_addr(ex), + makeexpr_sizeof(makeexpr_type(basetype), 0), + makeexpr_long(1), + filebasename(copyexpr(fex))); + if (FCheck(checkfilewrite)) { + ex = makeexpr_bicall_2("~SETIO", tp_void, + makeexpr_rel(EK_EQ, ex, makeexpr_long(1)), + makeexpr_name(filewriteerrorname, tp_int)); + } + sp = makestmt_seq(sp, makestmt_call(ex)); + if (curtok == TOK_COMMA) { + gettok(); + ex = p_expr(NULL); + } else + break; + } + freeexpr(tvardef); + return sp; +} + + + +Static Stmt *proc_write() +{ + Expr *fex, *ex; + Stmt *sp; + + if (!skipopenparen()) + return NULL; + ex = p_expr(NULL); + if (isfiletype(ex->val.type, -1) && wneedtok(TOK_COMMA)) { + fex = ex; + ex = p_expr(NULL); + } else { + fex = makeexpr_var(mp_output); + } + if (fex->val.type == tp_text || fex->val.type == tp_bigtext) + sp = handlewrite_text(fex, ex, 0); + else + sp = handlewrite_bin(fex, ex); + skipcloseparen(); + return wrapopencheck(sp, fex); +} + + + +Static Stmt *handle_modula_write(fmt) +char *fmt; +{ + Expr *ex, *wid; + + if (!skipopenparen()) + return NULL; + ex = makeexpr_forcelongness(p_expr(NULL)); + if (skipcomma()) + wid = p_expr(tp_integer); + else + wid = makeexpr_long(1); + if (checkconst(wid, 0) || checkconst(wid, 1)) + ex = makeexpr_bicall_2("printf", tp_str255, + makeexpr_string(format_ss("%%%s%s", + (exprlongness(ex) > 0) ? "l" : "", + fmt)), + ex); + else + ex = makeexpr_bicall_3("printf", tp_str255, + makeexpr_string(format_ss("%%*%s%s", + (exprlongness(ex) > 0) ? "l" : "", + fmt)), + makeexpr_arglong(wid, 0), + ex); + skipcloseparen(); + return makestmt_call(ex); +} + + +Static Stmt *proc_writecard() +{ + return handle_modula_write("u"); +} + + +Static Stmt *proc_writeint() +{ + return handle_modula_write("d"); +} + + +Static Stmt *proc_writehex() +{ + return handle_modula_write("x"); +} + + +Static Stmt *proc_writeoct() +{ + return handle_modula_write("o"); +} + + +Static Stmt *proc_writereal() +{ + return handle_modula_write("f"); +} + + + +Static Stmt *proc_writedir() +{ + Expr *fex, *ex; + Stmt *sp; + + if (!skipopenparen()) + return NULL; + fex = p_expr(tp_text); + if (!skipcomma()) + return NULL; + ex = p_expr(tp_integer); + sp = doseek(fex, ex); + if (!skipcomma()) + return sp; + sp = makestmt_seq(sp, handlewrite_bin(fex, p_expr(NULL))); + skipcloseparen(); + return wrapopencheck(sp, fex); +} + + + +Static Stmt *handlewriteln(iswriteln) +int iswriteln; +{ + Expr *fex, *ex; + Stmt *sp; + Meaning *deffile = mp_output; + + sp = NULL; + if (iswriteln == 3) { + iswriteln = 1; + if (messagestderr) + deffile = mp_stderr; + } + if (curtok != TOK_LPAR) { + fex = makeexpr_var(deffile); + if (iswriteln) + sp = handlewrite_text(fex, makeexpr_string(""), -iswriteln); + } else { + gettok(); + ex = p_expr(NULL); + if (isfiletype(ex->val.type, -1)) { + fex = ex; + if (curtok == TOK_RPAR || !wneedtok(TOK_COMMA)) { + if (iswriteln) + ex = makeexpr_string(""); + else + ex = NULL; + } else { + ex = p_expr(NULL); + } + } else { + fex = makeexpr_var(deffile); + } + if (ex) + sp = handlewrite_text(fex, ex, iswriteln); + skipcloseparen(); + } + if (iswriteln == 0) { + sp = makestmt_seq(sp, makestmt_call(makeexpr_bicall_1("fflush", tp_void, + filebasename(copyexpr(fex))))); + } + return wrapopencheck(sp, fex); +} + + + +Static Stmt *proc_overprint() +{ + return handlewriteln(2); +} + + + +Static Stmt *proc_prompt() +{ + return handlewriteln(0); +} + + + +Static Stmt *proc_writeln() +{ + return handlewriteln(1); +} + + +Static Stmt *proc_message() +{ + return handlewriteln(3); +} + + + +Static Stmt *proc_writev() +{ + Expr *vex, *ex; + Stmt *sp; + Meaning *mp; + + if (!skipopenparen()) + return NULL; + vex = p_expr(tp_str255); + if (curtok == TOK_RPAR) { + gettok(); + return makestmt_assign(vex, makeexpr_string("")); + } + if (!skipcomma()) + return NULL; + sp = handlewrite_text(vex, p_expr(NULL), 0); + skipcloseparen(); + ex = sp->exp1; + if (ex->kind == EK_BICALL && !strcmp(ex->val.s, "sprintf") && + (mp = istempvar(ex->args[0])) != NULL) { + canceltempvar(mp); + ex->args[0] = vex; + } else + sp->exp1 = makeexpr_assign(vex, ex); + return sp; +} + + +Static Stmt *proc_strwrite(mp_x, spbase) +Meaning *mp_x; +Stmt *spbase; +{ + Expr *vex, *exi, *exj, *ex; + Stmt *sp; + Meaning *mp; + + if (!skipopenparen()) + return NULL; + vex = p_expr(tp_str255); + if (!skipcomma()) + return NULL; + exi = p_expr(tp_integer); + if (!skipcomma()) + return NULL; + exj = p_expr(tp_integer); + if (!skipcomma()) + return NULL; + sp = handlewrite_text(vex, p_expr(NULL), 0); + skipcloseparen(); + ex = sp->exp1; + FREE(sp); + if (checkconst(exi, 1)) { + sp = spbase; + while (sp && sp->next) + sp = sp->next; + if (sp && sp->kind == SK_ASSIGN && sp->exp1->kind == EK_ASSIGN && + (sp->exp1->args[0]->kind == EK_HAT || + sp->exp1->args[0]->kind == EK_INDEX) && + exprsame(sp->exp1->args[0]->args[0], vex, 1) && + checkconst(sp->exp1->args[1], 0)) { + nukestmt(sp); /* remove preceding bogus setstrlen */ + } + } + if (ex->kind == EK_BICALL && !strcmp(ex->val.s, "sprintf") && + (mp = istempvar(ex->args[0])) != NULL) { + canceltempvar(mp); + ex->args[0] = bumpstring(copyexpr(vex), exi, 1); + sp = makestmt_call(ex); + } else + sp = makestmt_assign(bumpstring(copyexpr(vex), exi, 1), ex); + if (fullstrwrite != 0) { + sp = makestmt_seq(sp, makestmt_assign(exj, + makeexpr_plus(makeexpr_bicall_1("strlen", tp_int, vex), + makeexpr_long(1)))); + if (fullstrwrite == 1) + note("FullStrWrite=1 not yet supported [204]"); + if (fullstrwrite == 2) + note("STRWRITE was used [205]"); + } else { + freeexpr(vex); + } + return mixassignments(sp, NULL); +} + + + +Static Stmt *proc_str_turbo() +{ + Expr *ex, *wid, *prec; + + if (!skipopenparen()) + return NULL; + ex = p_expr(NULL); + wid = NULL; + prec = NULL; + if (curtok == TOK_COLON) { + gettok(); + wid = p_expr(tp_integer); + if (curtok == TOK_COLON) { + gettok(); + prec = p_expr(tp_integer); + } + } + ex = writeelement(ex, wid, prec, 10); + if (!skipcomma()) + return NULL; + wid = p_expr(tp_str255); + skipcloseparen(); + return makestmt_assign(wid, ex); +} + + + +Static Stmt *proc_time() +{ + Expr *ex; + + if (!skipopenparen()) + return NULL; + ex = p_expr(tp_str255); + skipcloseparen(); + return makestmt_call(makeexpr_bicall_1("VAXtime", tp_integer, ex)); +} + + +Static Expr *func_xor() +{ + Expr *ex, *ex2; + Type *type; + Meaning *tvar; + + if (!skipopenparen()) + return NULL; + ex = p_expr(NULL); + if (!skipcomma()) + return ex; + ex2 = p_expr(ex->val.type); + skipcloseparen(); + if (ex->val.type->kind != TK_SET && + ex->val.type->kind != TK_SMALLSET) { + ex = makeexpr_bin(EK_BXOR, ex->val.type, ex, ex2); + } else { + type = mixsets(&ex, &ex2); + tvar = makestmttempvar(type, name_SET); + ex = makeexpr_bicall_3(setxorname, type, + makeexpr_var(tvar), + ex, ex2); + } + return ex; +} + + + + + + + +void decl_builtins() +{ + makespecialfunc( "ABS", func_abs); + makespecialfunc( "ADDR", func_addr); + if (!modula2) + makespecialfunc( "ADDRESS", func_addr); + makespecialfunc( "ADDTOPOINTER", func_addtopointer); + makespecialfunc( "ADR", func_addr); + makespecialfunc( "ASL", func_lsl); + makespecialfunc( "ASR", func_asr); + makespecialfunc( "BADDRESS", func_iaddress); + makespecialfunc( "BAND", func_uand); + makespecialfunc( "BIN", func_bin); + makespecialfunc( "BITNEXT", func_bitnext); + makespecialfunc( "BITSIZE", func_bitsize); + makespecialfunc( "BITSIZEOF", func_bitsize); +mp_blockread_ucsd = + makespecialfunc( "BLOCKREAD", func_blockread); +mp_blockwrite_ucsd = + makespecialfunc( "BLOCKWRITE", func_blockwrite); + makespecialfunc( "BNOT", func_unot); + makespecialfunc( "BOR", func_uor); + makespecialfunc( "BSL", func_bsl); + makespecialfunc( "BSR", func_bsr); + makespecialfunc( "BTST", func_btst); + makespecialfunc( "BXOR", func_uxor); + makespecialfunc( "BYTEREAD", func_byteread); + makespecialfunc( "BYTEWRITE", func_bytewrite); + makespecialfunc( "BYTE_OFFSET", func_byte_offset); + makespecialfunc( "CHR", func_chr); + makespecialfunc( "CONCAT", func_concat); + makespecialfunc( "DBLE", func_float); +mp_dec_dec = + makespecialfunc( "DEC", func_dec); + makespecialfunc( "EOF", func_eof); + makespecialfunc( "EOLN", func_eoln); + makespecialfunc( "FCALL", func_fcall); + makespecialfunc( "FILEPOS", func_filepos); + makespecialfunc( "FILESIZE", func_filesize); + makespecialfunc( "FLOAT", func_float); + makespecialfunc( "HEX", func_hex); + makespecialfunc( "HI", func_hi); + makespecialfunc( "HIWORD", func_hiword); + makespecialfunc( "HIWRD", func_hiword); + makespecialfunc( "HIGH", func_high); + makespecialfunc( "IADDRESS", func_iaddress); + makespecialfunc( "INT", func_int); + makespecialfunc( "LAND", func_uand); + makespecialfunc( "LNOT", func_unot); + makespecialfunc( "LO", func_lo); + makespecialfunc( "LOOPHOLE", func_loophole); + makespecialfunc( "LOR", func_uor); + makespecialfunc( "LOWER", func_lower); + makespecialfunc( "LOWORD", func_loword); + makespecialfunc( "LOWRD", func_loword); + makespecialfunc( "LSL", func_lsl); + makespecialfunc( "LSR", func_lsr); + makespecialfunc( "MAX", func_max); + makespecialfunc( "MAXPOS", func_maxpos); + makespecialfunc( "MIN", func_min); + makespecialfunc( "NEXT", func_sizeof); + makespecialfunc( "OCT", func_oct); + makespecialfunc( "ORD", func_ord); + makespecialfunc( "ORD4", func_ord4); + makespecialfunc( "PI", func_pi); + makespecialfunc( "POSITION", func_position); + makespecialfunc( "PRED", func_pred); + makespecialfunc( "QUAD", func_float); + makespecialfunc( "RANDOM", func_random); + makespecialfunc( "REF", func_addr); + makespecialfunc( "SCAN", func_scan); + makespecialfunc( "SEEKEOF", func_seekeof); + makespecialfunc( "SEEKEOLN", func_seekeoln); + makespecialfunc( "SIZE", func_sizeof); + makespecialfunc( "SIZEOF", func_sizeof); + makespecialfunc( "SNGL", func_sngl); + makespecialfunc( "SQR", func_sqr); + makespecialfunc( "STATUSV", func_statusv); + makespecialfunc( "SUCC", func_succ); + makespecialfunc( "TSIZE", func_sizeof); + makespecialfunc( "UAND", func_uand); + makespecialfunc( "UDEC", func_udec); + makespecialfunc( "UINT", func_uint); + makespecialfunc( "UNOT", func_unot); + makespecialfunc( "UOR", func_uor); + makespecialfunc( "UPPER", func_upper); + makespecialfunc( "UXOR", func_uxor); +mp_val_modula = + makespecialfunc( "VAL", func_val_modula); + makespecialfunc( "WADDRESS", func_iaddress); + makespecialfunc( "XOR", func_xor); + + makestandardfunc("ARCTAN", func_arctan); + makestandardfunc("ARCTANH", func_arctanh); + makestandardfunc("BINARY", func_binary); + makestandardfunc("CAP", func_upcase); + makestandardfunc("COPY", func_copy); + makestandardfunc("COS", func_cos); + makestandardfunc("COSH", func_cosh); + makestandardfunc("EXP", func_exp); + makestandardfunc("EXP10", func_pwroften); + makestandardfunc("EXPO", func_expo); + makestandardfunc("FRAC", func_frac); + makestandardfunc("INDEX", func_strpos); + makestandardfunc("LASTPOS", NULL); + makestandardfunc("LINEPOS", NULL); + makestandardfunc("LENGTH", func_strlen); + makestandardfunc("LN", func_ln); + makestandardfunc("LOG", func_log); + makestandardfunc("LOG10", func_log); + makestandardfunc("MAXAVAIL", func_maxavail); + makestandardfunc("MEMAVAIL", func_memavail); + makestandardfunc("OCTAL", func_octal); + makestandardfunc("ODD", func_odd); + makestandardfunc("PAD", func_pad); + makestandardfunc("PARAMCOUNT", func_paramcount); + makestandardfunc("PARAMSTR", func_paramstr); + makestandardfunc("POS", func_pos); + makestandardfunc("PTR", func_ptr); + makestandardfunc("PWROFTEN", func_pwroften); + makestandardfunc("ROUND", func_round); + makestandardfunc("SCANEQ", func_scaneq); + makestandardfunc("SCANNE", func_scanne); + makestandardfunc("SIN", func_sin); + makestandardfunc("SINH", func_sinh); + makestandardfunc("SQRT", func_sqrt); +mp_str_hp = + makestandardfunc("STR", func_str_hp); + makestandardfunc("STRLEN", func_strlen); + makestandardfunc("STRLTRIM", func_strltrim); + makestandardfunc("STRMAX", func_strmax); + makestandardfunc("STRPOS", func_strpos); + makestandardfunc("STRRPT", func_strrpt); + makestandardfunc("STRRTRIM", func_strrtrim); + makestandardfunc("SUBSTR", func_str_hp); + makestandardfunc("SWAP", func_swap); + makestandardfunc("TAN", func_tan); + makestandardfunc("TANH", func_tanh); + makestandardfunc("TRUNC", func_trunc); + makestandardfunc("UPCASE", func_upcase); + makestandardfunc("UROUND", func_uround); + makestandardfunc("UTRUNC", func_utrunc); + + makespecialproc( "APPEND", proc_append); + makespecialproc( "ARGV", proc_argv); + makespecialproc( "ASSERT", proc_assert); + makespecialproc( "ASSIGN", proc_assign); + makespecialproc( "BCLR", proc_bclr); +mp_blockread_turbo = + makespecialproc( "BLOCKREAD_TURBO", proc_blockread); +mp_blockwrite_turbo = + makespecialproc( "BLOCKWRITE_TURBO", proc_blockwrite); + makespecialproc( "BREAK", proc_flush); + makespecialproc( "BSET", proc_bset); + makespecialproc( "CALL", proc_call); + makespecialproc( "CLOSE", proc_close); + makespecialproc( "CONNECT", proc_assign); + makespecialproc( "CYCLE", proc_cycle); + makespecialproc( "DATE", proc_date); +mp_dec_turbo = + makespecialproc( "DEC_TURBO", proc_dec); + makespecialproc( "DISPOSE", proc_dispose); + makespecialproc( "ESCAPE", proc_escape); + makespecialproc( "EXCL", proc_excl); + makespecialproc( "EXIT", proc_exit); + makespecialproc( "FILLCHAR", proc_fillchar); + makespecialproc( "FLUSH", proc_flush); + makespecialproc( "GET", proc_get); + makespecialproc( "HALT", proc_escape); + makespecialproc( "INC", proc_inc); + makespecialproc( "INCL", proc_incl); + makespecialproc( "LEAVE", proc_leave); + makespecialproc( "LOCATE", proc_seek); + makespecialproc( "MESSAGE", proc_message); + makespecialproc( "MOVE_FAST", proc_move_fast); + makespecialproc( "MOVE_L_TO_R", proc_move_fast); + makespecialproc( "MOVE_R_TO_L", proc_move_fast); + makespecialproc( "NEW", proc_new); + if (which_lang != LANG_VAX) + makespecialproc( "OPEN", proc_open); + makespecialproc( "OVERPRINT", proc_overprint); + makespecialproc( "PACK", proc_pack); + makespecialproc( "PAGE", proc_page); + makespecialproc( "PUT", proc_put); + makespecialproc( "PROMPT", proc_prompt); + makespecialproc( "RANDOMIZE", proc_randomize); + makespecialproc( "READ", proc_read); + makespecialproc( "READDIR", proc_readdir); + makespecialproc( "READLN", proc_readln); + makespecialproc( "READV", proc_readv); + makespecialproc( "RESET", proc_reset); + makespecialproc( "REWRITE", proc_rewrite); + makespecialproc( "SEEK", proc_seek); + makespecialproc( "SETSTRLEN", proc_setstrlen); + makespecialproc( "SETTEXTBUF", proc_settextbuf); +mp_str_turbo = + makespecialproc( "STR_TURBO", proc_str_turbo); + makespecialproc( "STRAPPEND", proc_strappend); + makespecialproc( "STRDELETE", proc_strdelete); + makespecialproc( "STRINSERT", proc_strinsert); + makespecialproc( "STRMOVE", proc_strmove); + makespecialproc( "STRREAD", proc_strread); + makespecialproc( "STRWRITE", proc_strwrite); + makespecialproc( "TIME", proc_time); + makespecialproc( "UNPACK", proc_unpack); + makespecialproc( "WRITE", proc_write); + makespecialproc( "WRITEDIR", proc_writedir); + makespecialproc( "WRITELN", proc_writeln); + makespecialproc( "WRITEV", proc_writev); +mp_val_turbo = + makespecialproc( "VAL_TURBO", proc_val_turbo); + + makestandardproc("DELETE", proc_delete); + makestandardproc("FREEMEM", proc_freemem); + makestandardproc("GETMEM", proc_getmem); + makestandardproc("GOTOXY", proc_gotoxy); + makestandardproc("INSERT", proc_insert); + makestandardproc("MARK", NULL); + makestandardproc("MOVE", proc_move); + makestandardproc("MOVELEFT", proc_move); + makestandardproc("MOVERIGHT", proc_move); + makestandardproc("RELEASE", NULL); + + makespecialvar( "MEM", var_mem); + makespecialvar( "MEMW", var_memw); + makespecialvar( "MEML", var_meml); + makespecialvar( "PORT", var_port); + makespecialvar( "PORTW", var_portw); + + /* Modula-2 standard I/O procedures (case-sensitive!) */ + makespecialproc( "Read", proc_read); + makespecialproc( "ReadCard", proc_read); + makespecialproc( "ReadInt", proc_read); + makespecialproc( "ReadReal", proc_read); + makespecialproc( "ReadString", proc_read); + makespecialproc( "Write", proc_write); + makespecialproc( "WriteCard", proc_writecard); + makespecialproc( "WriteHex", proc_writehex); + makespecialproc( "WriteInt", proc_writeint); + makespecialproc( "WriteOct", proc_writeoct); + makespecialproc( "WriteLn", proc_writeln); + makespecialproc( "WriteReal", proc_writereal); + makespecialproc( "WriteString", proc_write); +} + + + + +/* End. */ + + + diff --git a/MultiSource/Benchmarks/MallocBench/p2c/hpmods.c b/MultiSource/Benchmarks/MallocBench/p2c/hpmods.c new file mode 100644 index 00000000..fd30be81 --- /dev/null +++ b/MultiSource/Benchmarks/MallocBench/p2c/hpmods.c @@ -0,0 +1,140 @@ +/* "p2c", a Pascal to C translator. + Copyright (C) 1989, 1990, 1991 Free Software Foundation. + Author's address: daveg@csvax.caltech.edu; 256-80 Caltech/Pasadena CA 91125. + +This program is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation (any version). + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; see the file COPYING. If not, write to +the Free Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ + + + +#define PROTO_HPMODS_C +#include "trans.h" + + + + + +/* FS functions */ + + +Static Stmt *proc_freadbytes() +{ + Expr *ex, *ex2, *vex, *fex; + Type *type; + + if (!skipopenparen()) + return NULL; + fex = p_expr(tp_text); + if (!skipcomma()) + return NULL; + vex = p_expr(NULL); + if (!skipcomma()) + return NULL; + ex2 = p_expr(tp_integer); + skipcloseparen(); + type = vex->val.type; + ex = makeexpr_bicall_4("fread", tp_integer, + makeexpr_addr(vex), + convert_size(type, ex2, "FREADBYTES"), + makeexpr_long(1), + filebasename(copyexpr(fex))); + if (checkeof(fex)) { + ex = makeexpr_bicall_2(name_SETIO, tp_void, + makeexpr_rel(EK_EQ, ex, makeexpr_long(1)), + makeexpr_long(30)); + } + return wrapopencheck(makestmt_call(ex), fex); +} + + + + +Static Stmt *proc_fwritebytes() +{ + Expr *ex, *ex2, *vex, *fex; + Type *type; + + if (!skipopenparen()) + return NULL; + fex = p_expr(tp_text); + if (!skipcomma()) + return NULL; + vex = p_expr(NULL); + if (!skipcomma()) + return NULL; + ex2 = p_expr(tp_integer); + skipcloseparen(); + type = vex->val.type; + ex = makeexpr_bicall_4("fwrite", tp_integer, + makeexpr_addr(vex), + convert_size(type, ex2, "FWRITEBYTES"), + makeexpr_long(1), + filebasename(copyexpr(fex))); + if (checkfilewrite) { + ex = makeexpr_bicall_2(name_SETIO, tp_void, + makeexpr_rel(EK_EQ, ex, makeexpr_long(1)), + makeexpr_long(3)); + } + return wrapopencheck(makestmt_call(ex), fex); +} + + + + + + + + + + +/* SYSGLOBALS */ + + +Static void setup_sysglobals() +{ + Symbol *sym; + + sym = findsymbol("SYSESCAPECODE"); + if (sym->mbase) + strchange(&sym->mbase->name, name_ESCAPECODE); + sym = findsymbol("SYSIORESULT"); + if (sym->mbase) + strchange(&sym->mbase->name, name_IORESULT); +} + + + + + + + + +void hpmods(name, defn) +char *name; +int defn; +{ + if (!strcmp(name, "FS")) { + makespecialproc("freadbytes", proc_freadbytes); + makespecialproc("fwritebytes", proc_fwritebytes); + } else if (!strcmp(name, "SYSGLOBALS")) { + setup_sysglobals(); + } +} + + + + +/* End. */ + + + diff --git a/MultiSource/Benchmarks/MallocBench/p2c/lex.c b/MultiSource/Benchmarks/MallocBench/p2c/lex.c new file mode 100644 index 00000000..a31ed1ab --- /dev/null +++ b/MultiSource/Benchmarks/MallocBench/p2c/lex.c @@ -0,0 +1,3421 @@ +/* "p2c", a Pascal to C translator. + Copyright (C) 1989, 1990, 1991 Free Software Foundation. + Author's address: daveg@csvax.caltech.edu; 256-80 Caltech/Pasadena CA 91125. + +This program is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation (any version). + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; see the file COPYING. If not, write to +the Free Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ + + + +#define PROTO_LEX_C +#include "trans.h" + + +/* Define LEXDEBUG for a token trace */ +#define LEXDEBUG + + + + +#define EOFMARK 1 + + +Static char dollar_flag, lex_initialized; +Static int if_flag, if_skip; +Static int commenting_flag; +Static char *commenting_ptr; +Static int skipflag; +Static char modulenotation; +Static short inputkind; +Static Strlist *instrlist; +Static char inbuf[300]; +Static char *oldinfname, *oldctxname; +Static Strlist *endnotelist; + + + +#define INP_FILE 0 +#define INP_INCFILE 1 +#define INP_STRLIST 2 + +Static struct inprec { + struct inprec *next; + short kind; + char *fname, *inbufptr; + int lnum; + FILE *filep; + Strlist *strlistp, *tempopts; + Token curtok, saveblockkind; + Symbol *curtoksym; + Meaning *curtokmeaning; + char *curtokbuf, *curtokcase; +} *topinput; + + + + + + +char *fixpascalname(name) +char *name; +{ + char *cp, *cp2; + + if (pascalsignif > 0) { + name = format_ds("%.*s", pascalsignif, name); + if (!pascalcasesens) + upc(name); + else if (pascalcasesens == 3) + lwc(name); + } else if (!pascalcasesens) + name = strupper(name); + else if (pascalcasesens == 3) + name = strlower(name); + if (ignorenonalpha) { + for (cp = cp2 = name; *cp; cp++) + if (isalnum(*cp)) + *cp2++ = *cp; + } + return name; +} + + + +Static void makekeyword(name) +char *name; +{ + Symbol *sym; + + if (*name) { + sym = findsymbol(name); + sym->flags |= AVOIDNAME; + } +} + + +Static void makeglobword(name) +char *name; +{ + Symbol *sym; + + if (*name) { + sym = findsymbol(name); + sym->flags |= AVOIDGLOB; + } +} + + + +Static void makekeywords() +{ + makekeyword("auto"); + makekeyword("break"); + makekeyword("char"); + makekeyword("continue"); + makekeyword("default"); + makekeyword("defined"); /* is this one really necessary? */ + makekeyword("double"); + makekeyword("enum"); + makekeyword("extern"); + makekeyword("float"); + makekeyword("int"); + makekeyword("long"); + makekeyword("noalias"); + makekeyword("register"); + makekeyword("return"); + makekeyword("short"); + makekeyword("signed"); + makekeyword("sizeof"); + makekeyword("static"); + makekeyword("struct"); + makekeyword("switch"); + makekeyword("typedef"); + makekeyword("union"); + makekeyword("unsigned"); + makekeyword("void"); + makekeyword("volatile"); + makekeyword("asm"); + makekeyword("fortran"); + makekeyword("entry"); + makekeyword("pascal"); + if (cplus != 0) { + makekeyword("class"); + makekeyword("delete"); + makekeyword("friend"); + makekeyword("inline"); + makekeyword("new"); + makekeyword("operator"); + makekeyword("overload"); + makekeyword("public"); + makekeyword("this"); + makekeyword("virtual"); + } + makekeyword(name_UCHAR); + makekeyword(name_SCHAR); /* any others? */ + makekeyword(name_BOOLEAN); + makekeyword(name_PROCEDURE); + makekeyword(name_ESCAPE); + makekeyword(name_ESCIO); + makekeyword(name_CHKIO); + makekeyword(name_SETIO); + makeglobword("main"); + makeglobword("vextern"); /* used in generated .h files */ + makeglobword("argc"); + makeglobword("argv"); + makekeyword("TRY"); + makekeyword("RECOVER"); + makekeyword("RECOVER2"); + makekeyword("ENDTRY"); +} + + + +Static Symbol *Pkeyword(name, tok) +char *name; +Token tok; +{ + Symbol *sp = NULL; + + if (pascalcasesens != 2) { + sp = findsymbol(strlower(name)); + sp->kwtok = tok; + } + if (pascalcasesens != 3) { + sp = findsymbol(strupper(name)); + sp->kwtok = tok; + } + return sp; +} + + +Static Symbol *Pkeywordposs(name, tok) +char *name; +Token tok; +{ + Symbol *sp = NULL; + + if (pascalcasesens != 2) { + sp = findsymbol(strlower(name)); + sp->kwtok = tok; + sp->flags |= KWPOSS; + } + if (pascalcasesens != 3) { + sp = findsymbol(strupper(name)); + sp->kwtok = tok; + sp->flags |= KWPOSS; + } + return sp; +} + + +Static void makePascalwords() +{ + Pkeyword("AND", TOK_AND); + Pkeyword("ARRAY", TOK_ARRAY); + Pkeywordposs("ANYVAR", TOK_ANYVAR); + Pkeywordposs("ABSOLUTE", TOK_ABSOLUTE); + Pkeyword("BEGIN", TOK_BEGIN); + Pkeywordposs("BY", TOK_BY); + Pkeyword("CASE", TOK_CASE); + Pkeyword("CONST", TOK_CONST); + Pkeyword("DIV", TOK_DIV); + Pkeywordposs("DEFINITION", TOK_DEFINITION); + Pkeyword("DO", TOK_DO); + Pkeyword("DOWNTO", TOK_DOWNTO); + Pkeyword("ELSE", TOK_ELSE); + Pkeywordposs("ELSIF", TOK_ELSIF); + Pkeyword("END", TOK_END); + Pkeywordposs("EXPORT", TOK_EXPORT); + Pkeyword("FILE", TOK_FILE); + Pkeyword("FOR", TOK_FOR); + Pkeywordposs("FROM", TOK_FROM); + Pkeyword("FUNCTION", TOK_FUNCTION); + Pkeyword("GOTO", TOK_GOTO); + Pkeyword("IF", TOK_IF); + Pkeywordposs("IMPLEMENT", TOK_IMPLEMENT); + Pkeywordposs("IMPLEMENTATION", TOK_IMPLEMENT); + Pkeywordposs("IMPORT", TOK_IMPORT); + Pkeyword("IN", TOK_IN); + Pkeywordposs("INLINE", TOK_INLINE); + Pkeywordposs("INTERFACE", TOK_EXPORT); + Pkeywordposs("INTERRUPT", TOK_INTERRUPT); + Pkeyword("LABEL", TOK_LABEL); + Pkeywordposs("LOOP", TOK_LOOP); + Pkeyword("MOD", TOK_MOD); + Pkeywordposs("MODULE", TOK_MODULE); + Pkeyword("NIL", TOK_NIL); + Pkeyword("NOT", TOK_NOT); + Pkeyword("OF", TOK_OF); + Pkeyword("OR", TOK_OR); + Pkeywordposs("ORIGIN", TOK_ORIGIN); + Pkeywordposs("OTHERWISE", TOK_OTHERWISE); + Pkeywordposs("OVERLAY", TOK_SEGMENT); + Pkeyword("PACKED", TOK_PACKED); + Pkeywordposs("POINTER", TOK_POINTER); + Pkeyword("PROCEDURE", TOK_PROCEDURE); + Pkeyword("PROGRAM", TOK_PROGRAM); + Pkeywordposs("QUALIFIED", TOK_QUALIFIED); + Pkeyword("RECORD", TOK_RECORD); + Pkeywordposs("RECOVER", TOK_RECOVER); + Pkeywordposs("REM", TOK_REM); + Pkeyword("REPEAT", TOK_REPEAT); + Pkeywordposs("RETURN", TOK_RETURN); + if (which_lang == LANG_UCSD) + Pkeyword("SEGMENT", TOK_SEGMENT); + else + Pkeywordposs("SEGMENT", TOK_SEGMENT); + Pkeyword("SET", TOK_SET); + Pkeywordposs("SHL", TOK_SHL); + Pkeywordposs("SHR", TOK_SHR); + Pkeyword("THEN", TOK_THEN); + Pkeyword("TO", TOK_TO); + Pkeywordposs("TRY", TOK_TRY); + Pkeyword("TYPE", TOK_TYPE); + Pkeyword("UNTIL", TOK_UNTIL); + Pkeywordposs("USES", TOK_IMPORT); + Pkeywordposs("UNIT", TOK_MODULE); + if (which_lang == LANG_VAX) + Pkeyword("VALUE", TOK_VALUE); + else + Pkeywordposs("VALUE", TOK_VALUE); + Pkeyword("VAR", TOK_VAR); + Pkeywordposs("VARYING", TOK_VARYING); + Pkeyword("WHILE", TOK_WHILE); + Pkeyword("WITH", TOK_WITH); + Pkeywordposs("XOR", TOK_XOR); + Pkeyword("__MODULE", TOK_MODULE); + Pkeyword("__IMPORT", TOK_IMPORT); + Pkeyword("__EXPORT", TOK_EXPORT); + Pkeyword("__IMPLEMENT", TOK_IMPLEMENT); +} + + + +Static void deterministic(name) +char *name; +{ + Symbol *sym; + + if (*name) { + sym = findsymbol(name); + sym->flags |= DETERMF; + } +} + + +Static void nosideeff(name) +char *name; +{ + Symbol *sym; + + if (*name) { + sym = findsymbol(name); + sym->flags |= NOSIDEEFF; + } +} + + + +Static void recordsideeffects() +{ + deterministic("abs"); + deterministic("acos"); + deterministic("asin"); + deterministic("atan"); + deterministic("atan2"); + deterministic("atof"); + deterministic("atoi"); + deterministic("atol"); + deterministic("ceil"); + deterministic("cos"); + deterministic("cosh"); + deterministic("exp"); + deterministic("fabs"); + deterministic("feof"); + deterministic("feoln"); + deterministic("ferror"); + deterministic("floor"); + deterministic("fmod"); + deterministic("ftell"); + deterministic("isalnum"); + deterministic("isalpha"); + deterministic("isdigit"); + deterministic("islower"); + deterministic("isspace"); + deterministic("isupper"); + deterministic("labs"); + deterministic("ldexp"); + deterministic("log"); + deterministic("log10"); + deterministic("memcmp"); + deterministic("memchr"); + deterministic("pow"); + deterministic("sin"); + deterministic("sinh"); + deterministic("sqrt"); + deterministic("strchr"); + deterministic("strcmp"); + deterministic("strcspn"); + deterministic("strlen"); + deterministic("strncmp"); + deterministic("strpbrk"); + deterministic("strrchr"); + deterministic("strspn"); + deterministic("strstr"); + deterministic("tan"); + deterministic("tanh"); + deterministic("tolower"); + deterministic("toupper"); + deterministic(setequalname); + deterministic(subsetname); + deterministic(signextname); +} + + + + + +void init_lex() +{ + int i; + + inputkind = INP_FILE; + inf_lnum = 0; + inf_ltotal = 0; + *inbuf = 0; + inbufptr = inbuf; + keepingstrlist = NULL; + tempoptionlist = NULL; + switch_strpos = 0; + dollar_flag = 0; + if_flag = 0; + if_skip = 0; + commenting_flag = 0; + skipflag = 0; + inbufindent = 0; + modulenotation = 1; + notephase = 0; + endnotelist = NULL; + for (i = 0; i < SYMHASHSIZE; i++) + symtab[i] = 0; + C_lex = 0; + lex_initialized = 0; +} + + +void setup_lex() +{ + lex_initialized = 1; + if (!strcmp(language, "MODCAL")) + sysprog_flag = 2; + else + sysprog_flag = 0; + if (shortcircuit < 0) + partial_eval_flag = (which_lang == LANG_TURBO || + which_lang == LANG_VAX || + which_lang == LANG_OREGON || + modula2 || + hpux_lang); + else + partial_eval_flag = shortcircuit; + iocheck_flag = 1; + range_flag = 1; + ovflcheck_flag = 1; + stackcheck_flag = 1; + fixedflag = 0; + withlevel = 0; + makekeywords(); + makePascalwords(); + recordsideeffects(); + topinput = 0; + ignore_directives = 0; + skipping_module = 0; + blockkind = TOK_END; + gettok(); +} + + + + +int checkeatnote(msg) +char *msg; +{ + Strlist *lp; + char *cp; + int len; + + for (lp = eatnotes; lp; lp = lp->next) { + if (!strcmp(lp->s, "1")) { + echoword("[*]", 0); + return 1; + } + if (!strcmp(lp->s, "0")) + return 0; + len = strlen(lp->s); + cp = msg; + while (*cp && (*cp != lp->s[0] || strncmp(cp, lp->s, len))) + cp++; + if (*cp) { + cp = lp->s; + if (*cp != '[') + cp = format_s("[%s", cp); + if (cp[strlen(cp)-1] != ']') + cp = format_s("%s]", cp); + echoword(cp, 0); + return 1; + } + } + return 0; +} + + + +void beginerror() +{ + end_source(); + if (showprogress) { + fprintf(stderr, "\r%60s\r", ""); + clearprogress(); + } else + echobreak(); +} + + +void counterror() +{ + if (maxerrors > 0) { + if (--maxerrors == 0) { + fprintf(outf, "\n/* Translation aborted: Too many errors. */\n"); + fprintf(outf, "-------------------------------------------\n"); + if (outf != stdout) + printf("Translation aborted: Too many errors.\n"); + if (verbose) + fprintf(logf, "Translation aborted: Too many errors.\n"); + closelogfile(); + exit(EXIT_FAILURE); + } + } +} + + +void error(msg) /* does not return */ +char *msg; +{ + flushcomments(NULL, -1, -1); + beginerror(); + fprintf(outf, "/* %s, line %d: %s */\n", infname, inf_lnum, msg); + fprintf(outf, "/* Translation aborted. */\n"); + fprintf(outf, "--------------------------\n"); + if (outf != stdout) { + printf("%s, line %d/%d: %s\n", infname, inf_lnum, outf_lnum, msg); + printf("Translation aborted.\n"); + } + if (verbose) { + fprintf(logf, "%s, line %d/%d: %s\n", + infname, inf_lnum, outf_lnum, msg); + fprintf(logf, "Translation aborted.\n"); + } + closelogfile(); + exit(EXIT_FAILURE); +} + + +void interror(proc, msg) /* does not return */ +char *proc, *msg; +{ + error(format_ss("Internal error in %s: %s", proc, msg)); +} + + +void warning(msg) +char *msg; +{ + if (checkeatnote(msg)) { + if (verbose) + fprintf(logf, "%s, %d/%d: Omitted warning: %s\n", + infname, inf_lnum, outf_lnum, msg); + return; + } + beginerror(); + addnote(format_s("Warning: %s", msg), curserial); + counterror(); +} + + +void intwarning(proc, msg) +char *proc, *msg; +{ + if (checkeatnote(msg)) { + if (verbose) + fprintf(logf, "%s, %d/%d: Omitted internal error in %s: %s\n", + infname, inf_lnum, outf_lnum, proc, msg); + return; + } + beginerror(); + addnote(format_ss("Internal error in %s: %s", proc, msg), curserial); + if (error_crash) + exit(EXIT_FAILURE); + counterror(); +} + + + + +void note(msg) +char *msg; +{ + if (blockkind == TOK_IMPORT || checkeatnote(msg)) { + if (verbose) + fprintf(logf, "%s, %d/%d: Omitted note: %s\n", + infname, inf_lnum, outf_lnum, msg); + return; + } + beginerror(); + addnote(format_s("Note: %s", msg), curserial); + counterror(); +} + + + +void endnote(msg) +char *msg; +{ + if (blockkind == TOK_IMPORT || checkeatnote(msg)) { + if (verbose) + fprintf(logf, "%s, %d/%d: Omitted end-note: %s\n", + infname, inf_lnum, outf_lnum, msg); + return; + } + if (verbose) + fprintf(logf, "%s, %d/%d: Recorded end-note: %s\n", + infname, inf_lnum, outf_lnum, msg); + (void) strlist_add(&endnotelist, msg); +} + + +void showendnotes() +{ + while (initialcalls) { + if (initialcalls->value) + endnote(format_s("Remember to call %s in main program [215]", + initialcalls->s)); + strlist_eat(&initialcalls); + } + if (endnotelist) { + end_source(); + while (endnotelist) { + if (outf != stdout) { + beginerror(); + printf("Note: %s\n", endnotelist->s); + } + fprintf(outf, "/* p2c: Note: %s */\n", endnotelist->s); + outf_lnum++; + strlist_eat(&endnotelist); + } + } +} + + + + + + + +char *tok_name(tok) +Token tok; +{ + if (tok == TOK_END && inputkind == INP_STRLIST) + return "end of macro"; + if (tok == curtok && tok == TOK_IDENT) + return format_s("'%s'", curtokcase); + if (!modulenotation) { + switch (tok) { + case TOK_MODULE: return "UNIT"; + case TOK_IMPORT: return "USES"; + case TOK_EXPORT: return "INTERFACE"; + case TOK_IMPLEMENT: return "IMPLEMENTATION"; + default: break; + } + } + return toknames[(int) tok]; +} + + + +void expected(msg) +char *msg; +{ + error(format_ss("Expected %s, found %s", msg, tok_name(curtok))); +} + + +void expecttok(tok) +Token tok; +{ + if (curtok != tok) + expected(tok_name(tok)); +} + + +void needtok(tok) +Token tok; +{ + if (curtok != tok) + expected(tok_name(tok)); + gettok(); +} + + +int wexpected(msg) +char *msg; +{ + warning(format_ss("Expected %s, found %s [227]", msg, tok_name(curtok))); + return 0; +} + + +int wexpecttok(tok) +Token tok; +{ + if (curtok != tok) + return wexpected(tok_name(tok)); + else + return 1; +} + + +int wneedtok(tok) +Token tok; +{ + if (wexpecttok(tok)) { + gettok(); + return 1; + } else + return 0; +} + + +void alreadydef(sym) +Symbol *sym; +{ + warning(format_s("Symbol '%s' was already defined [220]", sym->name)); +} + + +void undefsym(sym) +Symbol *sym; +{ + warning(format_s("Symbol '%s' is not defined [221]", sym->name)); +} + + +void symclass(sym) +Symbol *sym; +{ + warning(format_s("Symbol '%s' is not of the appropriate class [222]", sym->name)); +} + + +void badtypes() +{ + warning("Type mismatch [223]"); +} + + +void valrange() +{ + warning("Value range error [224]"); +} + + + +void skipparens() +{ + Token begintok; + + if (curtok == TOK_LPAR) { + gettok(); + while (curtok != TOK_RPAR) + skipparens(); + } else if (curtok == TOK_LBR) { + gettok(); + while (curtok != TOK_RBR) + skipparens(); + } else if (curtok == TOK_BEGIN || curtok == TOK_RECORD || + curtok == TOK_CASE) { + begintok = curtok; + gettok(); + while (curtok != TOK_END) + if (curtok == TOK_CASE && begintok == TOK_RECORD) + gettok(); + else + skipparens(); + } + gettok(); +} + + +void skiptotoken2(tok1, tok2) +Token tok1, tok2; +{ + while (curtok != tok1 && curtok != tok2 && + curtok != TOK_END && curtok != TOK_RPAR && + curtok != TOK_RBR && curtok != TOK_EOF) + skipparens(); +} + + +void skippasttoken2(tok1, tok2) +Token tok1, tok2; +{ + skiptotoken2(tok1, tok2); + if (curtok == tok1 || curtok == tok2) + gettok(); +} + + +void skippasttotoken(tok1, tok2) +Token tok1, tok2; +{ + skiptotoken2(tok1, tok2); + if (curtok == tok1) + gettok(); +} + + +void skiptotoken(tok) +Token tok; +{ + skiptotoken2(tok, tok); +} + + +void skippasttoken(tok) +Token tok; +{ + skippasttoken2(tok, tok); +} + + + +int skipopenparen() +{ + if (wneedtok(TOK_LPAR)) + return 1; + skiptotoken(TOK_SEMI); + return 0; +} + + +int skipcloseparen() +{ + if (curtok == TOK_COMMA) + warning("Too many arguments for built-in routine [225]"); + else + if (wneedtok(TOK_RPAR)) + return 1; + skippasttotoken(TOK_RPAR, TOK_SEMI); + return 0; +} + + +int skipcomma() +{ + if (curtok == TOK_RPAR) + warning("Too few arguments for built-in routine [226]"); + else + if (wneedtok(TOK_COMMA)) + return 1; + skippasttotoken(TOK_RPAR, TOK_SEMI); + return 0; +} + + + + + +char *findaltname(name, num) +char *name; +int num; +{ + char *cp; + + if (num <= 0) + return name; + if (num == 1 && *alternatename1) + return format_s(alternatename1, name); + if (num == 2 && *alternatename2) + return format_s(alternatename2, name); + if (*alternatename) + return format_sd(alternatename, name, num); + cp = name; + if (*alternatename1) { + while (--num >= 0) + cp = format_s(alternatename1, cp); + } else { + while (--num >= 0) + cp = format_s("%s_", cp); + } + return cp; +} + + + + +Symbol *findsymbol_opt(name) +char *name; +{ + register int i; + register unsigned int hash; + register char *cp; + register Symbol *sp; + + hash = 0; + for (cp = name; *cp; cp++) + hash = hash*3 + *cp; + sp = symtab[hash % SYMHASHSIZE]; + while (sp && (i = strcmp(sp->name, name)) != 0) { + if (i < 0) + sp = sp->left; + else + sp = sp->right; + } + return sp; +} + + + +Symbol *findsymbol(name) +char *name; +{ + register int i; + register unsigned int hash; + register char *cp; + register Symbol **prev, *sp; + + hash = 0; + for (cp = name; *cp; cp++) + hash = hash*3 + *cp; + prev = symtab + (hash % SYMHASHSIZE); + while ((sp = *prev) != 0 && + (i = strcmp(sp->name, name)) != 0) { + if (i < 0) + prev = &(sp->left); + else + prev = &(sp->right); + } + if (!sp) { + sp = ALLOCV(sizeof(Symbol) + strlen(name), Symbol, symbols); + sp->mbase = sp->fbase = NULL; + sp->left = sp->right = NULL; + strcpy(sp->name, name); + sp->flags = 0; + sp->kwtok = TOK_NONE; + sp->symbolnames = NULL; + *prev = sp; + } + return sp; +} + + + + +void clearprogress() +{ + oldinfname = NULL; +} + + +void progress() +{ + char *ctxname; + int needrefr; + static int prevlen; + + if (showprogress) { + if (!curctx || curctx == nullctx || curctx->kind == MK_MODULE || + !strncmp(curctx->name, "__PROCPTR", 9) || blockkind == TOK_IMPORT) + ctxname = ""; + else + ctxname = curctx->name; + needrefr = (inf_lnum & 15) == 0; + if (oldinfname != infname || oldctxname != ctxname) { + if (oldinfname != infname) + prevlen = 60; + fprintf(stderr, "\r%*s", prevlen + 2, ""); + oldinfname = infname; + oldctxname = ctxname; + needrefr = 1; + } + if (needrefr) { + fprintf(stderr, "\r%5d %s %s", inf_lnum, infname, ctxname); + prevlen = 8 + strlen(infname) + strlen(ctxname); + } else { + fprintf(stderr, "\r%5d", inf_lnum); + prevlen = 5; + } + } +} + + + +void p2c_getline() +{ + char *cp, *cp2; + + switch (inputkind) { + + case INP_FILE: + case INP_INCFILE: + inf_lnum++; + inf_ltotal++; + if (fgets(inbuf, 300, inf)) { + cp = inbuf + strlen(inbuf); + if (*inbuf && cp[-1] == '\n') + cp[-1] = 0; + if (inbuf[0] == '#' && inbuf[1] == ' ' && isdigit(inbuf[2])) { + cp = inbuf + 2; /* in case input text came */ + inf_lnum = 0; /* from the C preprocessor */ + while (isdigit(*cp)) + inf_lnum = inf_lnum*10 + (*cp++) - '0'; + inf_lnum--; + while (isspace(*cp)) cp++; + if (*cp == '"' && (cp2 = my_strchr(cp+1, '"')) != NULL) { + cp++; + infname = stralloc(cp); + infname[cp2 - cp] = 0; + } + p2c_getline(); + return; + } + if (copysource && *inbuf) { + start_source(); + fprintf(outf, "%s\n", inbuf); + } + if (keepingstrlist) { + strlist_append(keepingstrlist, inbuf)->value = inf_lnum; + } + if (showprogress && inf_lnum % showprogress == 0) + progress(); + } else { + if (showprogress) + fprintf(stderr, "\n"); + if (inputkind == INP_INCFILE) { + pop_input(); + p2c_getline(); + } else + strcpy(inbuf, "\001"); + } + break; + + case INP_STRLIST: + if (instrlist) { + strcpy(inbuf, instrlist->s); + if (instrlist->value) + inf_lnum = instrlist->value; + else + inf_lnum++; + instrlist = instrlist->next; + } else + strcpy(inbuf, "\001"); + break; + } + inbufptr = inbuf; + inbufindent = 0; +} + + + + +Static void push_input() +{ + struct inprec *inp; + + inp = ALLOC(1, struct inprec, inprecs); + inp->kind = inputkind; + inp->fname = infname; + inp->lnum = inf_lnum; + inp->filep = inf; + inp->strlistp = instrlist; + inp->inbufptr = stralloc(inbufptr); + inp->curtok = curtok; + inp->curtoksym = curtoksym; + inp->curtokmeaning = curtokmeaning; + inp->curtokbuf = stralloc(curtokbuf); + inp->curtokcase = stralloc(curtokcase); + inp->saveblockkind = TOK_NIL; + inp->next = topinput; + topinput = inp; + inbufptr = inbuf + strlen(inbuf); +} + + + +void push_input_file(fp, fname, isinclude) +FILE *fp; +char *fname; +int isinclude; +{ + push_input(); + inputkind = (isinclude == 1) ? INP_INCFILE : INP_FILE; + inf = fp; + inf_lnum = 0; + infname = fname; + *inbuf = 0; + inbufptr = inbuf; + topinput->tempopts = tempoptionlist; + tempoptionlist = NULL; + if (isinclude != 2) + gettok(); +} + + +void include_as_import() +{ + if (inputkind == INP_INCFILE) { + if (topinput->saveblockkind == TOK_NIL) + topinput->saveblockkind = blockkind; + blockkind = TOK_IMPORT; + } else + warning(format_s("%s ignored except in include files [228]", + interfacecomment)); +} + + +void push_input_strlist(sp, fname) +Strlist *sp; +char *fname; +{ + push_input(); + inputkind = INP_STRLIST; + instrlist = sp; + if (fname) { + infname = fname; + inf_lnum = 0; + } else + inf_lnum--; /* adjust for extra p2c_getline() */ + *inbuf = 0; + inbufptr = inbuf; + gettok(); +} + + + +void pop_input() +{ + struct inprec *inp; + + if (inputkind == INP_FILE || inputkind == INP_INCFILE) { + while (tempoptionlist) { + undooption(tempoptionlist->value, tempoptionlist->s); + strlist_eat(&tempoptionlist); + } + tempoptionlist = topinput->tempopts; + if (inf) + fclose(inf); + } + inp = topinput; + topinput = inp->next; + if (inp->saveblockkind != TOK_NIL) + blockkind = inp->saveblockkind; + inputkind = inp->kind; + infname = inp->fname; + inf_lnum = inp->lnum; + inf = inp->filep; + curtok = inp->curtok; + curtoksym = inp->curtoksym; + curtokmeaning = inp->curtokmeaning; + strcpy(curtokbuf, inp->curtokbuf); + FREE(inp->curtokbuf); + strcpy(curtokcase, inp->curtokcase); + FREE(inp->curtokcase); + strcpy(inbuf, inp->inbufptr); + FREE(inp->inbufptr); + inbufptr = inbuf; + instrlist = inp->strlistp; + FREE(inp); +} + + + + +int undooption(i, name) +int i; +char *name; +{ + char kind = rctable[i].kind; + + switch (kind) { + + case 'S': + case 'B': + if (rcprevvalues[i]) { + *((short *)rctable[i].ptr) = rcprevvalues[i]->value; + strlist_eat(&rcprevvalues[i]); + return 1; + } + break; + + case 'I': + case 'D': + if (rcprevvalues[i]) { + *((int *)rctable[i].ptr) = rcprevvalues[i]->value; + strlist_eat(&rcprevvalues[i]); + return 1; + } + break; + + case 'L': + if (rcprevvalues[i]) { + *((long *)rctable[i].ptr) = rcprevvalues[i]->value; + strlist_eat(&rcprevvalues[i]); + return 1; + } + break; + + case 'R': + if (rcprevvalues[i]) { + *((double *)rctable[i].ptr) = atof(rcprevvalues[i]->s); + strlist_eat(&rcprevvalues[i]); + return 1; + } + break; + + case 'C': + case 'U': + if (rcprevvalues[i]) { + strcpy((char *)rctable[i].ptr, rcprevvalues[i]->s); + strlist_eat(&rcprevvalues[i]); + return 1; + } + break; + + case 'A': + strlist_remove((Strlist **)rctable[i].ptr, name); + return 1; + + case 'X': + if (rctable[i].def == 1) { + strlist_remove((Strlist **)rctable[i].ptr, name); + return 1; + } + break; + + } + return 0; +} + + + + +void badinclude() +{ + warning("Can't handle an \"include\" directive here [229]"); + inputkind = INP_INCFILE; /* expand it in-line */ + gettok(); +} + + + +int handle_include(fn) +char *fn; +{ + FILE *fp = NULL; + Strlist *sl; + + for (sl = includedirs; sl; sl = sl->next) { + fp = fopen(format_s(sl->s, fn), "r"); + if (fp) { + fn = stralloc(format_s(sl->s, fn)); + break; + } + } + if (!fp) { + perror(fn); + warning(format_s("Could not open include file %s [230]", fn)); + return 0; + } else { + if (!quietmode && !showprogress) + if (outf == stdout) + fprintf(stderr, "Reading include file \"%s\"\n", fn); + else + printf("Reading include file \"%s\"\n", fn); + if (verbose) + fprintf(logf, "Reading include file \"%s\"\n", fn); + if (expandincludes == 0) { + push_input_file(fp, fn, 2); + curtok = TOK_INCLUDE; + strcpy(curtokbuf, fn); + } else { + push_input_file(fp, fn, 1); + } + return 1; + } +} + + + +int turbo_directive(closing, after) +char *closing, *after; +{ + char *cp, *cp2; + int i, result; + + if (!strcincmp(inbufptr, "$double", 7)) { + cp = inbufptr + 7; + while (isspace(*cp)) cp++; + if (cp == closing) { + inbufptr = after; + doublereals = 1; + return 1; + } + } else if (!strcincmp(inbufptr, "$nodouble", 9)) { + cp = inbufptr + 9; + while (isspace(*cp)) cp++; + if (cp == closing) { + inbufptr = after; + doublereals = 0; + return 1; + } + } + switch (inbufptr[2]) { + + case '+': + case '-': + result = 1; + cp = inbufptr + 1; + for (;;) { + if (!isalpha(*cp++)) + return 0; + if (*cp != '+' && *cp != '-') + return 0; + if (++cp == closing) + break; + if (*cp++ != ',') + return 0; + } + cp = inbufptr + 1; + do { + switch (*cp++) { + + case 'b': + case 'B': + if (shortcircuit < 0 && which_lang != LANG_MPW) + partial_eval_flag = (*cp == '-'); + break; + + case 'i': + case 'I': + iocheck_flag = (*cp == '+'); + break; + + case 'r': + case 'R': + if (*cp == '+') { + if (!range_flag) + note("Range checking is ON [216]"); + range_flag = 1; + } else { + if (range_flag) + note("Range checking is OFF [216]"); + range_flag = 0; + } + break; + + case 's': + case 'S': + if (*cp == '+') { + if (!stackcheck_flag) + note("Stack checking is ON [217]"); + stackcheck_flag = 1; + } else { + if (stackcheck_flag) + note("Stack checking is OFF [217]"); + stackcheck_flag = 0; + } + break; + + default: + result = 0; + break; + } + cp++; + } while (*cp++ == ','); + if (result) + inbufptr = after; + return result; + + case 'c': + case 'C': + if (toupper(inbufptr[1]) == 'S' && + (inbufptr[3] == '+' || inbufptr[3] == '-') && + inbufptr + 4 == closing) { + if (shortcircuit < 0) + partial_eval_flag = (inbufptr[3] == '+'); + inbufptr = after; + return 1; + } + return 0; + + case ' ': + switch (inbufptr[1]) { + + case 'i': + case 'I': + if (skipping_module) + break; + cp = inbufptr + 3; + while (isspace(*cp)) cp++; + cp2 = cp; + i = 0; + while (*cp2 && cp2 != closing) + i++, cp2++; + if (cp2 != closing) + return 0; + while (isspace(cp[i-1])) + if (--i <= 0) + return 0; + inbufptr = after; + cp2 = ALLOC(i + 1, char, strings); + strncpy(cp2, cp, i); + cp2[i] = 0; + if (handle_include(cp2)) + return 2; + break; + + case 's': + case 'S': + cp = inbufptr + 3; + outsection(minorspace); + if (cp == closing) { + output("#undef __SEG__\n"); + } else { + output("#define __SEG__ "); + while (*cp && cp != closing) + cp++; + if (*cp) { + i = *cp; + *cp = 0; + output(inbufptr + 3); + *cp = i; + } + output("\n"); + } + outsection(minorspace); + inbufptr = after; + return 1; + + } + return 0; + + case '}': + case '*': + if (inbufptr + 2 == closing) { + switch (inbufptr[1]) { + + case 's': + case 'S': + outsection(minorspace); + output("#undef __SEG__\n"); + outsection(minorspace); + inbufptr = after; + return 1; + + } + } + return 0; + + case 'f': /* $ifdef etc. */ + case 'F': + if (toupper(inbufptr[1]) == 'I' && + ((toupper(inbufptr[3]) == 'O' && + toupper(inbufptr[4]) == 'P' && + toupper(inbufptr[5]) == 'T') || + (toupper(inbufptr[3]) == 'D' && + toupper(inbufptr[4]) == 'E' && + toupper(inbufptr[5]) == 'F') || + (toupper(inbufptr[3]) == 'N' && + toupper(inbufptr[4]) == 'D' && + toupper(inbufptr[5]) == 'E' && + toupper(inbufptr[6]) == 'F'))) { + note("Turbo Pascal conditional compilation directive was ignored [218]"); + } + return 0; + + } + return 0; +} + + + + +extern Strlist *addmacros; + +void defmacro(name, kind, fname, lnum) +char *name, *fname; +long kind; +int lnum; +{ + Strlist *defsl, *sl, *sl2; + Symbol *sym, *sym2; + Meaning *mp; + Expr *ex; + + defsl = NULL; + sl = strlist_append(&defsl, name); + C_lex++; + if (fname && !strcmp(fname, "<macro>") && curtok == TOK_IDENT) + fname = curtoksym->name; + push_input_strlist(defsl, fname); + if (fname) + inf_lnum = lnum; + switch (kind) { + + case MAC_VAR: + if (!wexpecttok(TOK_IDENT)) + break; + for (mp = curtoksym->mbase; mp; mp = mp->snext) { + if (mp->kind == MK_VAR) + warning(format_s("VarMacro must be defined before declaration of variable %s [231]", curtokcase)); + } + sl = strlist_append(&varmacros, curtoksym->name); + gettok(); + if (!wneedtok(TOK_EQ)) + break; + sl->value = (long)pc_expr(); + break; + + case MAC_CONST: + if (!wexpecttok(TOK_IDENT)) + break; + for (mp = curtoksym->mbase; mp; mp = mp->snext) { + if (mp->kind == MK_CONST) + warning(format_s("ConstMacro must be defined before declaration of variable %s [232]", curtokcase)); + } + sl = strlist_append(&constmacros, curtoksym->name); + gettok(); + if (!wneedtok(TOK_EQ)) + break; + sl->value = (long)pc_expr(); + break; + + case MAC_FIELD: + if (!wexpecttok(TOK_IDENT)) + break; + sym = curtoksym; + gettok(); + if (!wneedtok(TOK_DOT)) + break; + if (!wexpecttok(TOK_IDENT)) + break; + sym2 = curtoksym; + gettok(); + if (!wneedtok(TOK_EQ)) + break; + funcmacroargs = NULL; + sym->flags |= FMACREC; + ex = pc_expr(); + sym->flags &= ~FMACREC; + for (mp = sym2->fbase; mp; mp = mp->snext) { + if (mp->rectype && mp->rectype->meaning && + mp->rectype->meaning->sym == sym) + break; + } + if (mp) { + mp->constdefn = ex; + } else { + sl = strlist_append(&fieldmacros, + format_ss("%s.%s", sym->name, sym2->name)); + sl->value = (long)ex; + } + break; + + case MAC_FUNC: + if (!wexpecttok(TOK_IDENT)) + break; + sym = curtoksym; + if (sym->mbase && + (sym->mbase->kind == MK_FUNCTION || + sym->mbase->kind == MK_SPECIAL)) + sl = NULL; + else + sl = strlist_append(&funcmacros, sym->name); + gettok(); + funcmacroargs = NULL; + if (curtok == TOK_LPAR) { + do { + gettok(); + if (curtok == TOK_RPAR && !funcmacroargs) + break; + if (!wexpecttok(TOK_IDENT)) { + skiptotoken2(TOK_COMMA, TOK_RPAR); + continue; + } + sl2 = strlist_append(&funcmacroargs, curtoksym->name); + sl2->value = (long)curtoksym; + curtoksym->flags |= FMACREC; + gettok(); + } while (curtok == TOK_COMMA); + if (!wneedtok(TOK_RPAR)) + skippasttotoken(TOK_RPAR, TOK_EQ); + } + if (!wneedtok(TOK_EQ)) + break; + if (sl) + sl->value = (long)pc_expr(); + else + sym->mbase->constdefn = pc_expr(); + for (sl2 = funcmacroargs; sl2; sl2 = sl2->next) { + sym2 = (Symbol *)sl2->value; + sym2->flags &= ~FMACREC; + } + strlist_empty(&funcmacroargs); + break; + + } + if (curtok != TOK_EOF) + warning(format_s("Junk (%s) at end of macro definition [233]", tok_name(curtok))); + pop_input(); + C_lex--; + strlist_empty(&defsl); +} + + + +void check_unused_macros() +{ + Strlist *sl; + + if (warnmacros) { + for (sl = varmacros; sl; sl = sl->next) + warning(format_s("VarMacro %s was never used [234]", sl->s)); + for (sl = constmacros; sl; sl = sl->next) + warning(format_s("ConstMacro %s was never used [234]", sl->s)); + for (sl = fieldmacros; sl; sl = sl->next) + warning(format_s("FieldMacro %s was never used [234]", sl->s)); + for (sl = funcmacros; sl; sl = sl->next) + warning(format_s("FuncMacro %s was never used [234]", sl->s)); + } +} + + + + + +#define skipspc(cp) while (isspace(*cp)) cp++ + +Static int parsecomment(p2c_only, starparen) +int p2c_only, starparen; +{ + char namebuf[302]; + char *cp, *cp2 = namebuf, *closing, *after; + char kind, chgmode, upcflag; + long val, oldval, sign; + double dval; + int i, tempopt, hassign; + Strlist *sp; + Symbol *sym; + + if (if_flag) + return 0; + if (!p2c_only) { + if (!strncmp(inbufptr, noskipcomment, strlen(noskipcomment)) && + *noskipcomment) { + inbufptr += strlen(noskipcomment); + if (skipflag < 0) { + if (skipflag < -1) { + skipflag++; + } else { + curtok = TOK_ENDIF; + skipflag = 1; + return 2; + } + } else { + skipflag = 1; + return 1; + } + } + } + closing = inbufptr; + while (*closing && (starparen + ? (closing[0] != '*' || closing[1] != ')') + : (closing[0] != '}'))) + closing++; + if (!*closing) + return 0; + after = closing + (starparen ? 2 : 1); + cp = inbufptr; + while (cp < closing && (*cp != '#' || cp[1] != '#')) + cp++; /* Ignore comments */ + if (cp < closing) { + while (isspace(cp[-1])) + cp--; + *cp = '#'; /* avoid skipping spaces past closing! */ + closing = cp; + } + if (!p2c_only) { + if (!strncmp(inbufptr, "DUMP-SYMBOLS", 12) && + closing == inbufptr + 12) { + wrapup(); + inbufptr = after; + return 1; + } + if (!strncmp(inbufptr, fixedcomment, strlen(fixedcomment)) && + *fixedcomment && + inbufptr + strlen(fixedcomment) == closing) { + fixedflag++; + inbufptr = after; + return 1; + } + if (!strncmp(inbufptr, permanentcomment, strlen(permanentcomment)) && + *permanentcomment && + inbufptr + strlen(permanentcomment) == closing) { + permflag = 1; + inbufptr = after; + return 1; + } + if (!strncmp(inbufptr, interfacecomment, strlen(interfacecomment)) && + *interfacecomment && + inbufptr + strlen(interfacecomment) == closing) { + inbufptr = after; + curtok = TOK_INTFONLY; + return 2; + } + if (!strncmp(inbufptr, skipcomment, strlen(skipcomment)) && + *skipcomment && + inbufptr + strlen(skipcomment) == closing) { + inbufptr = after; + skipflag--; + if (skipflag == -1) { + skipping_module++; /* eat comments in skipped portion */ + do { + gettok(); + } while (curtok != TOK_ENDIF); + skipping_module--; + } + return 1; + } + if (!strncmp(inbufptr, signedcomment, strlen(signedcomment)) && + *signedcomment && !p2c_only && + inbufptr + strlen(signedcomment) == closing) { + inbufptr = after; + gettok(); + if (curtok == TOK_IDENT && curtokmeaning && + curtokmeaning->kind == MK_TYPE && + curtokmeaning->type == tp_char) { + curtokmeaning = mp_schar; + } else + warning("{SIGNED} applied to type other than CHAR [314]"); + return 2; + } + if (!strncmp(inbufptr, unsignedcomment, strlen(unsignedcomment)) && + *unsignedcomment && !p2c_only && + inbufptr + strlen(unsignedcomment) == closing) { + inbufptr = after; + gettok(); + if (curtok == TOK_IDENT && curtokmeaning && + curtokmeaning->kind == MK_TYPE && + curtokmeaning->type == tp_char) { + curtokmeaning = mp_uchar; + } else if (curtok == TOK_IDENT && curtokmeaning && + curtokmeaning->kind == MK_TYPE && + curtokmeaning->type == tp_integer) { + curtokmeaning = mp_unsigned; + } else if (curtok == TOK_IDENT && curtokmeaning && + curtokmeaning->kind == MK_TYPE && + curtokmeaning->type == tp_int) { + curtokmeaning = mp_uint; + } else + warning("{UNSIGNED} applied to type other than CHAR or INTEGER [313]"); + return 2; + } + if (*inbufptr == '$') { + i = turbo_directive(closing, after); + if (i) + return i; + } + } + tempopt = 0; + cp = inbufptr; + if (*cp == '*') { + cp++; + tempopt = 1; + } + if (!isalpha(*cp)) + return 0; + while ((isalnum(*cp) || *cp == '_') && cp2 < namebuf+300) + *cp2++ = toupper(*cp++); + *cp2 = 0; + i = numparams; + while (--i >= 0 && strcmp(rctable[i].name, namebuf)) ; + if (i < 0) + return 0; + kind = rctable[i].kind; + chgmode = rctable[i].chgmode; + if (chgmode == ' ') /* allowed in p2crc only */ + return 0; + if (chgmode == 'T' && lex_initialized) { + if (cp == closing || *cp == '=' || *cp == '+' || *cp == '-') + warning(format_s("%s works only at top of program [235]", + rctable[i].name)); + } + if (cp == closing) { + if (kind == 'S' || kind == 'I' || kind == 'D' || kind == 'L' || + kind == 'R' || kind == 'B' || kind == 'C' || kind == 'U') { + undooption(i, ""); + inbufptr = after; + return 1; + } + } + switch (kind) { + + case 'S': + case 'I': + case 'L': + val = oldval = (kind == 'L') ? *(( long *)rctable[i].ptr) : + (kind == 'S') ? *((short *)rctable[i].ptr) : + *(( int *)rctable[i].ptr); + switch (*cp) { + + case '=': + skipspc(cp); + hassign = (*++cp == '-' || *cp == '+'); + sign = (*cp == '-') ? -1 : 1; + cp += hassign; + if (isdigit(*cp)) { + val = 0; + while (isdigit(*cp)) + val = val * 10 + (*cp++) - '0'; + val *= sign; + if (kind == 'D' && !hassign) + val += 10000; + } else if (toupper(cp[0]) == 'D' && + toupper(cp[1]) == 'E' && + toupper(cp[2]) == 'F') { + val = rctable[i].def; + cp += 3; + } + break; + + case '+': + case '-': + if (chgmode != 'R') + return 0; + for (;;) { + if (*cp == '+') + val++; + else if (*cp == '-') + val--; + else + break; + cp++; + } + break; + + } + skipspc(cp); + if (cp != closing) + return 0; + strlist_insert(&rcprevvalues[i], "")->value = oldval; + if (tempopt) + strlist_insert(&tempoptionlist, "")->value = i; + if (kind == 'L') + *((long *)rctable[i].ptr) = val; + else if (kind == 'S') + *((short *)rctable[i].ptr) = val; + else + *((int *)rctable[i].ptr) = val; + inbufptr = after; + return 1; + + case 'D': + val = oldval = *((int *)rctable[i].ptr); + if (*cp++ != '=') + return 0; + skipspc(cp); + if (toupper(cp[0]) == 'D' && + toupper(cp[1]) == 'E' && + toupper(cp[2]) == 'F') { + val = rctable[i].def; + cp += 3; + } else { + cp2 = namebuf; + while (*cp && cp != closing && !isspace(*cp)) + *cp2++ = *cp++; + *cp2 = 0; + val = parsedelta(namebuf, -1); + if (!val) + return 0; + } + skipspc(cp); + if (cp != closing) + return 0; + strlist_insert(&rcprevvalues[i], "")->value = oldval; + if (tempopt) + strlist_insert(&tempoptionlist, "")->value = i; + *((int *)rctable[i].ptr) = val; + inbufptr = after; + return 1; + + case 'R': + if (*cp++ != '=') + return 0; + skipspc(cp); + if (toupper(cp[0]) == 'D' && + toupper(cp[1]) == 'E' && + toupper(cp[2]) == 'F') { + dval = rctable[i].def / 100.0; + cp += 3; + } else { + cp2 = cp; + while (isdigit(*cp) || *cp == '-' || *cp == '+' || + *cp == '.' || toupper(*cp) == 'E') + cp++; + if (cp == cp2) + return 0; + dval = atof(cp2); + } + skipspc(cp); + if (cp != closing) + return 0; + sprintf(namebuf, "%g", *((double *)rctable[i].ptr)); + strlist_insert(&rcprevvalues[i], namebuf); + if (tempopt) + strlist_insert(&tempoptionlist, namebuf)->value = i; + *((double *)rctable[i].ptr) = dval; + inbufptr = after; + return 1; + + case 'B': + if (*cp++ != '=') + return 0; + skipspc(cp); + if (toupper(cp[0]) == 'D' && + toupper(cp[1]) == 'E' && + toupper(cp[2]) == 'F') { + val = rctable[i].def; + cp += 3; + } else { + val = parse_breakstr(cp); + while (*cp && cp != closing && !isspace(*cp)) + cp++; + } + skipspc(cp); + if (cp != closing || val == -1) + return 0; + strlist_insert(&rcprevvalues[i], "")->value = + *((short *)rctable[i].ptr); + if (tempopt) + strlist_insert(&tempoptionlist, "")->value = i; + *((short *)rctable[i].ptr) = val; + inbufptr = after; + return 1; + + case 'C': + case 'U': + if (*cp == '=') { + cp++; + skipspc(cp); + for (cp2 = cp; cp2 != closing && !isspace(*cp2); cp2++) + if (!*cp2 || cp2-cp >= rctable[i].def) + return 0; + cp2 = (char *)rctable[i].ptr; + sp = strlist_insert(&rcprevvalues[i], cp2); + if (tempopt) + strlist_insert(&tempoptionlist, "")->value = i; + while (cp != closing && !isspace(*cp2)) + *cp2++ = *cp++; + *cp2 = 0; + if (kind == 'U') + upc((char *)rctable[i].ptr); + skipspc(cp); + if (cp != closing) + return 0; + inbufptr = after; + if (!strcmp(rctable[i].name, "LANGUAGE") && + !strcmp((char *)rctable[i].ptr, "MODCAL")) + sysprog_flag |= 2; + return 1; + } + return 0; + + case 'F': + case 'G': + if (*cp == '=' || *cp == '+' || *cp == '-') { + upcflag = (kind == 'F' && !pascalcasesens); + chgmode = *cp++; + skipspc(cp); + cp2 = namebuf; + while (isalnum(*cp) || *cp == '_' || *cp == '$' || *cp == '%') + *cp2++ = *cp++; + *cp2++ = 0; + if (!*namebuf) + return 0; + skipspc(cp); + if (cp != closing) + return 0; + if (upcflag) + upc(namebuf); + sym = findsymbol(namebuf); + if (rctable[i].def & FUNCBREAK) + sym->flags &= ~FUNCBREAK; + if (chgmode == '-') + sym->flags &= ~rctable[i].def; + else + sym->flags |= rctable[i].def; + inbufptr = after; + return 1; + } + return 0; + + case 'A': + if (*cp == '=' || *cp == '+' || *cp == '-') { + chgmode = *cp++; + skipspc(cp); + cp2 = namebuf; + while (cp != closing && !isspace(*cp) && *cp) + *cp2++ = *cp++; + *cp2++ = 0; + skipspc(cp); + if (cp != closing) + return 0; + if (chgmode != '+') + strlist_remove((Strlist **)rctable[i].ptr, namebuf); + if (chgmode != '-') + sp = strlist_insert((Strlist **)rctable[i].ptr, namebuf); + if (tempopt) + strlist_insert(&tempoptionlist, namebuf)->value = i; + inbufptr = after; + return 1; + } + return 0; + + case 'M': + if (!isspace(*cp)) + return 0; + skipspc(cp); + if (!isalpha(*cp)) + return 0; + for (cp2 = cp; *cp2 && cp2 != closing; cp2++) ; + if (cp2 > cp && cp2 == closing) { + inbufptr = after; + cp2 = format_ds("%.*s", (int)(cp2-cp), cp); + if (tp_integer != NULL) { + defmacro(cp2, rctable[i].def, NULL, 0); + } else { + sp = strlist_append(&addmacros, cp2); + sp->value = rctable[i].def; + } + return 1; + } + return 0; + + case 'X': + switch (rctable[i].def) { + + case 1: /* strlist with string values */ + if (!isspace(*cp) && *cp != '=' && + *cp != '+' && *cp != '-') + return 0; + chgmode = *cp++; + skipspc(cp); + cp2 = namebuf; + while (isalnum(*cp) || *cp == '_' || + *cp == '$' || *cp == '%' || + *cp == '.' || *cp == '-' || + (*cp == '\'' && cp[1] && cp[2] == '\'' && + cp+1 != closing && cp[1] != '=')) { + if (*cp == '\'') { + *cp2++ = *cp++; + *cp2++ = *cp++; + } + *cp2++ = *cp++; + } + *cp2++ = 0; + if (chgmode == '-') { + skipspc(cp); + if (cp != closing) + return 0; + strlist_remove((Strlist **)rctable[i].ptr, namebuf); + } else { + if (!isspace(*cp) && *cp != '=') + return 0; + skipspc(cp); + if (*cp == '=') { + cp++; + skipspc(cp); + } + if (chgmode == '=' || isspace(chgmode)) + strlist_remove((Strlist **)rctable[i].ptr, namebuf); + sp = strlist_append((Strlist **)rctable[i].ptr, namebuf); + if (tempopt) + strlist_insert(&tempoptionlist, namebuf)->value = i; + cp2 = namebuf; + while (*cp && cp != closing && !isspace(*cp)) + *cp2++ = *cp++; + *cp2++ = 0; + skipspc(cp); + if (cp != closing) + return 0; + sp->value = (long)stralloc(namebuf); + } + inbufptr = after; + if (lex_initialized) + handle_nameof(); /* as good a place to do this as any! */ + return 1; + + case 3: /* Synonym parameter */ + if (isspace(*cp) || *cp == '=' || + *cp == '+' || *cp == '-') { + chgmode = *cp++; + skipspc(cp); + cp2 = namebuf; + while (isalnum(*cp) || *cp == '_' || + *cp == '$' || *cp == '%') + *cp2++ = *cp++; + *cp2++ = 0; + if (!*namebuf) + return 0; + skipspc(cp); + if (!pascalcasesens) + upc(namebuf); + sym = findsymbol(namebuf); + if (chgmode == '-') { + if (cp != closing) + return 0; + sym->flags &= ~SSYNONYM; + inbufptr = after; + return 1; + } + if (*cp == '=') { + cp++; + skipspc(cp); + } + cp2 = namebuf; + while (isalnum(*cp) || *cp == '_' || + *cp == '$' || *cp == '%') + *cp2++ = *cp++; + *cp2++ = 0; + skipspc(cp); + if (cp != closing) + return 0; + sym->flags |= SSYNONYM; + if (!pascalcasesens) + upc(namebuf); + if (*namebuf) + strlist_append(&sym->symbolnames, "===")->value = + (long)findsymbol(namebuf); + else + strlist_append(&sym->symbolnames, "===")->value=0; + inbufptr = after; + return 1; + } + return 0; + + } + return 0; + + } + return 0; +} + + + +Static void comment(starparen) +int starparen; /* 0={ }, 1=(* *), 2=C comments*/ +{ + register char ch; + int nestcount = 1, startlnum = inf_lnum, wasrel = 0, trailing; + int i, cmtindent, cmtindent2, saveeat = eatcomments; + char *cp; + + if (!strncmp(inbufptr, embedcomment, strlen(embedcomment)) && + *embedcomment) + eatcomments = 0; + cp = inbuf; + while (isspace(*cp)) + cp++; + trailing = (*cp != '{' && ((*cp != '(' && *cp != '/') || cp[1] != '*')); + cmtindent = inbufindent; + cmtindent2 = cmtindent + 1 + (starparen != 0); + cp = inbufptr; + while (isspace(*cp)) + cmtindent2++, cp++; + cp = curtokbuf; + for (;;) { + ch = *inbufptr++; + switch (ch) { + + case '}': + if ((!starparen || nestedcomments == 0) && + starparen != 2 && + --nestcount <= 0) { + *cp = 0; + if (wasrel && !strcmp(curtokbuf, "\003")) + *curtokbuf = '\002'; + if (!commenting_flag) + commentline(trailing ? CMT_TRAIL : CMT_POST); + eatcomments = saveeat; + return; + } + break; + + case '{': + if (nestedcomments == 1 && starparen != 2) + nestcount++; + break; + + case '*': + if ((*inbufptr == ((starparen == 2) ? '/' : ')') && + (starparen || nestedcomments == 0)) && + --nestcount <= 0) { + inbufptr++; + *cp = 0; + if (wasrel && !strcmp(curtokbuf, "\003")) + *curtokbuf = '\002'; + if (!commenting_flag) + commentline(trailing ? CMT_TRAIL : CMT_POST); + eatcomments = saveeat; + return; + } + break; + + case '(': + if (*inbufptr == '*' && nestedcomments == 1 && + starparen != 2) { + *cp++ = ch; + ch = *inbufptr++; + nestcount++; + } + break; + + case 0: + *cp = 0; + if (commenting_flag) + saveinputcomment(inbufptr-1); + else + commentline(CMT_POST); + trailing = 0; + p2c_getline(); + i = 0; + for (;;) { + if (*inbufptr == ' ') { + inbufptr++; + i++; + } else if (*inbufptr == '\t') { + inbufptr++; + i++; + if (intabsize) + i = (i / intabsize + 1) * intabsize; + } else + break; + } + cp = curtokbuf; + if (*inbufptr) { + if (i == cmtindent2 && !starparen) + cmtindent--; + cmtindent2 = -1; + if (i >= cmtindent && i > 0) { + *cp++ = '\002'; + i -= cmtindent; + wasrel = 1; + } else { + *cp++ = '\003'; + } + while (--i >= 0) + *cp++ = ' '; + } else + *cp++ = '\003'; + continue; + + case EOFMARK: + error(format_d("Runaway comment from line %d", startlnum)); + eatcomments = saveeat; + return; /* unnecessary */ + + } + *cp++ = ch; + } +} + + + +char *getinlinepart() +{ + char *cp, *buf; + + for (;;) { + if (isspace(*inbufptr)) { + inbufptr++; + } else if (!*inbufptr) { + p2c_getline(); + } else if (*inbufptr == '{') { + inbufptr++; + comment(0); + } else if (*inbufptr == '(' && inbufptr[1] == '*') { + inbufptr += 2; + comment(1); + } else + break; + } + cp = inbufptr; + while (isspace(*cp) || isalnum(*cp) || + *cp == '_' || *cp == '$' || + *cp == '+' || *cp == '-' || + *cp == '<' || *cp == '>') + cp++; + if (cp == inbufptr) + return ""; + while (isspace(cp[-1])) + cp--; + buf = format_s("%s", inbufptr); + buf[cp-inbufptr] = 0; /* truncate the string */ + inbufptr = cp; + return buf; +} + + + + +Static int getflag() +{ + int res = 1; + + gettok(); + if (curtok == TOK_IDENT) { + res = (strcmp(curtokbuf, "OFF") != 0); + gettok(); + } + return res; +} + + + + +char getchartok() +{ + if (!*inbufptr) { + warning("Unexpected end of line [236]"); + return ' '; + } + if (isspace(*inbufptr)) { + warning("Whitespace not allowed here [237]"); + return ' '; + } + return *inbufptr++; +} + + + +char *getparenstr(buf) +char *buf; +{ + int count = 0; + char *cp; + + if (inbufptr < buf) /* this will get most bad cases */ + error("Can't handle a line break here"); + while (isspace(*buf)) + buf++; + cp = buf; + for (;;) { + if (!*cp) + error("Can't handle a line break here"); + if (*cp == '(') + count++; + if (*cp == ')') + if (--count < 0) + break; + cp++; + } + inbufptr = cp + 1; + while (cp > buf && isspace(cp[-1])) + cp--; + return format_ds("%.*s", (int)(cp - buf), buf); +} + + + +void leadingcomments() +{ + for (;;) { + switch (*inbufptr++) { + + case 0: + p2c_getline(); + break; + + case ' ': + case '\t': + case 26: + /* ignore whitespace */ + break; + + case '{': + if (!parsecomment(1, 0)) { + inbufptr--; + return; + } + break; + + case '(': + if (*inbufptr == '*') { + inbufptr++; + if (!parsecomment(1, 1)) { + inbufptr -= 2; + return; + } + break; + } + /* fall through */ + + default: + inbufptr--; + return; + + } + } +} + + + + +void get_C_string(term) +int term; +{ + char *cp = curtokbuf; + char ch; + int i; + + while ((ch = *inbufptr++)) { + if (ch == term) { + *cp = 0; + curtokint = cp - curtokbuf; + return; + } else if (ch == '\\') { + if (isdigit(*inbufptr)) { + i = (*inbufptr++) - '0'; + if (isdigit(*inbufptr)) + i = i*8 + (*inbufptr++) - '0'; + if (isdigit(*inbufptr)) + i = i*8 + (*inbufptr++) - '0'; + *cp++ = i; + } else { + ch = *inbufptr++; + switch (tolower(ch)) { + case 'n': + *cp++ = '\n'; + break; + case 't': + *cp++ = '\t'; + break; + case 'v': + *cp++ = '\v'; + break; + case 'b': + *cp++ = '\b'; + break; + case 'r': + *cp++ = '\r'; + break; + case 'f': + *cp++ = '\f'; + break; + case '\\': + *cp++ = '\\'; + break; + case '\'': + *cp++ = '\''; + break; + case '"': + *cp++ = '"'; + break; + case 'x': + if (isxdigit(*inbufptr)) { + if (isdigit(*inbufptr)) + i = (*inbufptr++) - '0'; + else + i = (toupper(*inbufptr++)) - 'A' + 10; + if (isdigit(*inbufptr)) + i = i*16 + (*inbufptr++) - '0'; + else if (isxdigit(*inbufptr)) + i = i*16 + (toupper(*inbufptr++)) - 'A' + 10; + *cp++ = i; + break; + } + /* fall through */ + default: + warning("Strange character in C string [238]"); + } + } + } else + *cp++ = ch; + } + *cp = 0; + curtokint = cp - curtokbuf; + warning("Unterminated C string [239]"); +} + + + + + +void begincommenting(cp) +char *cp; +{ + if (!commenting_flag) { + commenting_ptr = cp; + } + commenting_flag++; +} + + +void saveinputcomment(cp) +char *cp; +{ + if (commenting_ptr) + sprintf(curtokbuf, "%.*s", (int)(cp - commenting_ptr), commenting_ptr); + else + sprintf(curtokbuf, "\003%.*s", (int)(cp - inbuf), inbuf); + commentline(CMT_POST); + commenting_ptr = NULL; +} + + +void endcommenting(cp) +char *cp; +{ + commenting_flag--; + if (!commenting_flag) { + saveinputcomment(cp); + } +} + + + + +int peeknextchar() +{ + char *cp; + + cp = inbufptr; + while (isspace(*cp)) + cp++; + return *cp; +} + + + + +#ifdef LEXDEBUG +Static void zgettok(); +void gettok() +{ + zgettok(); + if (tokentrace) { + printf("gettok() found %s", tok_name(curtok)); + switch (curtok) { + case TOK_HEXLIT: + case TOK_OCTLIT: + case TOK_INTLIT: + case TOK_MININT: + printf(", curtokint = %d", curtokint); + break; + case TOK_REALLIT: + case TOK_STRLIT: + printf(", curtokbuf = %s", makeCstring(curtokbuf, curtokint)); + break; + default: + break; + } + putchar('\n'); + } +} +Static void zgettok() +#else +void gettok() +#endif +{ + register char ch; + register char *cp; + char ch2; + char *startcp; + int i; + + debughook(); + for (;;) { + switch ((ch = *inbufptr++)) { + + case 0: + if (commenting_flag) + saveinputcomment(inbufptr-1); + p2c_getline(); + cp = curtokbuf; + for (;;) { + inbufindent = 0; + for (;;) { + if (*inbufptr == '\t') { + inbufindent++; + if (intabsize) + inbufindent = (inbufindent / intabsize + 1) * intabsize; + } else if (*inbufptr == ' ') + inbufindent++; + else if (*inbufptr != 26) + break; + inbufptr++; + } + if (!*inbufptr && !commenting_flag) { /* blank line */ + *cp++ = '\001'; + p2c_getline(); + } else + break; + } + if (cp > curtokbuf) { + *cp = 0; + commentline(CMT_POST); + } + break; + + case '\t': + case ' ': + case 26: /* ignore ^Z's in Turbo files */ + while (*inbufptr++ == ch) ; + inbufptr--; + break; + + case '$': + if (dollar_idents) + goto ident; + if (dollar_flag) { + dollar_flag = 0; + curtok = TOK_DOLLAR; + return; + } + startcp = inbufptr-1; + while (isspace(*inbufptr)) + inbufptr++; + cp = inbufptr; + while (isxdigit(*cp)) + cp++; + if (cp > inbufptr && cp <= inbufptr+8 && !isalnum(*cp)) { + while (isspace(*cp)) + cp++; + if (!isdigit(*cp) && *cp != '\'') { + cp = curtokbuf; /* Turbo hex constant */ + while (isxdigit(*inbufptr)) + *cp++ = *inbufptr++; + *cp = 0; + curtok = TOK_HEXLIT; + curtokint = my_strtol(curtokbuf, NULL, 16); + return; + } + } + dollar_flag++; /* HP Pascal compiler directive */ + do { + gettok(); + if (curtok == TOK_IF) { /* $IF expr$ */ + Expr *ex; + Value val; + if (!skipping_module) { + if (!setup_complete) + error("$IF$ not allowed at top of program"); + + /* Even though HP Pascal doesn't let these nest, + there's no harm in supporting it. */ + if (if_flag) { + skiptotoken(TOK_DOLLAR); + if_flag++; + break; + } + gettok(); + ex = p_expr(tp_boolean); + val = eval_expr_consts(ex); + freeexpr(ex); + i = (val.type == tp_boolean && val.i); + free_value(&val); + if (!i) { + if (curtok != TOK_DOLLAR) { + warning("Syntax error in $IF$ expression [240]"); + skiptotoken(TOK_DOLLAR); + } + begincommenting(startcp); + if_flag++; + while (if_flag > 0) + gettok(); + endcommenting(inbufptr); + } + } else { + skiptotoken(TOK_DOLLAR); + } + } else if (curtok == TOK_END) { /* $END$ */ + if (if_flag) { + gettok(); + if (!wexpecttok(TOK_DOLLAR)) + skiptotoken(TOK_DOLLAR); + curtok = TOK_ENDIF; + if_flag--; + return; + } else { + gettok(); + if (!wexpecttok(TOK_DOLLAR)) + skiptotoken(TOK_DOLLAR); + } + } else if (curtok == TOK_IDENT) { + if (!strcmp(curtokbuf, "INCLUDE") && + !if_flag && !skipping_module) { + char *fn; + gettok(); + if (curtok == TOK_IDENT) { + fn = stralloc(curtokcase); + gettok(); + } else if (wexpecttok(TOK_STRLIT)) { + fn = stralloc(curtokbuf); + gettok(); + } else + fn = ""; + if (!wexpecttok(TOK_DOLLAR)) { + skiptotoken(TOK_DOLLAR); + } else { + if (handle_include(fn)) + return; + } + } else if (ignore_directives || + if_flag || + !strcmp(curtokbuf, "SEARCH") || + !strcmp(curtokbuf, "REF") || + !strcmp(curtokbuf, "DEF")) { + skiptotoken(TOK_DOLLAR); + } else if (!strcmp(curtokbuf, "SWITCH_STRPOS")) { + switch_strpos = getflag(); + } else if (!strcmp(curtokbuf, "SYSPROG")) { + if (getflag()) + sysprog_flag |= 1; + else + sysprog_flag &= ~1; + } else if (!strcmp(curtokbuf, "MODCAL")) { + if (getflag()) + sysprog_flag |= 2; + else + sysprog_flag &= ~2; + } else if (!strcmp(curtokbuf, "PARTIAL_EVAL")) { + if (shortcircuit < 0) + partial_eval_flag = getflag(); + } else if (!strcmp(curtokbuf, "IOCHECK")) { + iocheck_flag = getflag(); + } else if (!strcmp(curtokbuf, "RANGE")) { + if (getflag()) { + if (!range_flag) + note("Range checking is ON [216]"); + range_flag = 1; + } else { + if (range_flag) + note("Range checking is OFF [216]"); + range_flag = 0; + } + } else if (!strcmp(curtokbuf, "OVFLCHECK")) { + if (getflag()) { + if (!ovflcheck_flag) + note("Overflow checking is ON [219]"); + ovflcheck_flag = 1; + } else { + if (ovflcheck_flag) + note("Overflow checking is OFF [219]"); + ovflcheck_flag = 0; + } + } else if (!strcmp(curtokbuf, "STACKCHECK")) { + if (getflag()) { + if (!stackcheck_flag) + note("Stack checking is ON [217]"); + stackcheck_flag = 1; + } else { + if (stackcheck_flag) + note("Stack checking is OFF [217]"); + stackcheck_flag = 0; + } + } + skiptotoken2(TOK_DOLLAR, TOK_COMMA); + } else { + warning("Mismatched '$' signs [241]"); + dollar_flag = 0; /* got out of sync */ + return; + } + } while (curtok == TOK_COMMA); + break; + + case '"': + if (C_lex) { + get_C_string(ch); + curtok = TOK_STRLIT; + return; + } + goto stringLiteral; + + case '#': + if (modula2) { + curtok = TOK_NE; + return; + } + cp = inbufptr; + while (isspace(*cp)) cp++; + if (!strcincmp(cp, "INCLUDE", 7)) { + char *cp2, *cp3; + cp += 7; + while (isspace(*cp)) cp++; + cp2 = cp + strlen(cp) - 1; + while (isspace(*cp2)) cp2--; + if ((*cp == '"' && *cp2 == '"' && cp2 > cp) || + (*cp == '<' && *cp2 == '>')) { + inbufptr = cp2 + 1; + cp3 = stralloc(cp + 1); + cp3[cp2 - cp - 1] = 0; + if (handle_include(cp3)) + return; + else + break; + } + } + /* fall through */ + + case '\'': + if (C_lex && ch == '\'') { + get_C_string(ch); + if (curtokint != 1) + warning("Character constant has length != 1 [242]"); + curtokint = *curtokbuf; + curtok = TOK_CHARLIT; + return; + } + stringLiteral: + cp = curtokbuf; + ch2 = (ch == '"') ? '"' : '\''; + do { + if (ch == ch2) { + while ((ch = *inbufptr++) != '\n' && + ch != EOF) { + if (ch == ch2) { + if (*inbufptr != ch2 || modula2) + break; + else + inbufptr++; + } + *cp++ = ch; + } + if (ch != ch2) + warning("Error in string literal [243]"); + } else { + ch = *inbufptr++; + if (isdigit(ch)) { + i = 0; + while (isdigit(ch)) { + i = i*10 + ch - '0'; + ch = *inbufptr++; + } + inbufptr--; + *cp++ = i; + } else { + *cp++ = ch & 0x1f; + } + } + while (*inbufptr == ' ' || *inbufptr == '\t') + inbufptr++; + } while ((ch = *inbufptr++) == ch2 || ch == '#'); + inbufptr--; + *cp = 0; + curtokint = cp - curtokbuf; + curtok = TOK_STRLIT; + return; + + case '(': + if (*inbufptr == '*' && !C_lex) { + inbufptr++; + switch (commenting_flag ? 0 : parsecomment(0, 1)) { + case 0: + comment(1); + break; + case 2: + return; + } + break; + } else if (*inbufptr == '.') { + curtok = TOK_LBR; + inbufptr++; + } else { + curtok = TOK_LPAR; + } + return; + + case '{': + if (C_lex || modula2) { + curtok = TOK_LBRACE; + return; + } + switch (commenting_flag ? 0 : parsecomment(0, 0)) { + case 0: + comment(0); + break; + case 2: + return; + } + break; + + case '}': + if (C_lex || modula2) { + curtok = TOK_RBRACE; + return; + } + if (skipflag > 0) { + skipflag = 0; + } else + warning("Unmatched '}' in input file [244]"); + break; + + case ')': + curtok = TOK_RPAR; + return; + + case '*': + if (*inbufptr == (C_lex ? '/' : ')')) { + inbufptr++; + if (skipflag > 0) { + skipflag = 0; + } else + warning("Unmatched '*)' in input file [245]"); + break; + } else if (*inbufptr == '*' && !C_lex) { + curtok = TOK_STARSTAR; + inbufptr++; + } else + curtok = TOK_STAR; + return; + + case '+': + if (C_lex && *inbufptr == '+') { + curtok = TOK_PLPL; + inbufptr++; + } else + curtok = TOK_PLUS; + return; + + case ',': + curtok = TOK_COMMA; + return; + + case '-': + if (C_lex && *inbufptr == '-') { + curtok = TOK_MIMI; + inbufptr++; + } else if (*inbufptr == '>') { + curtok = TOK_ARROW; + inbufptr++; + } else + curtok = TOK_MINUS; + return; + + case '.': + if (*inbufptr == '.') { + curtok = TOK_DOTS; + inbufptr++; + } else if (*inbufptr == ')') { + curtok = TOK_RBR; + inbufptr++; + } else + curtok = TOK_DOT; + return; + + case '/': + if (C_lex && *inbufptr == '*') { + inbufptr++; + comment(2); + break; + } + curtok = TOK_SLASH; + return; + + case ':': + if (*inbufptr == '=') { + curtok = TOK_ASSIGN; + inbufptr++; + } else if (*inbufptr == ':') { + curtok = TOK_COLONCOLON; + inbufptr++; + } else + curtok = TOK_COLON; + return; + + case ';': + curtok = TOK_SEMI; + return; + + case '<': + if (*inbufptr == '=') { + curtok = TOK_LE; + inbufptr++; + } else if (*inbufptr == '>') { + curtok = TOK_NE; + inbufptr++; + } else if (*inbufptr == '<') { + curtok = TOK_LTLT; + inbufptr++; + } else + curtok = TOK_LT; + return; + + case '>': + if (*inbufptr == '=') { + curtok = TOK_GE; + inbufptr++; + } else if (*inbufptr == '>') { + curtok = TOK_GTGT; + inbufptr++; + } else + curtok = TOK_GT; + return; + + case '=': + if (*inbufptr == '=') { + curtok = TOK_EQEQ; + inbufptr++; + } else + curtok = TOK_EQ; + return; + + case '[': + curtok = TOK_LBR; + return; + + case ']': + curtok = TOK_RBR; + return; + + case '^': + curtok = TOK_HAT; + return; + + case '&': + if (*inbufptr == '&') { + curtok = TOK_ANDAND; + inbufptr++; + } else + curtok = TOK_AMP; + return; + + case '|': + if (*inbufptr == '|') { + curtok = TOK_OROR; + inbufptr++; + } else + curtok = TOK_VBAR; + return; + + case '~': + curtok = TOK_TWIDDLE; + return; + + case '!': + if (*inbufptr == '=') { + curtok = TOK_BANGEQ; + inbufptr++; + } else + curtok = TOK_BANG; + return; + + case '%': + if (C_lex) { + curtok = TOK_PERC; + return; + } + goto ident; + + case '?': + curtok = TOK_QM; + return; + + case '@': + curtok = TOK_ADDR; + return; + + case EOFMARK: + if (curtok == TOK_EOF) { + if (inputkind == INP_STRLIST) + error("Unexpected end of macro"); + else + error("Unexpected end of file"); + } + curtok = TOK_EOF; + return; + + default: + if (isdigit(ch)) { + cp = inbufptr; + while (isxdigit(*cp)) + cp++; + if (*cp == '#' && isxdigit(cp[1])) { + i = atoi(inbufptr-1); + inbufptr = cp+1; + } else if (toupper(cp[-1]) == 'B' || + toupper(cp[-1]) == 'C') { + inbufptr--; + i = 8; + } else if (toupper(*cp) == 'H') { + inbufptr--; + i = 16; + } else if ((ch == '0' && toupper(*inbufptr) == 'X' && + isxdigit(inbufptr[1]))) { + inbufptr++; + i = 16; + } else { + i = 10; + } + if (i != 10) { + curtokint = 0; + while (isdigit(*inbufptr) || + (i > 10 && isxdigit(*inbufptr))) { + ch = toupper(*inbufptr++); + curtokint *= i; + if (ch <= '9') + curtokint += ch - '0'; + else + curtokint += ch - 'A' + 10; + } + sprintf(curtokbuf, "%ld", curtokint); + if ((toupper(*inbufptr) == 'B' && i == 8) || + (toupper(*inbufptr) == 'H' && i == 16)) + inbufptr++; + if (toupper(*inbufptr) == 'C' && i == 8) { + inbufptr++; + curtok = TOK_STRLIT; + curtokbuf[0] = curtokint; + curtokbuf[1] = 0; + curtokint = 1; + return; + } + if (toupper(*inbufptr) == 'L') { + strcat(curtokbuf, "L"); + inbufptr++; + } + curtok = (i == 8) ? TOK_OCTLIT : TOK_HEXLIT; + return; + } + cp = curtokbuf; + i = 0; + while (ch == '0') + ch = *inbufptr++; + if (isdigit(ch)) { + while (isdigit(ch)) { + *cp++ = ch; + ch = *inbufptr++; + } + } else + *cp++ = '0'; + if (ch == '.') { + if (isdigit(*inbufptr)) { + *cp++ = ch; + ch = *inbufptr++; + i = 1; + while (isdigit(ch)) { + *cp++ = ch; + ch = *inbufptr++; + } + } + } + if (ch == 'e' || ch == 'E' || + ch == 'd' || ch == 'D' || + ch == 'q' || ch == 'Q') { + ch = *inbufptr; + if (isdigit(ch) || ch == '+' || ch == '-') { + *cp++ = 'e'; + inbufptr++; + i = 1; + do { + *cp++ = ch; + ch = *inbufptr++; + } while (isdigit(ch)); + } + } + inbufptr--; + *cp = 0; + if (i) { + curtok = TOK_REALLIT; + curtokint = cp - curtokbuf; + } else { + if (cp >= curtokbuf+10) { + i = strcmp(curtokbuf, "2147483648"); + if (cp > curtokbuf+10 || i > 0) { + curtok = TOK_REALLIT; + curtokint = cp - curtokbuf + 2; + strcat(curtokbuf, ".0"); + return; + } + if (i == 0) { + curtok = TOK_MININT; + curtokint = -2147483648; + return; + } + } + curtok = TOK_INTLIT; + curtokint = atol(curtokbuf); + if (toupper(*inbufptr) == 'L') { + strcat(curtokbuf, "L"); + inbufptr++; + } + } + return; + } else if (isalpha(ch) || ch == '_') { +ident: + { + register char *cp2; + curtoksym = NULL; + cp = curtokbuf; + cp2 = curtokcase; + *cp2++ = symcase ? ch : tolower(ch); + *cp++ = pascalcasesens ? ch : toupper(ch); + while (isalnum((ch = *inbufptr++)) || + ch == '_' || + (ch == '%' && !C_lex) || + (ch == '$' && dollar_idents)) { + *cp2++ = symcase ? ch : tolower(ch); + if (!ignorenonalpha || isalnum(ch)) + *cp++ = pascalcasesens ? ch : toupper(ch); + } + inbufptr--; + *cp2 = 0; + *cp = 0; + if (pascalsignif > 0) + curtokbuf[pascalsignif] = 0; + } + if (*curtokbuf == '%') { + if (!strcicmp(curtokbuf, "%INCLUDE")) { + char *cp2 = inbufptr; + while (isspace(*cp2)) cp2++; + if (*cp2 == '\'') + cp2++; + cp = curtokbuf; + while (*cp2 && *cp2 != '\'' && + *cp2 != ';' && !isspace(*cp2)) { + *cp++ = *cp2++; + } + *cp = 0; + cp = my_strrchr(curtokbuf, '/'); + if (cp && (!strcicmp(cp, "/LIST") || + !strcicmp(cp, "/NOLIST"))) + *cp = 0; + if (*cp2 == '\'') + cp2++; + while (isspace(*cp2)) cp2++; + if (*cp2 == ';') + cp2++; + while (isspace(*cp2)) cp2++; + if (!*cp2) { + inbufptr = cp2; + (void) handle_include(stralloc(curtokbuf)); + return; + } + } else if (!strcicmp(curtokbuf, "%TITLE") || + !strcicmp(curtokbuf, "%SUBTITLE")) { + gettok(); /* string literal */ + break; + } else if (!strcicmp(curtokbuf, "%PAGE")) { + /* should store a special page-break comment? */ + break; /* ignore token */ + } else if ((i = 2, !strcicmp(curtokbuf, "%B")) || + (i = 8, !strcicmp(curtokbuf, "%O")) || + (i = 16, !strcicmp(curtokbuf, "%X"))) { + while (isspace(*inbufptr)) inbufptr++; + if (*inbufptr == '\'') { + inbufptr++; + curtokint = 0; + while (*inbufptr && *inbufptr != '\'') { + ch = toupper(*inbufptr++); + if (isxdigit(ch)) { + curtokint *= i; + if (ch <= '9') + curtokint += ch - '0'; + else + curtokint += ch - 'A' + 10; + } else if (!isspace(ch)) + warning("Bad digit in literal [246]"); + } + if (*inbufptr) + inbufptr++; + sprintf(curtokbuf, "%ld", curtokint); + curtok = (i == 8) ? TOK_OCTLIT : TOK_HEXLIT; + return; + } + } + } + { + register unsigned int hash; + register Symbol *sp; + + hash = 0; + for (cp = curtokbuf; *cp; cp++) + hash = hash*3 + *cp; + sp = symtab[hash % SYMHASHSIZE]; + while (sp && (i = strcmp(sp->name, curtokbuf)) != 0) { + if (i < 0) + sp = sp->left; + else + sp = sp->right; + } + if (!sp) + sp = findsymbol(curtokbuf); + if (sp->flags & SSYNONYM) { + i = 100; + while (--i > 0 && sp && (sp->flags & SSYNONYM)) { + Strlist *sl; + sl = strlist_find(sp->symbolnames, "==="); + if (sl) + sp = (Symbol *)sl->value; + else + sp = NULL; + } + if (!sp) + break; /* ignore token */ + } + if (sp->kwtok && !(sp->flags & KWPOSS) && + (pascalcasesens != 2 || !islower(*curtokbuf)) && + (pascalcasesens != 3 || !isupper(*curtokbuf))) { + curtok = sp->kwtok; + return; + } + curtok = TOK_IDENT; + curtoksym = sp; + if ((i = withlevel) != 0 && sp->fbase) { + while (--i >= 0) { + curtokmeaning = sp->fbase; + while (curtokmeaning) { + if (curtokmeaning->rectype == withlist[i]) { + curtokint = i; + return; + } + curtokmeaning = curtokmeaning->snext; + } + } + } + curtokmeaning = sp->mbase; + while (curtokmeaning && !curtokmeaning->isactive) + curtokmeaning = curtokmeaning->snext; + if (!curtokmeaning) + return; + while (curtokmeaning->kind == MK_SYNONYM) + curtokmeaning = curtokmeaning->xnext; + /* look for unit.ident notation */ + if (curtokmeaning->kind == MK_MODULE || + curtokmeaning->kind == MK_FUNCTION) { + for (cp = inbufptr; isspace(*cp); cp++) ; + if (*cp == '.') { + for (cp++; isspace(*cp); cp++) ; + if (isalpha(*cp)) { + Meaning *mp = curtokmeaning; + Symbol *sym = curtoksym; + char *saveinbufptr = inbufptr; + gettok(); + if (curtok == TOK_DOT) + gettok(); + else + curtok = TOK_END; + if (curtok == TOK_IDENT) { + curtokmeaning = curtoksym->mbase; + while (curtokmeaning && + curtokmeaning->ctx != mp) + curtokmeaning = curtokmeaning->snext; + if (!curtokmeaning && + !strcmp(sym->name, "SYSTEM")) { + curtokmeaning = curtoksym->mbase; + while (curtokmeaning && + curtokmeaning->ctx != nullctx) + curtokmeaning = curtokmeaning->snext; + } + } else + curtokmeaning = NULL; + if (!curtokmeaning) { + /* oops, was probably funcname.field */ + inbufptr = saveinbufptr; + curtokmeaning = mp; + curtoksym = sym; + } + } + } + } + return; + } + } else { + warning(format_d("Unrecognized character 0%o in file [247]", + ch)); + } + } + } +} + + + +void checkkeyword(tok) +Token tok; +{ + if (curtok == TOK_IDENT && + curtoksym->kwtok == tok) { + curtoksym->flags &= ~KWPOSS; + curtok = tok; + } +} + + +void checkmodulewords() +{ + if (modula2) { + checkkeyword(TOK_FROM); + checkkeyword(TOK_DEFINITION); + checkkeyword(TOK_IMPLEMENT); + checkkeyword(TOK_MODULE); + checkkeyword(TOK_IMPORT); + checkkeyword(TOK_EXPORT); + } else if (curtok == TOK_IDENT && + (curtoksym->kwtok == TOK_MODULE || + curtoksym->kwtok == TOK_IMPORT || + curtoksym->kwtok == TOK_EXPORT || + curtoksym->kwtok == TOK_IMPLEMENT)) { + if (!strcmp(curtokbuf, "UNIT") || + !strcmp(curtokbuf, "USES") || + !strcmp(curtokbuf, "INTERFACE") || + !strcmp(curtokbuf, "IMPLEMENTATION")) { + modulenotation = 0; + findsymbol("UNIT")->flags &= ~KWPOSS; + findsymbol("USES")->flags &= ~KWPOSS; + findsymbol("INTERFACE")->flags &= ~KWPOSS; + findsymbol("IMPLEMENTATION")->flags &= ~KWPOSS; + } else { + modulenotation = 1; + findsymbol("MODULE")->flags &= ~KWPOSS; + findsymbol("EXPORT")->flags &= ~KWPOSS; + findsymbol("IMPORT")->flags &= ~KWPOSS; + findsymbol("IMPLEMENT")->flags &= ~KWPOSS; + } + curtok = curtoksym->kwtok; + } +} + + + + + + + + + + + + +/* End. */ + + + diff --git a/MultiSource/Benchmarks/MallocBench/p2c/libp2c.a b/MultiSource/Benchmarks/MallocBench/p2c/libp2c.a Binary files differnew file mode 100644 index 00000000..a2b76f3c --- /dev/null +++ b/MultiSource/Benchmarks/MallocBench/p2c/libp2c.a diff --git a/MultiSource/Benchmarks/MallocBench/p2c/loc.p2clib.c b/MultiSource/Benchmarks/MallocBench/p2c/loc.p2clib.c new file mode 100644 index 00000000..5ad3b636 --- /dev/null +++ b/MultiSource/Benchmarks/MallocBench/p2c/loc.p2clib.c @@ -0,0 +1,6 @@ + +/* Put p2c runtime features local to your system here. + * In particular, additional initialization may be provided by defining + * the symbol LOCAL_INIT when you compile p2clib.c. + */ + diff --git a/MultiSource/Benchmarks/MallocBench/p2c/makeproto b/MultiSource/Benchmarks/MallocBench/p2c/makeproto Binary files differnew file mode 100644 index 00000000..adaaa6f9 --- /dev/null +++ b/MultiSource/Benchmarks/MallocBench/p2c/makeproto diff --git a/MultiSource/Benchmarks/MallocBench/p2c/out.c b/MultiSource/Benchmarks/MallocBench/p2c/out.c new file mode 100644 index 00000000..e0591ae8 --- /dev/null +++ b/MultiSource/Benchmarks/MallocBench/p2c/out.c @@ -0,0 +1,1580 @@ +/* "p2c", a Pascal to C translator. + Copyright (C) 1989, 1990, 1991 Free Software Foundation. + Author's address: daveg@csvax.caltech.edu; 256-80 Caltech/Pasadena CA 91125. + +This program is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation (any version). + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; see the file COPYING. If not, write to +the Free Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ + + + + +/* This needs to go before trans.h (and thus p2c.proto) is read */ + +typedef struct S_paren { + struct S_paren *next; + int pos, indent, qmindent, flags; +} Paren; + + + +#define PROTO_OUT_C +#include "trans.h" + + +#ifndef USETIME +# if defined(BSD) || defined(hpux) +# define USETIME 1 +# else +# define USETIME 0 +# endif +#endif + +#if USETIME +# include <sys/time.h> +#else +# include <time.h> +#endif + + + + +/* Output control characters: + + \001 \B Possible break point + \002 \X Break point in parentheses + \003 \( Invisible open paren + \004 \) Invisible close paren + \005 \T Set left margin + \006 \F Forced break point + \007 \A Preceding paren requires all-or-none breaking + \010 \[ Invisible open paren, becomes visible if not all on one line + \011 \S Break point after last "special argument" of a function + \012 \n (newline) + \013 \E Preceding break has extra penalty + \014 \f (form-feed) + \015 \H Hang-indent the preceding operator + \016 \. (unused) + \017 \C Break point for last : of a ?: construct + +*/ + +char spchars[] = ".BX()TFA[SnEfH.C................"; + + + +Static int testinglinebreaker = 0; + +Static int deltaindent, thisindent, thisfutureindent; +Static int sectionsize, blanklines, codesectsize, hdrsectsize; +Static int codelnum, hdrlnum; + +#define MAXBREAKS 200 +Static int numbreaks, bestnumbreaks; +Static double bestbadness; +Static int breakpos[MAXBREAKS], breakindent[MAXBREAKS]; +Static int breakcount[MAXBREAKS], breakparen[MAXBREAKS]; +Static int bestbreakpos[MAXBREAKS], bestbreakindent[MAXBREAKS]; +Static int breakerrorflag; + +#define MAXEDITS 200 +Static int numedits, bestnumedits; +Static int editpos[MAXEDITS], besteditpos[MAXEDITS]; +Static char editold[MAXEDITS], editnew[MAXEDITS]; +Static char besteditold[MAXEDITS], besteditnew[MAXEDITS]; + +Static Paren *parenlist; + +Static long numalts, bestnumalts; +Static int randombreaks; + +Static char *outbuf; +Static int outbufpos, outbufcount, outbufsize; +Static int suppressnewline, lastlinelength; +Static int eatblanks; +Static int embeddedcode; +Static int showingsourcecode = 0; + +#define BIGBADNESS (1e20) + + + +void setup_out() +{ + end_source(); + if (!nobanner) + fprintf(outf, "/* From input file \"%s\" */\n", infname); + outf_lnum++; + hdrlnum = 1; + outindent = 0; + deltaindent = 0; + thisindent = 0; + thisfutureindent = -1; + sectionsize = 2; + blanklines = 0; + dontbreaklines = 0; + embeddedcode = 0; + outputmode = 0; + suppressnewline = 0; + eatblanks = 0; + outbufsize = 1000; + outbuf = ALLOC(outbufsize, char, misc); + outbufpos = 0; + outbufcount = 0; + srand(17); +} + + + +void select_outfile(fp) +FILE *fp; +{ + if (outf == codef) { + codesectsize = sectionsize; + codelnum = outf_lnum; + } else { + hdrsectsize = sectionsize; + hdrlnum = outf_lnum; + } + outf = fp; + if (outf == codef) { + sectionsize = codesectsize; + outf_lnum = codelnum; + } else { + sectionsize = hdrsectsize; + outf_lnum = hdrlnum; + } +} + + + +void start_source() +{ + if (!showingsourcecode) { + fprintf(outf, "\n#ifdef Pascal\n"); + showingsourcecode = 1; + } +} + +void end_source() +{ + if (showingsourcecode) { + fprintf(outf, "#endif /*Pascal*/\n\n"); + showingsourcecode = 0; + } +} + + + +int line_start() +{ + return (outbufcount == 0); +} + + +int cur_column() +{ + if (outbufpos == 0) + return outindent; + else + return thisindent + outbufcount; +} + + + +int lookback(n) +int n; +{ + if (n <= 0 || n > outbufpos) + return 0; + else + return outbuf[outbufpos - n]; +} + + +int lookback_prn(n) +int n; +{ + for (;;) { + if (n <= 0 || n > outbufpos) + return 0; + else if (outbuf[outbufpos - n] >= ' ') + return outbuf[outbufpos - n]; + else + n++; + } +} + + + +/* Combine two indentation adjustments */ +int adddeltas(d1, d2) +int d1, d2; +{ + if (d2 >= 1000) + return d2; + else + return d1 + d2; +} + + +/* Apply an indentation delta */ +int applydelta(i, d) +int i, d; +{ + if (d >= 1000) + return d - 1000; + else + return i + d; +} + + +/* Adjust the current indentation by delta */ +void moreindent(delta) +int delta; +{ + outindent = applydelta(outindent, delta); +} + + +/* Adjust indentation for just this line */ +void singleindent(delta) +int delta; +{ + deltaindent = adddeltas(deltaindent, delta); +} + + +/* Predict indentation for next line */ +void futureindent(num) +int num; +{ + thisfutureindent = applydelta(applydelta(outindent, deltaindent), num); +} + + +int parsedelta(cp, def) +char *cp; +int def; +{ + if (!cp || !*cp) + return def; + if ((*cp == '+' || *cp == '-') && isdigit(cp[1])) + return atoi(cp); + if (*cp == '*' && isdigit(cp[1])) + return 2000 + atoi(cp+1); + else + return 1000 + atoi(cp); +} + + + + +Static void leading_tab(col) +int col; +{ + if (col > maxlinewidth) + return; /* something wrong happened! */ + if (phystabsize > 0) { + while (col >= phystabsize) { + putc('\t', outf); + col -= phystabsize; + } + } + while (col > 0) { + putc(' ', outf); + col--; + } +} + + + +void eatblanklines() +{ + eatblanks = 1; +} + + + +Static void flush_outbuf(numbreaks, breakpos, breakindent, + numedits, editpos, editold, editnew) +int numbreaks, *breakpos, *breakindent, numedits, *editpos; +char *editold, *editnew; +{ + unsigned char ch, ch2; + char *cp; + int i, j, linelen = 0, spaces, hashline; + int editsaves[MAXEDITS]; + + end_source(); + if (outbufcount > 0) { + for (i = 0; i < numedits; i++) { + editsaves[i] = outbuf[editpos[i]]; + outbuf[editpos[i]] = editnew[i]; + } + leading_tab(thisindent); + cp = outbuf; + hashline = (*cp == '#'); /* a preprocessor directive */ + spaces = 0; + j = 1; + for (i = 0; i < outbufpos; ) { + if (j < numbreaks && i == breakpos[j]) { + if (hashline) + fprintf(outf, " \\"); /* trailing backslash required */ + putc('\n', outf); + outf_lnum++; + leading_tab(breakindent[j]); + linelen = breakindent[j]; + j++; + while (i < outbufpos && *cp == ' ') + i++, cp++; /* eat leading spaces */ + spaces = 0; /* eat trailing spaces */ + } else { + ch = *cp++; + if (ch == ' ') { + spaces++; + } else if (ch > ' ') { + linelen += spaces; + while (spaces > 0) + putc(' ', outf), spaces--; + linelen++; + if (ch == '\\' && embeddedcode) { + if (*cp == '[') { + putc('{', outf); + cp++, i++; + } else if (*cp == ']') { + putc('}', outf); + cp++, i++; + } else + putc(ch, outf); + } else + putc(ch, outf); + } else if (testinglinebreaker >= 3) { + linelen += spaces; + while (spaces > 0) + putc(' ', outf), spaces--; + linelen++; + putc('\\', outf); + ch2 = spchars[ch]; + if (ch2 != '.') + putc(ch2, outf); + else { + putc('0' + ((ch >> 6) & 7), outf); + putc('0' + ((ch >> 3) & 7), outf); + putc('0' + (ch & 7), outf); + } + } + i++; + } + } + for (i = 0; i < numedits; i++) + outbuf[editpos[i]] = editsaves[i]; + eatblanks = 0; + } else if (eatblanks) { + return; + } + if (suppressnewline) { + lastlinelength = linelen; + } else + putc('\n', outf); + outf_lnum++; +} + + + +#define ISQUOTE(ch) ((ch)=='"' || (ch)=='\'') +#define ISOPENP(ch) ((ch)=='(' || (ch)=='[' || (ch)=='\003' || (ch)=='\010') +#define ISCLOSEP(ch) ((ch)==')' || (ch)==']' || (ch)=='\004') +#define ISBREAK(ch) ((ch)=='\001' || (ch)=='\002' || (ch)=='\006' || (ch)=='\011' || (ch)=='\017') + +Static int readquotes(posp, err) +int *posp, err; +{ + int pos; + char quote; + + pos = *posp; + quote = outbuf[pos++]; + while (pos < outbufpos && outbuf[pos] != quote) { + if (outbuf[pos] == '\\') + pos++; + pos++; + } + if (pos >= outbufpos) { + if (err && breakerrorflag) { + intwarning("output", "Mismatched quotes [248]"); + breakerrorflag = 0; + } + return 0; + } else { + *posp = pos; + return 1; + } +} + + +Static int maxdepth; + +Static int readparens(posp, err) +int *posp, err; +{ + char ch, closing; + int pos, level; + + pos = *posp; + switch (outbuf[pos]) { + case '(': + closing = ')'; + break; + case '[': + closing = ']'; + break; + case '\003': + case '\010': + closing = '\004'; + break; + default: + closing = 0; + break; + } + level = 0; + for (;;) { + pos++; + if (pos >= outbufpos) + break; + ch = outbuf[pos]; + if (ISOPENP(ch)) { + level++; + if (level > maxdepth) + maxdepth = level; + } else if (ISCLOSEP(ch)) { + level--; + if (level < 0) { + if (closing && outbuf[pos] != closing) + break; + *posp = pos; + return 1; + } + } else if (ISQUOTE(ch)) { + if (!readquotes(&pos, err)) + return 0; + } + } + if (err && breakerrorflag) { + switch (closing) { + case ')': + intwarning("output", "Mismatched parentheses [249]"); + break; + case ']': + intwarning("output", "Mismatched brackets [249]"); + break; + default: + intwarning("output", "Mismatched clauses [250]"); + break; + } + breakerrorflag = 0; + } + return 0; +} + + + +Static int measurechars(first, last) +int first, last; +{ + int count = 0; + + while (first <= last) { + if (outbuf[first] >= ' ') + count++; + first++; + } + return count; +} + + + +Static void makeedit(pos, ch) +int pos, ch; +{ + editpos[numedits] = pos; + editold[numedits] = outbuf[pos]; + editnew[numedits] = ch; + outbuf[pos] = ch; + numedits++; +} + +Static void unedit() +{ + numedits--; + outbuf[editpos[numedits]] = editold[numedits]; +} + + +Static int parencount(par) +Paren *par; +{ + int count = 0; + + while (par) { + count++; + par = par->next; + } + return count; +} + + + + + +/* The following routine explores the tree of all possible line breaks, + pruning according to the fact that "badness" and "extra" are + increasing functions. The object is to find the set of breaks and + indentation with the least total badness. + (The basic idea was borrowed from Donald Knuth's "TeX".) +*/ + +/* As an additional optimization, the concept of a "simple" line is used, + i.e., a line with a structure such that the best break is sure to be + the straightforward left-to-right fill used by a simple word processor. + (For example, a long line with nothing but comma-breakpoints is simple.) + + Also, if the line is very long a few initial random passes are made just + to scope out an estimate of the eventual badness of the line. This + combined with the badness cull helps keep the breaker from using up its + quota of tries before even considering a key break point! Note that + when randombreaks==1, each call to trybreakline is fast since only one + branch is taken at each decision point. +*/ + + +#define randtest(lim) (!randombreaks ? -1 \ + : randombreaks > 0 \ + ? parencount(parens) < randombreaks-1 \ + : randombreaks == -2 \ + ? 0 \ + : (rand() & 0xfff) < (lim)) + +#define TB_BRKCOUNT 0x0ff +#define TB_FORCEBRK 0x100 +#define TB_NOBREAK 0x200 +#define TB_ALREADYBRK 0x400 +#define TB_ALLORNONE 0x800 +#define TB_EXTRAIND 0x1000 +#define TB_EXTRAIND2 0x2000 + +#define TBR_ABORT 0x1 +#define TBR_SIMPLE 0x2 +#define TBR_REACHED 0x4 + +Static int trybreakline(pos, count, indent, badness, flags, parens) +int pos, count, indent, flags; +double badness; +Paren *parens; +{ + int edited; + int i, j, jmask, f, pos2, r; + char ch, ch2, closing; + double extra, penalty; + Paren *pp; + +#if 0 + { static double save = -1; + if (showbadlimit != save) printf("Showbadlimit = %g\n", showbadlimit); + save = showbadlimit; + } +#endif + + if (numalts >= maxalts) + return TBR_ABORT; + jmask = -1; + for (;;) { + if (numbreaks >= MAXBREAKS) { /* must leave rest of line alone */ + count += measurechars(pos, outbufpos-1); + pos = outbufpos; + } + i = count - breakcount[numbreaks-1] + + breakindent[numbreaks-1] - linewidth; + if (i <= 0) + extra = 0; + else { + if (i + linewidth >= maxlinewidth || randombreaks == -2) + return 0; /* absolutely too long! */ + extra = overwidepenalty + ((long)i*i)*overwideextrapenalty; + jmask &= ~TBR_SIMPLE; + if (extra < 0) + extra = 0; + } + if ((testinglinebreaker > 1 && showbadlimit > 0) ? + (badness + extra >= showbadlimit) : + (badness + extra >= bestbadness)) { + numalts++; + return 0; /* no point in going on, badness will only increase */ + } + if (pos >= outbufpos) + break; + if (parens && pos >= parens->pos) { + indent = parens->indent; + flags = parens->flags; + parens = parens->next; + } + ch = outbuf[pos++]; + if (ch >= ' ') + count++; + switch (ch) { + + case '(': + case '[': + case '\003': /* "invisible open paren" */ + case '\010': /* "semi-invisible open paren" */ + pos2 = pos - 1; + if (!readparens(&pos2, 1)) + break; + i = measurechars(pos, pos2); + if (count + i - breakcount[numbreaks-1] + + breakindent[numbreaks-1] <= linewidth) { + /* it fits, so leave it on one line */ +#if 0 /* I don't think this is necessary */ + while (pos <= pos2) { + if (outbuf[pos] == '\002') { + jmask &= ~TBR_SIMPLE; + pos = pos2 + 1; + break; + } + pos++; + } +#else + pos = pos2 + 1; +#endif + count += i; + break; + } + pp = ALLOC(1, Paren, parens); /* doesn't fit, try poss breaks */ + pp->next = parens; + pp->pos = pos2; + pp->indent = indent; + pp->qmindent = indent; + pp->flags = flags; + parens = pp; + flags = 0; + if (ch == '\010' && /* change to real parens when broken */ + numedits+1 < MAXEDITS) { /* (assume it will be broken!) */ + makeedit(pos-1, '('); + makeedit(pos2, ')'); + count++; /* count the new open paren */ + edited = 1; + } else + edited = 0; + i = breakindent[numbreaks-1] + count - breakcount[numbreaks-1]; + if (i <= thisindent) + r = 0; /* e.g., don't break top-level assignments */ + else if (i == indent + extraindent) + r = 1; /* don't waste time on identical operations */ + else + r = randtest(0xc00); + if (r != 0) { + j = trybreakline(pos, count, i, + badness + MAX(- extraindentpenalty,0), + flags, parens); + } else + j = 0; + if (r != 1) { + j &= trybreakline(pos, count, indent + extraindent, + badness + MAX(extraindentpenalty,0), + flags | TB_EXTRAIND, parens); + } + if (!randombreaks && bumpindent != 0) { + if (i == thisfutureindent) { + j &= trybreakline(pos, count, i + bumpindent, + badness + MAX(- extraindentpenalty,0) + + bumpindentpenalty, + flags, parens); + } else if (indent + extraindent == thisfutureindent) { + j &= trybreakline(pos, count, + indent + extraindent + bumpindent, + badness + MAX(extraindentpenalty,0) + + bumpindentpenalty, + flags | TB_EXTRAIND, parens); + } + } + if (edited) { + unedit(); + unedit(); + } + FREE(pp); + return j & jmask; + + case '\005': /* "set left margin" */ + indent = breakindent[numbreaks-1] + + count - breakcount[numbreaks-1]; + break; + + case '\007': /* "all-or-none breaking" */ + flags |= TB_ALLORNONE; + break; + + case '\001': /* "possible break point" */ + case '\002': /* "break point in parens" */ + case '\006': /* "forced break point" */ + case '\011': /* "break point after special args" */ + case '\017': /* "break point for final : operator" */ + /* first try the non-breaking case */ + if (ch != '\001' && ch != '\006') + jmask &= ~TBR_SIMPLE; + if ((flags & TB_BRKCOUNT) != TB_BRKCOUNT) + flags++; /* increment TB_BRKCOUNT field */ + if (outbuf[pos] == '?' && parens) + parens->qmindent = breakindent[numbreaks-1] + + count - breakcount[numbreaks-1]; + j = TBR_REACHED; + if (ch == '\006' || (flags & TB_FORCEBRK)) { + /* don't try the non-breaking case */ + } else { + if (ch == '\011') { + i = breakindent[numbreaks-1] + + count - breakcount[numbreaks-1] + 2; + } else { + i = indent; + } + f = flags; + if (f & TB_ALLORNONE) + f |= TB_NOBREAK; + r = randtest(0x800); + if (r != 1 || (flags & TB_NOBREAK)) { + j = trybreakline(pos, count, i, badness, f, parens) & + jmask; + if (randombreaks == -2 && !(j & TBR_REACHED)) { + r = -1; + j |= TBR_REACHED; + } + if (r == 0 || (j & TBR_SIMPLE)) + flags |= TB_NOBREAK; + } + } + if (flags & TB_NOBREAK) + return j; + if (flags & TB_ALLORNONE) + flags |= TB_FORCEBRK; + if (flags & TB_EXTRAIND) { + flags &= ~TB_EXTRAIND; + flags |= TB_EXTRAIND2; + } + /* now try breaking here */ + if (ch == '\017') + indent = parens->qmindent; + if (indent < 0) + indent = 0; + breakpos[numbreaks] = pos; + breakcount[numbreaks] = count; + breakindent[numbreaks] = indent; + breakparen[numbreaks] = parens ? parens->pos : 0; + numbreaks++; + penalty = extra; + if (indent == thisfutureindent) { + i = pos; + while (i < outbufpos-1 && outbuf[i] <= ' ') + i++; + ch2 = outbuf[i]; /* first character on next line */ + if (ch2 != '(' && ch2 != '!' && ch2 != '~' && ch2 != '-') + penalty += nobumpindentpenalty; + } + switch (ch) { + case '\001': + penalty += commabreakpenalty; + if (flags & TB_ALREADYBRK) + penalty += morebreakpenalty; + break; + case '\011': + i = parencount(parens); + penalty += specialargbreakpenalty + commabreakextrapenalty*i; + break; + case '\002': + case '\017': + i = parencount(parens); + if (outbuf[pos-2] == '(') + penalty += parenbreakpenalty + parenbreakextrapenalty*i; + else if (outbuf[pos-2] == ',') + penalty += commabreakpenalty + commabreakextrapenalty*i; + else if (((outbuf[pos] == '&' || outbuf[pos] == '|') && + outbuf[pos+1] == outbuf[pos]) || + ((outbuf[pos-3] == '&' || outbuf[pos-3] == '|') && + outbuf[pos-3] == outbuf[pos-2])) + penalty += logbreakpenalty + logbreakextrapenalty*i; + else if (((outbuf[pos] == '<' || outbuf[pos] == '>') && + outbuf[pos+1] != outbuf[pos]) || + ((outbuf[pos] == '=' || outbuf[pos] == '!') && + outbuf[pos+1] == '=') || + ((outbuf[pos-2] == '<' || outbuf[pos-2] == '>') && + outbuf[pos-3] != outbuf[pos-2]) || + ((outbuf[pos-3] == '<' || outbuf[pos-3] == '>' || + outbuf[pos-3] == '=' || outbuf[pos-3] == '!') && + outbuf[pos-2] == '=')) + penalty += relbreakpenalty + relbreakextrapenalty*i; + else if (outbuf[pos-2] == '=') + penalty += assignbreakpenalty + assignbreakextrapenalty*i; + else if (outbuf[pos] == '?') { + penalty += qmarkbreakpenalty + qmarkbreakextrapenalty*i; + if (parens) + parens->qmindent = breakindent[numbreaks-1] + + count - breakcount[numbreaks-1]; + } else + penalty += opbreakpenalty + opbreakextrapenalty*i; + if (outbuf[pos-2] == '-') + penalty += exhyphenpenalty; + if (flags & TB_ALREADYBRK) + penalty += morebreakpenalty + morebreakextrapenalty*i; + break; + default: + break; + } + while (pos < outbufpos && outbuf[pos] == '\013') { + penalty += wrongsidepenalty; + pos++; + } + penalty -= earlybreakpenalty*(flags & TB_BRKCOUNT); + /* the following test is not quite right, but it's not too bad. */ + if (breakindent[numbreaks-2] == breakindent[numbreaks-1] && + breakparen[numbreaks-2] != breakparen[numbreaks-1]) + penalty += sameindentpenalty; +#if 0 + else if (ch == '\002' && parens && /*don't think this is needed*/ + parens->indent == breakindent[numbreaks-1] && + parens->pos != breakparen[numbreaks-1]) + penalty += sameindentpenalty + 0.001; /***/ +#endif + penalty += (breakindent[numbreaks-1] - thisindent) * + indentamountpenalty; + if (penalty < 1) penalty = 1; + pos2 = pos; + while (pos2 < outbufpos && outbuf[pos2] == ' ') + pos2++; + flags |= TB_ALREADYBRK; + j = trybreakline(pos2, count, indent, badness + penalty, + flags, parens) & jmask; + numbreaks--; + return j; + + case '\015': /* "hang-indent operator" */ + if (count <= breakcount[numbreaks-1] + 2 && + !(flags & TB_EXTRAIND2)) { + breakindent[numbreaks-1] -= count - breakcount[numbreaks-1]; + pos2 = pos; + while (pos2 < outbufpos && outbuf[pos2] <= ' ') { + if (outbuf[pos2] == ' ') + breakindent[numbreaks-1]--; + pos2++; + } + } + break; + + case '"': + case '\'': + closing = ch; + while (pos < outbufpos && outbuf[pos] != closing) { + if (outbuf[pos] == '\\') + pos++, count++; + pos++; + count++; + } + if (pos >= outbufpos) { + intwarning("output", "Mismatched quotes [248]"); + continue; + } + pos++; + count++; + break; + + case '/': + if (pos < outbufpos && (outbuf[pos] == '*' || + (outbuf[pos] == '/' && cplus > 0))) { + count += measurechars(pos, outbufpos-1); + pos = outbufpos; /* assume comment is at end of line */ + } + break; + + } + } + numalts++; + badness += extra; + if (testinglinebreaker > 1) { + if (badness >= bestbadness && + (badness < showbadlimit || showbadlimit == 0)) { + fprintf(outf, "\n#if 0 /* rejected #%ld, badness = %g >= %g */\n", numalts, badness, bestbadness); + flush_outbuf(numbreaks, breakpos, breakindent, + numedits, editpos, editold, editnew); + fprintf(outf, "#endif\n"); + return TBR_SIMPLE & jmask; + } else if ((bestbadness < showbadlimit || showbadlimit == 0) && + bestnumalts > 0) { + fprintf(outf, "\n#if 0 /* rejected #%ld, badness = %g > %g */\n", bestnumalts, bestbadness, badness); + flush_outbuf(bestnumbreaks, bestbreakpos, bestbreakindent, + bestnumedits, besteditpos, + besteditold, besteditnew); + fprintf(outf, "#endif\n"); + } + } + bestbadness = badness; + bestnumbreaks = numbreaks; + bestnumalts = numalts; + for (i = 0; i < numbreaks; i++) { + bestbreakpos[i] = breakpos[i]; + bestbreakindent[i] = breakindent[i]; + } + bestnumedits = numedits; + for (i = 0; i < numedits; i++) { + besteditpos[i] = editpos[i]; + besteditold[i] = editold[i]; + besteditnew[i] = editnew[i]; + } + return TBR_SIMPLE & jmask; +} + + + + +int parse_breakstr(cp) +char *cp; +{ + short val = 0; + + if (isdigit(*cp)) + return atoi(cp); + while (*cp && !isspace(*cp) && *cp != '}') { + switch (toupper(*cp++)) { + + case 'N': + case '=': + break; + + case 'L': + val |= BRK_LEFT; + break; + + case 'R': + val |= BRK_RIGHT; + break; + + case 'H': + val |= BRK_HANG | BRK_LEFT; + break; + + case '>': + if (val & BRK_LEFT) + val |= BRK_LPREF; + else if (val & BRK_RIGHT) + val |= BRK_RPREF; + else + return -1; + break; + + case '<': + if (val & BRK_LEFT) + val |= BRK_RPREF; + else if (val & BRK_RIGHT) + val |= BRK_LPREF; + else + return -1; + break; + + case 'A': + val |= BRK_ALLNONE; + break; + + default: + return -1; + + } + } + return val; +} + + + + +long getcurtime() +{ +#if USETIME + static unsigned long starttime = 0; + struct timeval t; + struct timezone tz; + + gettimeofday(&t, &tz); + if (starttime == 0) + starttime = t.tv_sec; + t.tv_sec -= starttime; + return (t.tv_sec*1000 + t.tv_usec/1000); +#else + static unsigned long starttime = 0; + if (!starttime) starttime = time(NULL); + return (time(NULL) - starttime) * 1000; +#endif +} + + + +void output(msg) +register char *msg; +{ + unsigned char ch; + double savelimit; + int i, savemaxlw, maxdp; + long alts; + long time0, time0a, time1; + + debughook(); + if (outputmode) { + end_source(); + while ((ch = *msg++) != 0) { + if (ch >= ' ') { + putc(ch, outf); + } else if (ch == '\n') { + putc('\n', outf); + outf_lnum++; + } + } + return; + } + while ((ch = *msg++) != 0) { + if (ch == '\n') { + if (outbufpos == 0) { /* blank line */ + thisfutureindent = -1; + blanklines++; + continue; + } + if (sectionsize > blanklines) + blanklines = sectionsize; + sectionsize = 0; + if (eatblanks) + blanklines = 0; + while (blanklines > 0) { + blanklines--; + end_source(); + putc('\n', outf); + outf_lnum++; + } + if (thisindent + outbufcount >= linewidth && !dontbreaklines) { + numbreaks = 1; + bestnumbreaks = 0; + bestbadness = BIGBADNESS; + breakpos[0] = 0; + breakindent[0] = thisindent; + breakcount[0] = 0; + breakerrorflag = 1; + numedits = 0; + bestnumedits = 0; + savelimit = showbadlimit; + numalts = 0; + bestnumalts = 0; + savemaxlw = maxlinewidth; + time0 = time0a = getcurtime(); + if (regression) + srand(17); + if (thisindent + outbufcount > linewidth*3/2) { + i = 0; + maxdepth = 0; + readparens(&i, 0); + maxdp = maxdepth; + for (;;) { /* try some simple fixed methods first... */ + for (i = 1; i <= 20; i++) { + randombreaks = -1; + trybreakline(0, 0, thisindent, 0.0, 0, NULL); + } + randombreaks = -2; + trybreakline(0, 0, thisindent, 0.0, 0, NULL); + for (i = 0; i <= maxdp+1; i++) { + randombreaks = i+1; + trybreakline(0, 0, thisindent, 0.0, 0, NULL); + } + if (bestbadness == BIGBADNESS && maxlinewidth < 9999) { + maxlinewidth = 9999; /* no choice but to relax */ + numalts = 0; + } else + break; + } + time0a = getcurtime(); + } + randombreaks = 0; + trybreakline(0, 0, thisindent, 0.0, 0, NULL); + if (bestbadness == BIGBADNESS && maxlinewidth < 9999) { + numalts = 0; + maxlinewidth = 9999; /* no choice but to relax this */ + trybreakline(0, 0, thisindent, 0.0, 0, NULL); + } + time1 = getcurtime() - time0; + alts = numalts; + if (testinglinebreaker) { + if (savelimit < 0 && testinglinebreaker > 1) { + showbadlimit = bestbadness * (-savelimit); + numalts = 0; + bestnumalts = 0; + trybreakline(0, 0, thisindent, 0.0, 0, NULL); + } + fprintf(outf, "\n#if 1 /* accepted #%ld, badness = %g, tried %ld in %.3f sec */\n", bestnumalts, bestbadness, alts, time1/1000.0); + } + showbadlimit = savelimit; + maxlinewidth = savemaxlw; + flush_outbuf(bestnumbreaks, bestbreakpos, bestbreakindent, + bestnumedits, besteditpos, + besteditold, besteditnew); + if (((USETIME && time1 > 1000) || alts >= maxalts) && + !regression) { + sprintf(outbuf, "Line breaker spent %.1f", + (time1 + time0 - time0a) / 1000.0); + if (time0 != time0a) + sprintf(outbuf + strlen(outbuf), + "+%.2f", (time0a - time0) / 1000.0); + sprintf(outbuf + strlen(outbuf), + " seconds, %ld tries on line %d [251]", alts, outf_lnum); + note(outbuf); + } else if (verbose) { + fprintf(logf, "%s, %d/%d: Line breaker spent %ld tries\n", + infname, inf_lnum, outf_lnum, alts); + } + if (testinglinebreaker) + fprintf(outf, "#endif\n\n"); + } else { + if (testinglinebreaker < 2) + flush_outbuf(0, NULL, NULL, 0, NULL, NULL, NULL); + } + thisfutureindent = -1; + outbufpos = 0; + outbufcount = 0; + } else { + if (outbufpos == 0) { + if (ch == ' ' && !dontbreaklines) /* eat leading spaces */ + continue; + thisindent = applydelta(outindent, deltaindent); + deltaindent = 0; + } + if (outbufpos == outbufsize) { + outbufsize *= 2; + outbuf = REALLOC(outbuf, outbufsize, char); + } + outbuf[outbufpos++] = ch; + if (ch >= ' ') + outbufcount++; + } + } +} + + + +void out_n_spaces(n) +int n; +{ + while (--n >= 0) + output(" "); +} + + + +void out_spaces(spc, over, len, delta) +int spc, over, len, delta; +{ + int n; + + if (spc == -999) + spc = commentindent; + if (spc < 0) { /* right-justify */ + n = (-spc) - cur_column() - len; + if (n < minspcthresh) + n = minspacing; + else + over = 1000; + } else if (spc >= 2000) { /* tab to multiple */ + spc -= 2000; + n = (spc-1) - ((cur_column()+spc-1) % spc); + if (n < minspcthresh) + n += spc; + } else if (spc >= 1000) { /* absolute column */ + spc -= 1000; + n = spc - cur_column(); + if (n < minspcthresh) + n = minspacing; + } else /* relative spacing */ + n = spc; + if (line_start()) { + singleindent(n); + } else if (len > 0 && over != 1000 && cur_column() + n + len > linewidth) { + output("\n"); + out_spaces(over, 1000, len, 0); + singleindent(delta); + } else { + out_n_spaces(n); + } +} + + + + +void testlinebreaker(lev, fn) +int lev; +char *fn; +{ + char buf[256], *bp, *cp; + int first, indent; + + testinglinebreaker = lev; + if (!fn) + return; + inf = fopen(fn, "r"); + if (!inf) { + perror(fn); + exit(1); + } + sprintf(buf, "%s.br", fn); + outf = fopen(buf, "w"); + if (!outf) { + perror(buf); + exit(1); + } + setup_out(); + outindent = 4; + first = 1; + while (fgets(buf, 256, inf)) { + cp = buf + strlen(buf) - 2; + if (cp >= buf) { + bp = buf; + indent = 0; + while (isspace(*bp)) + if (*bp++ == '\t') + indent += 8; + else + indent++; + if (first) { + first = 0; + outindent = indent; + } + if (!(*cp == '{' || + *cp == ')' || + *cp == ';') || + (*cp == '/' && cp[-1] == '*')) { + cp[1] = '\001'; /* eat the \n */ + } else { + first = 1; + } + output(bp); + } + } + fclose(outf); + fclose(inf); +} + + + + + +void outsection(size) +int size; +{ + if (size > sectionsize) + sectionsize = size; +} + + + +int isembedcomment(cmt) +Strlist *cmt; +{ + int len = strlen(embedcomment); + return (cmt && len > 0 && !strncmp(cmt->s, embedcomment, len) && + (isspace(cmt->s[len]) || + (!cmt->s[len] && cmt->next && + (*cmt->next->s == '\002' || *cmt->next->s == '\003')))); +} + + +Strlist *outcomments(cmt) +Strlist *cmt; +{ + char *cp; + int saveindent = outindent, savesingle = deltaindent, theindent; + int saveeat = eatcomments; + int i = 0; + + if (!cmt) + return NULL; + if (!commentvisible(cmt)) { + setcommentkind(cmt, CMT_DONE); + return cmt->next; + } + if (*cmt->s == '\001') { + if (cmtdebug) + output(format_sd("[] [%s:%d]", + CMT_NAMES[getcommentkind(cmt)], + cmt->value & CMT_MASK)); + for (cp = cmt->s; *cp; cp++) { + output("\n"); + if (cmtdebug && cp[1]) + output("[]"); + } + setcommentkind(cmt, CMT_DONE); + return cmt->next; + } + dontbreaklines++; + if (isembedcomment(cmt)) { + embeddedcode = 1; + eatcomments = 0; + if (!strcmp(cmt->s, embedcomment)) { + cmt = cmt->next; + theindent = 0; + cp = cmt/*->next*/->s + 1; + while (*cp++ == ' ') + theindent++; + } else { + strcpy(cmt->s, cmt->s + strlen(embedcomment) + 1); + moreindent(deltaindent); + theindent = outindent; + deltaindent = 0; + } + } else { + moreindent(deltaindent); + if (cmt->s[0] == '\004') + outindent = 0; + theindent = outindent; + deltaindent = 0; + output("/*"); + } + cp = cmt->s; + for (;;) { + if (*cp == '\002') + cp++; + else if (*cp == '\003' || *cp == '\004') { + outindent = 0; + cp++; + } + if (embeddedcode) { + for (i = 0; *cp == ' ' && i < theindent; i++) + cp++; + i = *cp; + if (*cp == '#') + outindent = 0; + } + output(cp); + if (cmtdebug) + output(format_sd(" [%s:%d] ", + CMT_NAMES[getcommentkind(cmt)], + cmt->value & CMT_MASK)); + setcommentkind(cmt, CMT_DONE); + cmt = cmt->next; + if (!cmt || !commentvisible(cmt)) + break; + cp = cmt->s; + if (*cp != '\002' && *cp != '\003') + break; + output("\n"); + if (!embeddedcode) { + outindent = (*cp == '\002') ? theindent : 0; + deltaindent = 0; + } + } + if (embeddedcode) { + embeddedcode = 0; + if (i) { /* eat final blank line */ + output("\n"); + } + } else { + output("*/\n"); + } + outindent = saveindent; + deltaindent = savesingle; + dontbreaklines--; + eatcomments = saveeat; + return cmt; +} + + + +void outcomment(cmt) +Strlist *cmt; +{ + Strlist *savenext; + + if (cmt) { + savenext = cmt->next; + cmt->next = NULL; + outcomments(cmt); + cmt->next = savenext; + } +} + + + +void outtrailcomment(cmt, serial, indent) +Strlist *cmt; +int serial, indent; +{ + int savedelta = deltaindent; + +#if 0 + suppressnewline = 1; + output("\n"); + suppressnewline = 0; +#endif + cmt = findcomment(cmt, CMT_TRAIL, serial); + if (commentvisible(cmt)) { + out_spaces(indent, commentoverindent, commentlen(cmt), 0); + outcomment(cmt); + deltaindent = savedelta; + } else + output("\n"); +} + + + +void flushcomments(cmt, kind, serial) +Strlist **cmt; +int kind, serial; +{ + Strlist *cmt2, *cmt3; + int saveindent, savesingle, saveeat; + + if (!cmt) + cmt = &curcomments; + cmt2 = extractcomment(cmt, kind, serial); + saveindent = outindent; + savesingle = deltaindent; + moreindent(deltaindent); + deltaindent = 0; + saveeat = eatcomments; + if (eatcomments == 2) + eatcomments = 0; + cmt3 = cmt2; + while (cmt3) + cmt3 = outcomments(cmt3); + eatcomments = saveeat; + outindent = saveindent; + deltaindent = savesingle; + strlist_empty(&cmt2); +} + + + + + +char *rawCstring(fmt, s, len, special) +char *fmt; +register char *s; +int len, special; +{ + char buf[500]; + register char *cp; + register unsigned char ch; + + cp = buf; + while (--len >= 0) { + ch = *((unsigned char *) s); + s++; + if (ch == 0 && (len == 0 || !isdigit(*s))) { + *cp++ = '\\'; + *cp++ = '0'; + } else if (ch == '\n') { + *cp++ = '\\'; + *cp++ = 'n'; + } else if (ch == '\b') { + *cp++ = '\\'; + *cp++ = 'b'; + } else if (ch == '\t') { + *cp++ = '\\'; + *cp++ = 't'; + } else if (ch == '\f') { + *cp++ = '\\'; + *cp++ = 'f'; +#if 0 + } else if (ch == '\r') { + *cp++ = '\\'; + *cp++ = 'r'; +#endif + } else if (ch < ' ' || ch >= 127) { + *cp++ = '\\'; + *cp++ = '0' + (ch>>6); + *cp++ = '0' + ((ch>>3) & 7); + *cp++ = '0' + (ch & 7); + } else if (ch == special) { + switch (ch) { + case '%': + *cp++ = ch; + *cp++ = ch; + break; + } + } else { + if (ch == '"' || ch == '\\') + *cp++ = '\\'; + *cp++ = ch; + } + } + *cp = 0; + return format_s(fmt, buf); +} + + +char *makeCstring(s, len) +register char *s; +int len; +{ + return rawCstring("\"%s\"", s, len, 0); +} + + + +char *makeCchar(ich) +int ich; +{ + char buf[500]; + register char *cp; + register unsigned char ch = (ich & 0xff); + + if (ich < 0 || ich > 255 || (ich == 0 && !nullcharconst)) + return format_d("%d", ich); + cp = buf; + if (ch == 0) { + *cp++ = '\\'; + *cp++ = '0'; + } else if (ch == '\n') { + *cp++ = '\\'; + *cp++ = 'n'; + } else if (ch == '\b') { + *cp++ = '\\'; + *cp++ = 'b'; + } else if (ch == '\t') { + *cp++ = '\\'; + *cp++ = 't'; + } else if (ch == '\f') { + *cp++ = '\\'; + *cp++ = 'f'; +#if 0 + } else if (ch == '\r') { + *cp++ = '\\'; + *cp++ = 'r'; +#endif + } else if (ch < ' ' || ch >= 127) { + *cp++ = '\\'; + *cp++ = '0' + (ch>>6); + *cp++ = '0' + ((ch>>3) & 7); + *cp++ = '0' + (ch & 7); + } else { + if (ch == '\'' || ch == '\\') + *cp++ = '\\'; + *cp++ = ch; + } + *cp = 0; + return format_s("'%s'", buf); +} + + + + + + +/* End. */ + + diff --git a/MultiSource/Benchmarks/MallocBench/p2c/p2c.h b/MultiSource/Benchmarks/MallocBench/p2c/p2c.h new file mode 100644 index 00000000..d39e619c --- /dev/null +++ b/MultiSource/Benchmarks/MallocBench/p2c/p2c.h @@ -0,0 +1,511 @@ +#ifndef P2C_H +#define P2C_H + + +/* Header file for code generated by "p2c", the Pascal-to-C translator */ + +/* "p2c" Copyright (C) 1989, 1990, 1991 Free Software Foundation. + * By Dave Gillespie, daveg@csvax.cs.caltech.edu. Version 1.20. + * This file may be copied, modified, etc. in any way. It is not restricted + * by the licence agreement accompanying p2c itself. + */ + + +#include <stdio.h> + + + +/* If the following heuristic fails, compile -DBSD=0 for non-BSD systems, + or -DBSD=1 for BSD systems. */ + +#ifdef M_XENIX +# define BSD 0 +#endif + +#ifdef vms +# define BSD 0 +# ifndef __STDC__ +# define __STDC__ 1 +# endif +#endif + +#ifdef __TURBOC__ +# define MSDOS 1 +#endif + +#ifdef MSDOS +# define BSD 0 +#endif + +#ifdef FILE /* a #define in BSD, a typedef in SYSV (hp-ux, at least) */ +# ifndef BSD /* (a convenient, but horrible kludge!) */ +# define BSD 1 +# endif +#endif + +#ifdef BSD +# if !BSD +# undef BSD +# endif +#endif + + +#if (defined(__STDC__) && !defined(M_XENIX)) || defined(__TURBOC__) +/*# include <stddef.h>*/ +# include <stdlib.h> +# define HAS_STDLIB +# if defined(vms) || defined(__TURBOC__) +# define __ID__(a)a +# endif +#else +# ifndef BSD +# ifndef __TURBOC__ +# include <memory.h> +# endif +# endif +# ifdef hpux +# ifdef _INCLUDE__STDC__ +# include <stddef.h> +# include <stdlib.h> +# endif +# endif +# include <sys/types.h> +# if !defined(MSDOS) || defined(__TURBOC__) +# define __ID__(a)a +# endif +#endif + +#ifdef __ID__ +# define __CAT__(a,b)__ID__(a)b +#else +# define __CAT__(a,b)a##b +#endif + + +#ifdef BSD +# include <strings.h> +# define memcpy(a,b,n) (bcopy(b,a,n),a) +# define memcmp(a,b,n) bcmp(a,b,n) +# define strchr(s,c) index(s,c) +# define strrchr(s,c) rindex(s,c) +#else +# include <string.h> +#endif + +#include <ctype.h> +#include <math.h> +#include <setjmp.h> +#include <assert.h> + + +#ifndef NO_LACK +#ifdef vms + +#define LACK_LABS +#define LACK_MEMMOVE +#define LACK_MEMCPY + +#else + +#define LACK_LABS /* Undefine these if your library has these */ +#define LACK_MEMMOVE + +#endif +#endif + + +typedef struct __p2c_jmp_buf { + struct __p2c_jmp_buf *next; + jmp_buf jbuf; +} __p2c_jmp_buf; + + +/* Warning: The following will not work if setjmp is used simultaneously. + This also violates the ANSI restriction about using vars after longjmp, + but a typical implementation of longjmp will get it right anyway. */ + +#ifndef FAKE_TRY +# define TRY(x) do { __p2c_jmp_buf __try_jb; \ + __try_jb.next = __top_jb; \ + if (!setjmp((__top_jb = &__try_jb)->jbuf)) { +# define RECOVER(x) __top_jb = __try_jb.next; } else { +# define RECOVER2(x,L) __top_jb = __try_jb.next; } else { \ + if (0) { L: __top_jb = __try_jb.next; } +# define ENDTRY(x) } } while (0) +#else +# define TRY(x) if (1) { +# define RECOVER(x) } else do { +# define RECOVER2(x,L) } else do { L: ; +# define ENDTRY(x) } while (0) +#endif + + + +#ifdef M_XENIX /* avoid compiler bug */ +# define SHORT_MAX (32767) +# define SHORT_MIN (-32768) +#endif + + +/* The following definitions work only on twos-complement machines */ +#ifndef SHORT_MAX +# define SHORT_MAX ((short)(((unsigned short) -1) >> 1)) +# define SHORT_MIN (~SHORT_MAX) +#endif + +#ifndef INT_MAX +# define INT_MAX ((int)(((unsigned int) -1) >> 1)) +# define INT_MIN (~INT_MAX) +#endif + +#ifndef LONG_MAX +# define LONG_MAX ((long)(((unsigned long) -1) >> 1)) +# define LONG_MIN (~LONG_MAX) +#endif + +#ifndef SEEK_SET +# define SEEK_SET 0 +# define SEEK_CUR 1 +# define SEEK_END 2 +#endif + +#ifndef EXIT_SUCCESS +# ifdef vms +# define EXIT_SUCCESS 1 +# define EXIT_FAILURE (02000000000L) +# else +# define EXIT_SUCCESS 0 +# define EXIT_FAILURE 1 +# endif +#endif + + +#define SETBITS 32 + + +#if defined(__STDC__) || defined(__TURBOC__) +# if !defined(vms) && !defined(M_LINT) +# define Signed signed +# else +# define Signed +# endif +# define Void void /* Void f() = procedure */ +# ifndef Const +# define Const const +# endif +# ifndef Volatile +# define Volatile volatile +# endif +# ifdef M_LINT +# define PP(x) () +# define PV() () +typedef char *Anyptr; +# else +# define PP(x) x /* function prototype */ +# define PV() (void) /* null function prototype */ +typedef void *Anyptr; +# endif +#else +# define Signed +# define Void void +# ifndef Const +# define Const +# endif +# ifndef Volatile +# define Volatile +# endif +# define PP(x) () +# define PV() () +typedef char *Anyptr; +#endif + +#ifdef __GNUC__ +# define Inline inline +#else +# define Inline +#endif + +#define Register register /* Register variables */ +#define Char char /* Characters (not bytes) */ + +#ifndef Static +# define Static static /* Private global funcs and vars */ +#endif + +#ifndef Local +# define Local static /* Nested functions */ +#endif + +typedef Signed char schar; +typedef unsigned char uchar; +typedef unsigned char boolean; + +#ifndef true +# define true 1 +# define false 0 +#endif + +#ifndef TRUE +# define TRUE 1 +# define FALSE 0 +#endif + + +typedef struct { + Anyptr proc, link; +} _PROCEDURE; + +#ifndef _FNSIZE +# define _FNSIZE 120 +#endif + + +extern Void PASCAL_MAIN PP( (int, Char **) ); +extern Char **P_argv; +extern int P_argc; +extern short P_escapecode; +extern int P_ioresult; +extern __p2c_jmp_buf *__top_jb; + + +#ifdef P2C_H_PROTO /* if you have Ansi C but non-prototyped header files */ +extern Char *strcat PP( (Char *, Const Char *) ); +extern Char *strchr PP( (Const Char *, int) ); +extern int strcmp PP( (Const Char *, Const Char *) ); +extern Char *strcpy PP( (Char *, Const Char *) ); +extern size_t strlen PP( (Const Char *) ); +extern Char *strncat PP( (Char *, Const Char *, size_t) ); +extern int strncmp PP( (Const Char *, Const Char *, size_t) ); +extern Char *strncpy PP( (Char *, Const Char *, size_t) ); +extern Char *strrchr PP( (Const Char *, int) ); + +extern Anyptr memchr PP( (Const Anyptr, int, size_t) ); +extern Anyptr memmove PP( (Anyptr, Const Anyptr, size_t) ); +extern Anyptr memset PP( (Anyptr, int, size_t) ); +#ifndef memcpy +extern Anyptr memcpy PP( (Anyptr, Const Anyptr, size_t) ); +extern int memcmp PP( (Const Anyptr, Const Anyptr, size_t) ); +#endif + +extern int atoi PP( (Const Char *) ); +extern double atof PP( (Const Char *) ); +extern long atol PP( (Const Char *) ); +extern double strtod PP( (Const Char *, Char **) ); +extern long strtol PP( (Const Char *, Char **, int) ); +#endif /*P2C_H_PROTO*/ + +#ifndef HAS_STDLIB +extern Anyptr malloc PP( (size_t) ); +extern Void free PP( (Anyptr) ); +#endif + +extern int _OutMem PV(); +extern int _CaseCheck PV(); +extern int _NilCheck PV(); +extern int _Escape PP( (int) ); +extern int _EscIO PP( (int) ); + +extern long ipow PP( (long, long) ); +extern Char *strsub PP( (Char *, Char *, int, int) ); +extern Char *strltrim PP( (Char *) ); +extern Char *strrtrim PP( (Char *) ); +extern Char *strrpt PP( (Char *, Char *, int) ); +extern Char *strpad PP( (Char *, Char *, int, int) ); +extern int strpos2 PP( (Char *, Char *, int) ); +extern long memavail PV(); +extern int P_peek PP( (FILE *) ); +extern int P_eof PP( (FILE *) ); +extern int P_eoln PP( (FILE *) ); +extern Void P_readpaoc PP( (FILE *, Char *, int) ); +extern Void P_readlnpaoc PP( (FILE *, Char *, int) ); +extern long P_maxpos PP( (FILE *) ); +extern Char *P_trimname PP( (Char *, int) ); +extern long *P_setunion PP( (long *, long *, long *) ); +extern long *P_setint PP( (long *, long *, long *) ); +extern long *P_setdiff PP( (long *, long *, long *) ); +extern long *P_setxor PP( (long *, long *, long *) ); +extern int P_inset PP( (unsigned, long *) ); +extern int P_setequal PP( (long *, long *) ); +extern int P_subset PP( (long *, long *) ); +extern long *P_addset PP( (long *, unsigned) ); +extern long *P_addsetr PP( (long *, unsigned, unsigned) ); +extern long *P_remset PP( (long *, unsigned) ); +extern long *P_setcpy PP( (long *, long *) ); +extern long *P_expset PP( (long *, long) ); +extern long P_packset PP( (long *) ); +extern int P_getcmdline PP( (int, int, Char *) ); +extern Void TimeStamp PP( (int *, int *, int *, + int *, int *, int *) ); +extern Void P_sun_argv PP( (char *, int, int) ); + + +/* I/O error handling */ +#define _CHKIO(cond,ior,val,def) ((cond) ? P_ioresult=0,(val) \ + : P_ioresult=(ior),(def)) +#define _SETIO(cond,ior) (P_ioresult = (cond) ? 0 : (ior)) + +/* Following defines are suitable for the HP Pascal operating system */ +#define FileNotFound 10 +#define FileNotOpen 13 +#define FileWriteError 38 +#define BadInputFormat 14 +#define EndOfFile 30 + +#define FILENOTFOUND 10 +#define FILENOTOPEN 13 +#define FILEWRITEERROR 38 +#define BADINPUTFORMAT 14 +#define ENDOFFILE 30 + +/* Creating temporary files */ +#if (defined(BSD) || defined(NO_TMPFILE)) && !defined(HAVE_TMPFILE) +# define tmpfile() (fopen(tmpnam(NULL), "w+")) +#endif + +/* File buffers */ +#define FILEBUF(f,sc,type) sc int __CAT__(f,_BFLAGS); \ + sc type __CAT__(f,_BUFFER) +#define FILEBUFNC(f,type) int __CAT__(f,_BFLAGS); \ + type __CAT__(f,_BUFFER) + +#define RESETBUF(f,type) (__CAT__(f,_BFLAGS) = 1) +#define SETUPBUF(f,type) (__CAT__(f,_BFLAGS) = 0) + +#define GETFBUF(f,type) (*((__CAT__(f,_BFLAGS) == 1 && \ + ((__CAT__(f,_BFLAGS) = 2), \ + fread(&__CAT__(f,_BUFFER), \ + sizeof(type),1,(f)))),\ + &__CAT__(f,_BUFFER))) +#define AGETFBUF(f,type) ((__CAT__(f,_BFLAGS) == 1 && \ + ((__CAT__(f,_BFLAGS) = 2), \ + fread(__CAT__(f,_BUFFER), \ + sizeof(type),1,(f)))),\ + __CAT__(f,_BUFFER)) + +#define PUTFBUF(f,type,v) (GETFBUF(f,type) = (v)) +#define CPUTFBUF(f,v) (PUTFBUF(f,char,v)) +#define APUTFBUF(f,type,v) (memcpy(AGETFBUF(f,type), (v), \ + sizeof(__CAT__(f,_BUFFER)))) + +#define GET(f,type) (__CAT__(f,_BFLAGS) == 1 ? \ + fread(&__CAT__(f,_BUFFER),sizeof(type),1,(f)) : \ + (__CAT__(f,_BFLAGS) = 1)) + +#define PUT(f,type) (fwrite(&__CAT__(f,_BUFFER),sizeof(type),1,(f)), \ + (__CAT__(f,_BFLAGS) = 0)) +#define CPUT(f) (PUT(f,char)) + +#define BUFEOF(f) (__CAT__(f,_BFLAGS) != 2 && P_eof(f)) +#define BUFFPOS(f) (ftell(f) - (__CAT__(f,_BFLAGS) == 2)) + +typedef struct { + FILE *f; + FILEBUFNC(f,Char); + Char name[_FNSIZE]; +} _TEXT; + +/* Memory allocation */ +#ifdef __GCC__ +# define Malloc(n) (malloc(n) ?: (Anyptr)_OutMem()) +#else +extern Anyptr __MallocTemp__; +# define Malloc(n) ((__MallocTemp__ = malloc(n)) ? __MallocTemp__ : (Anyptr)_OutMem()) +#endif +#define FreeR(p) (free((Anyptr)(p))) /* used if arg is an rvalue */ +#define Free(p) (free((Anyptr)(p)), (p)=NULL) + +/* sign extension */ +#define SEXT(x,n) ((x) | -(((x) & (1L<<((n)-1))) << 1)) + +/* packed arrays */ /* BEWARE: these are untested! */ +#define P_getbits_UB(a,i,n,L) ((int)((a)[(i)>>(L)-(n)] >> \ + (((~(i))&((1<<(L)-(n))-1)) << (n)) & \ + (1<<(1<<(n)))-1)) + +#define P_getbits_SB(a,i,n,L) ((int)((a)[(i)>>(L)-(n)] << \ + (16 - ((((~(i))&((1<<(L)-(n))-1))+1) <<\ + (n)) >> (16-(1<<(n)))))) + +#define P_putbits_UB(a,i,x,n,L) ((a)[(i)>>(L)-(n)] |= \ + (x) << (((~(i))&((1<<(L)-(n))-1)) << (n))) + +#define P_putbits_SB(a,i,x,n,L) ((a)[(i)>>(L)-(n)] |= \ + ((x) & (1<<(1<<(n)))-1) << \ + (((~(i))&((1<<(L)-(n))-1)) << (n))) + +#define P_clrbits_B(a,i,n,L) ((a)[(i)>>(L)-(n)] &= \ + ~( ((1<<(1<<(n)))-1) << \ + (((~(i))&((1<<(L)-(n))-1)) << (n))) ) + +/* small packed arrays */ +#define P_getbits_US(v,i,n) ((int)((v) >> ((i)<<(n)) & (1<<(1<<(n)))-1)) +#define P_getbits_SS(v,i,n) ((int)((long)(v) << (SETBITS - (((i)+1) << (n))) >> (SETBITS-(1<<(n))))) +#define P_putbits_US(v,i,x,n) ((v) |= (x) << ((i) << (n))) +#define P_putbits_SS(v,i,x,n) ((v) |= ((x) & (1<<(1<<(n)))-1) << ((i)<<(n))) +#define P_clrbits_S(v,i,n) ((v) &= ~( ((1<<(1<<(n)))-1) << ((i)<<(n)) )) + +#define P_max(a,b) ((a) > (b) ? (a) : (b)) +#define P_min(a,b) ((a) < (b) ? (a) : (b)) + + +/* Fix ANSI-isms */ + +#ifdef LACK_LABS +# ifndef labs +# define labs my_labs + extern long my_labs PP( (long) ); +# endif +#endif + +#ifdef LACK_MEMMOVE +# ifndef memmove +# define memmove my_memmove + extern Anyptr my_memmove PP( (Anyptr, Const Anyptr, size_t) ); +# endif +#endif + +#ifdef LACK_MEMCPY +# ifndef memcpy +# define memcpy my_memcpy + extern Anyptr my_memcpy PP( (Anyptr, Const Anyptr, size_t) ); +# endif +# ifndef memcmp +# define memcmp my_memcmp + extern int my_memcmp PP( (Const Anyptr, Const Anyptr, size_t) ); +# endif +# ifndef memset +# define memset my_memset + extern Anyptr my_memset PP( (Anyptr, int, size_t) ); +# endif +#endif + +/* Fix toupper/tolower on Suns and other stupid BSD systems */ +#ifdef toupper +# undef toupper +# undef tolower +# define toupper(c) my_toupper(c) +# define tolower(c) my_tolower(c) +#endif + +#ifndef _toupper +# if 'A' == 65 && 'a' == 97 +# define _toupper(c) ((c)-'a'+'A') +# define _tolower(c) ((c)-'A'+'a') +# else +# ifdef toupper +# undef toupper /* hope these are shadowing real functions, */ +# undef tolower /* because my_toupper calls _toupper! */ +# endif +# define _toupper(c) toupper(c) +# define _tolower(c) tolower(c) +# endif +#endif + + +#endif /* P2C_H */ + + + +/* End. */ + + diff --git a/MultiSource/Benchmarks/MallocBench/p2c/parse.c b/MultiSource/Benchmarks/MallocBench/p2c/parse.c new file mode 100644 index 00000000..1d0be409 --- /dev/null +++ b/MultiSource/Benchmarks/MallocBench/p2c/parse.c @@ -0,0 +1,4380 @@ +/* "p2c", a Pascal to C translator. + Copyright (C) 1989, 1990, 1991 Free Software Foundation. + Author's address: daveg@csvax.caltech.edu; 256-80 Caltech/Pasadena CA 91125. + +This program is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation (any version). + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; see the file COPYING. If not, write to +the Free Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ + + + +#define PROTO_PARSE_C +#include "trans.h" + + + +Static short candeclare; +Static int trycount; +Static Strlist *includedfiles; +Static char echo_first; +Static int echo_pos; + + + +void setup_parse() +{ + candeclare = 0; + trycount = 0; + includedfiles = NULL; + echo_first = 1; + echo_pos = 0; + fixexpr_tryblock = 0; +} + + + +void echobreak() +{ + if (echo_pos > 0) { + printf("\n"); + echo_pos = 0; + echo_first = 0; + } +} + + +void echoword(name, comma) +char *name; +int comma; +{ + FILE *f = (outf == stdout) ? stderr : stdout; + + if (quietmode || showprogress) + return; + if (!echo_first) { + if (comma) { + fprintf(f, ","); + echo_pos++; + } + if (echo_pos + strlen(name) > 77) { + fprintf(f, "\n"); + echo_pos = 0; + } else { + fprintf(f, " "); + echo_pos++; + } + } + echo_first = 0; + fprintf(f, "%s", name); + echo_pos += strlen(name); + fflush(f); +} + + + +void echoprocname(mp) +Meaning *mp; +{ + echoword(mp->name, 1); +} + + + + + +Static void forward_decl(func, isextern) +Meaning *func; +int isextern; +{ + if (func->wasdeclared) + return; + if (isextern && func->constdefn && !checkvarmac(func)) + return; + if (isextern) { + output("extern "); + } else if (func->ctx->kind == MK_FUNCTION) { + if (useAnyptrMacros) + output("Local "); + else + output("static "); + } else if ((use_static != 0 && !useAnyptrMacros) || + (findsymbol(func->name)->flags & NEEDSTATIC)) { + output("static "); + } else if (useAnyptrMacros) { + output("Static "); + } + if (func->type->basetype != tp_void || ansiC != 0) { + outbasetype(func->type, ODECL_FORWARD); + output(" "); + } + outdeclarator(func->type, func->name, ODECL_FORWARD); + output(";\n"); + func->wasdeclared = 1; +} + + + + +/* Check if calling a parent procedure, whose body must */ +/* be declared forward */ + +void need_forward_decl(func) +Meaning *func; +{ + Meaning *mp; + + if (func->wasdeclared) + return; + for (mp = curctx->ctx; mp; mp = mp->ctx) { + if (mp == func) { + if (func->ctx->kind == MK_FUNCTION) + func->isforward = 1; + else + forward_decl(func, 0); + return; + } + } +} + + + + +void free_stmt(sp) +register Stmt *sp; +{ + if (sp) { + free_stmt(sp->stm1); + free_stmt(sp->stm2); + free_stmt(sp->next); + freeexpr(sp->exp1); + freeexpr(sp->exp2); + freeexpr(sp->exp3); + FREE(sp); + } +} + + + + +Stmt *makestmt(kind) +enum stmtkind kind; +{ + Stmt *sp; + + sp = ALLOC(1, Stmt, stmts); + sp->kind = kind; + sp->next = NULL; + sp->stm1 = NULL; + sp->stm2 = NULL; + sp->exp1 = NULL; + sp->exp2 = NULL; + sp->exp3 = NULL; + sp->serial = curserial = ++serialcount; + return sp; +} + + + +Stmt *makestmt_call(call) +Expr *call; +{ + Stmt *sp = makestmt(SK_ASSIGN); + sp->exp1 = call; + return sp; +} + + + +Stmt *makestmt_assign(lhs, rhs) +Expr *lhs, *rhs; +{ + Stmt *sp = makestmt(SK_ASSIGN); + sp->exp1 = makeexpr_assign(lhs, rhs); + return sp; +} + + + +Stmt *makestmt_if(cond, thn, els) +Expr *cond; +Stmt *thn, *els; +{ + Stmt *sp = makestmt(SK_IF); + sp->exp1 = cond; + sp->stm1 = thn; + sp->stm2 = els; + return sp; +} + + + +Stmt *makestmt_seq(s1, s2) +Stmt *s1, *s2; +{ + Stmt *s1a; + + if (!s1) + return s2; + if (!s2) + return s1; + for (s1a = s1; s1a->next; s1a = s1a->next) ; + s1a->next = s2; + return s1; +} + + + +Stmt *copystmt(sp) +Stmt *sp; +{ + Stmt *sp2; + + if (sp) { + sp2 = makestmt(sp->kind); + sp2->stm1 = copystmt(sp->stm1); + sp2->stm2 = copystmt(sp->stm2); + sp2->exp1 = copyexpr(sp->exp1); + sp2->exp2 = copyexpr(sp->exp2); + sp2->exp3 = copyexpr(sp->exp3); + return sp2; + } else + return NULL; +} + + + +void nukestmt(sp) +Stmt *sp; +{ + if (sp) { + sp->kind = SK_ASSIGN; + sp->exp1 = makeexpr_long(0); + } +} + + + +void splicestmt(sp, spnew) +Stmt *sp, *spnew; +{ + Stmt *snext; + + if (spnew) { + snext = sp->next; + *sp = *spnew; + while (sp->next) + sp = sp->next; + sp->next = snext; + } else + nukestmt(sp); +} + + + +int stmtcount(sp) +Stmt *sp; +{ + int i = 0; + + while (sp) { + i += 1 + stmtcount(sp->stm1) + stmtcount(sp->stm2); + sp = sp->next; + } + return i; +} + + + + + +Stmt *close_files_to_ctx(ctx) +Meaning *ctx; +{ + Meaning *ctx2, *mp; + Stmt *splist = NULL, *sp; + + ctx2 = curctx; + while (ctx2 && ctx2 != ctx && ctx2->kind == MK_FUNCTION) { + for (mp = ctx2->cbase; mp; mp = mp->cnext) { + if (mp->kind == MK_VAR && + isfiletype(mp->type, -1) && !mp->istemporary) { + var_reference(mp); + sp = makestmt_if(makeexpr_rel(EK_NE, + filebasename(makeexpr_var(mp)), + makeexpr_nil()), + makestmt_call( + makeexpr_bicall_1("fclose", tp_void, + filebasename(makeexpr_var(mp)))), + NULL); + splist = makestmt_seq(splist, sp); + } + } + ctx2 = ctx2->ctx; + } + return splist; +} + + + + +int simplewith(ex) +Expr *ex; +{ + switch (ex->kind) { + case EK_VAR: + case EK_CONST: + return 1; + case EK_DOT: + return simplewith(ex->args[0]); + default: + return 0; + } +} + + +int simplefor(sp, ex) +Stmt *sp; +Expr *ex; +{ + return (exprspeed(sp->exp2) <= 3 && + !checkexprchanged(sp->stm1, sp->exp2) && + !exproccurs(sp->exp2, ex)); +} + + + +int tryfuncmacro(exp, mp) +Expr **exp; +Meaning *mp; +{ + char *name; + Strlist *lp; + Expr *ex = *exp, *ex2; + + ex2 = (mp) ? mp->constdefn : NULL; + if (!ex2) { + if (ex->kind == EK_BICALL || ex->kind == EK_NAME) + name = ex->val.s; + else if (ex->kind == EK_FUNCTION) + name = ((Meaning *)ex->val.i)->name; + else + return 0; + lp = strlist_cifind(funcmacros, name); + ex2 = (lp) ? (Expr *)lp->value : NULL; + } + if (ex2) { + *exp = replacemacargs(copyexpr(ex2), ex); + freeexpr(ex); + return 1; + } + return 0; +} + + + + + +#define addstmt(kind) \ + *spp = sp = makestmt(kind), \ + spp = &(sp->next) + +#define newstmt(kind) \ + addstmt(kind), \ + steal_comments(firstserial, sp->serial, sflags & SF_FIRST), \ + sflags &= ~SF_FIRST + + + +#define SF_FUNC 0x1 +#define SF_SAVESER 0x2 +#define SF_FIRST 0x4 +#define SF_IF 0x8 + +Static Stmt *p_stmt(slist, sflags) +Stmt *slist; +int sflags; +{ + Stmt *sbase = NULL, **spp = &sbase, **spp2, **spp3, **savespp; + Stmt *defsp, **defsphook; + register Stmt *sp; + Stmt *sp2; + long li1, li2, firstserial = 0, saveserial = 0, saveserial2; + int i, forfixed, offset, line1, line2, toobig, isunsafe; + Token savetok; + char *name; + Expr *ep, *ep2, *ep3, *forstep, *range, *swexpr, *trueswexpr; + Type *tp; + Meaning *mp, *tvar, *tempmark; + Symbol *sym; + enum exprkind ekind; + Stmt *(*prochandler)(); + Strlist *cmt; + + tempmark = markstmttemps(); +again: + while (findlabelsym()) { + newstmt(SK_LABEL); + sp->exp1 = makeexpr_name(format_s(name_LABEL, curtokmeaning->name), tp_integer); + gettok(); + wneedtok(TOK_COLON); + } + firstserial = curserial; + checkkeyword(TOK_TRY); + checkkeyword(TOK_INLINE); + checkkeyword(TOK_LOOP); + checkkeyword(TOK_RETURN); + if (modula2) { + if (sflags & SF_SAVESER) + goto stmtSeq; + } + switch (curtok) { + + case TOK_BEGIN: + stmtSeq: + if (sflags & (SF_FUNC|SF_SAVESER)) { + saveserial = curserial; + cmt = grabcomment(CMT_ONBEGIN); + if (sflags & SF_FUNC) + cmt = fixbeginendcomment(cmt); + strlist_mix(&curcomments, cmt); + } + i = sflags & SF_FIRST; + do { + if (modula2) { + if (curtok == TOK_BEGIN || curtok == TOK_SEMI) + gettok(); + checkkeyword(TOK_ELSIF); + if (curtok == TOK_ELSE || curtok == TOK_ELSIF) + break; + } else + gettok(); + *spp = p_stmt(sbase, i); + i = 0; + while (*spp) + spp = &((*spp)->next); + } while (curtok == TOK_SEMI); + if (sflags & (SF_FUNC|SF_SAVESER)) { + cmt = grabcomment(CMT_ONEND); + changecomments(cmt, -1, -1, -1, saveserial); + if (sflags & SF_FUNC) + cmt = fixbeginendcomment(cmt); + strlist_mix(&curcomments, cmt); + if (sflags & SF_FUNC) + changecomments(curcomments, -1, saveserial, -1, 10000); + curserial = saveserial; + } + checkkeyword(TOK_ELSIF); + if (modula2 && (sflags & SF_IF)) { + break; + } + if (curtok == TOK_VBAR) + break; + if (!wneedtok(TOK_END)) + skippasttoken(TOK_END); + break; + + case TOK_CASE: + gettok(); + swexpr = trueswexpr = p_ord_expr(); + if (nosideeffects(swexpr, 1)) { + tvar = NULL; + } else { + tvar = makestmttempvar(swexpr->val.type, name_TEMP); + swexpr = makeexpr_var(tvar); + } + savespp = spp; + newstmt(SK_CASE); + saveserial2 = curserial; + sp->exp1 = trueswexpr; + spp2 = &sp->stm1; + tp = swexpr->val.type; + defsp = NULL; + defsphook = &defsp; + if (!wneedtok(TOK_OF)) { + skippasttoken(TOK_END); + break; + } + i = 1; + while (curtok == TOK_VBAR) + gettok(); + checkkeyword(TOK_OTHERWISE); + while (curtok != TOK_END && curtok != TOK_OTHERWISE && curtok != TOK_ELSE) { + spp3 = spp2; + saveserial = curserial; + *spp2 = sp = makestmt(SK_CASELABEL); + steal_comments(saveserial, sp->serial, i); + spp2 = &sp->next; + range = NULL; + toobig = 0; + for (;;) { + ep = gentle_cast(p_expr(tp), tp); + if (curtok == TOK_DOTS) { + li1 = ord_value(eval_expr(ep)); + gettok(); + ep2 = gentle_cast(p_expr(tp), tp); + li2 = ord_value(eval_expr(ep2)); + range = makeexpr_or(range, + makeexpr_range(copyexpr(swexpr), + ep, ep2, 1)); + if (li2 - li1 >= caselimit) + toobig = 1; + if (!toobig) { + for (;;) { + sp->exp1 = makeexpr_val(make_ord(tp, li1)); + if (li1 >= li2) break; + li1++; + serialcount--; /* make it reuse the count */ + sp->stm1 = makestmt(SK_CASELABEL); + sp = sp->stm1; + } + } + } else { + sp->exp1 = copyexpr(ep); + range = makeexpr_or(range, + makeexpr_rel(EK_EQ, + copyexpr(swexpr), + ep)); + } + if (curtok == TOK_COMMA) { + gettok(); + serialcount--; /* make it reuse the count */ + sp->stm1 = makestmt(SK_CASELABEL); + sp = sp->stm1; + } else + break; + } + wneedtok(TOK_COLON); + if (toobig) { + free_stmt(*spp3); + spp2 = spp3; + *defsphook = makestmt_if(range, p_stmt(NULL, SF_SAVESER), + NULL); + if (defsphook != &defsp && elseif != 0) + (*defsphook)->exp2 = makeexpr_long(1); + defsphook = &((*defsphook)->stm2); + } else { + freeexpr(range); + sp->stm1 = p_stmt(NULL, SF_SAVESER); + } + i = 0; + checkkeyword(TOK_OTHERWISE); + if (curtok != TOK_END && curtok != TOK_OTHERWISE && curtok != TOK_ELSE) { + if (curtok == TOK_VBAR) { + while (curtok == TOK_VBAR) + gettok(); + } else + wneedtok(TOK_SEMI); + checkkeyword(TOK_OTHERWISE); + } + } + if (defsp) { + *spp2 = defsp; + spp2 = defsphook; + if (tvar) { + sp = makestmt_assign(makeexpr_var(tvar), trueswexpr); + sp->next = *savespp; + *savespp = sp; + sp->next->exp1 = swexpr; + } + } else { + if (tvar) { + canceltempvar(tvar); + freeexpr(swexpr); + } + } + if (curtok == TOK_OTHERWISE || curtok == TOK_ELSE) { + gettok(); + while (curtok == TOK_SEMI) + gettok(); +/* changecomments(curcomments, CMT_TRAIL, curserial, + CMT_POST, -1); */ + i = SF_FIRST; + while (curtok != TOK_END) { + *spp2 = p_stmt(NULL, i); + while (*spp2) + spp2 = &((*spp2)->next); + i = 0; + if (curtok != TOK_SEMI) + break; + gettok(); + } + if (!wexpecttok(TOK_END)) + skiptotoken(TOK_END); + } else if (casecheck == 1 || (casecheck == 2 && range_flag)) { + *spp2 = makestmt(SK_CASECHECK); + } + curserial = saveserial2; + strlist_mix(&curcomments, grabcomment(CMT_ONEND)); + gettok(); + break; + + case TOK_FOR: + forfixed = fixedflag; + gettok(); + newstmt(SK_FOR); + ep = p_expr(tp_integer); + if (!wneedtok(TOK_ASSIGN)) { + skippasttoken(TOK_DO); + break; + } + ep2 = makeexpr_charcast(p_expr(ep->val.type)); + if (curtok != TOK_DOWNTO) { + if (!wexpecttok(TOK_TO)) { + skippasttoken(TOK_DO); + break; + } + } + savetok = curtok; + gettok(); + sp->exp2 = makeexpr_charcast(p_expr(ep->val.type)); + checkkeyword(TOK_BY); + if (curtok == TOK_BY) { + gettok(); + forstep = p_expr(tp_integer); + i = possiblesigns(forstep); + if ((i & 5) == 5) { + if (expr_is_neg(forstep)) { + ekind = EK_GE; + note("Assuming FOR loop step is negative [252]"); + } else { + ekind = EK_LE; + note("Assuming FOR loop step is positive [252]"); + } + } else { + if (!(i & 1)) + ekind = EK_LE; + else + ekind = EK_GE; + } + } else { + if (savetok == TOK_DOWNTO) { + ekind = EK_GE; + forstep = makeexpr_long(-1); + } else { + ekind = EK_LE; + forstep = makeexpr_long(1); + } + } + tvar = NULL; + swexpr = NULL; + if (ep->kind == EK_VAR) { + tp = findbasetype(ep->val.type, ODECL_NOPRES); + if ((tp == tp_char || tp == tp_schar || tp == tp_uchar || + tp == tp_abyte || tp == tp_sbyte || tp == tp_ubyte || + tp == tp_boolean) && + ((checkconst(sp->exp2, 0) && + tp != tp_sbyte && tp != tp_schar) || + checkconst(sp->exp2, -128) || + (checkconst(sp->exp2, 127) && + tp != tp_ubyte && tp != tp_uchar) || + checkconst(sp->exp2, 255) || + (tp == tp_char && + (useAnyptrMacros == 1 || unsignedchar != 1) && + isliteralconst(sp->exp2, NULL) == 2 && + sp->exp2->val.i >= 128))) { + swexpr = ep; + tvar = makestmttempvar(tp_sshort, name_TEMP); + ep = makeexpr_var(tvar); + } else if (((tp == tp_sshort && + (checkconst(sp->exp2, -32768) || + checkconst(sp->exp2, 32767))) || + (tp == tp_ushort && + (checkconst(sp->exp2, 0) || + checkconst(sp->exp2, 65535))))) { + swexpr = ep; + tvar = makestmttempvar(tp_integer, name_TEMP); + ep = makeexpr_var(tvar); + } else if (tp == tp_integer && + (checkconst(sp->exp2, LONG_MAX) || + (sp->exp2->kind == EK_VAR && + sp->exp2->val.i == (long)mp_maxint))) { + swexpr = ep; + tvar = makestmttempvar(tp_unsigned, name_TEMP); + ep = makeexpr_var(tvar); + } + } + sp->exp3 = makeexpr_assign(copyexpr(ep), + makeexpr_inc(copyexpr(ep), + copyexpr(forstep))); + wneedtok(TOK_DO); + forfixed = (fixedflag != forfixed); + mp = makestmttempvar(ep->val.type, name_FOR); + sp->stm1 = p_stmt(NULL, SF_SAVESER); + if (tvar) { + if (checkexprchanged(sp->stm1, swexpr)) + note(format_s("Rewritten FOR loop won't work if it meddles with %s [253]", + ((Meaning *)swexpr->val.i)->name)); + sp->stm1 = makestmt_seq(makestmt_assign(swexpr, makeexpr_var(tvar)), + sp->stm1); + } else if (offsetforloops && ep->kind == EK_VAR) { + offset = checkvaroffset(sp->stm1, (Meaning *)ep->val.i); + if (offset != 0) { + ep3 = makeexpr_inc(copyexpr(ep), makeexpr_long(-offset)); + replaceexpr(sp->stm1, ep, ep3); + freeexpr(ep3); + ep2 = makeexpr_plus(ep2, makeexpr_long(offset)); + sp->exp2 = makeexpr_inc(sp->exp2, makeexpr_long(offset)); + } + } + if (!exprsame(ep, ep2, 1)) + sp->exp1 = makeexpr_assign(copyexpr(ep), copyexpr(ep2)); + isunsafe = ((!nodependencies(ep2, 2) && + !nosideeffects(sp->exp2, 1)) || + (!nodependencies(sp->exp2, 2) && + !nosideeffects(ep2, 1))); + if (forfixed || (simplefor(sp, ep) && !isunsafe)) { + canceltempvar(mp); + sp->exp2 = makeexpr_rel(ekind, ep, sp->exp2); + } else { + ep3 = makeexpr_neg(copyexpr(forstep)); + if ((checkconst(forstep, 1) || checkconst(forstep, -1)) && + sp->exp2->kind == EK_PLUS && + exprsame(sp->exp2->args[sp->exp2->nargs-1], ep3, 2)) { + sp->exp2 = makeexpr_inc(sp->exp2, forstep); + } else { + freeexpr(forstep); + freeexpr(ep3); + ep3 = makeexpr_long(0); + } + if (forevalorder && isunsafe) { + if (exprdepends(sp->exp2, ep)) { + tvar = makestmttempvar(mp->type, name_TEMP); + sp->exp1 = makeexpr_comma( + makeexpr_comma( + makeexpr_assign(makeexpr_var(tvar), + copyexpr(ep2)), + makeexpr_assign(makeexpr_var(mp), + sp->exp2)), + makeexpr_assign(copyexpr(ep), + makeexpr_var(tvar))); + } else + sp->exp1 = makeexpr_comma( + sp->exp1, + makeexpr_assign(makeexpr_var(mp), + sp->exp2)); + } else { + if (isunsafe) + note("Evaluating FOR loop limit before initial value [315]"); + sp->exp1 = makeexpr_comma( + makeexpr_assign(makeexpr_var(mp), + sp->exp2), + sp->exp1); + } + sp->exp2 = makeexpr_inc(makeexpr_var(mp), ep3); + sp->exp2 = makeexpr_rel(ekind, ep, sp->exp2); + } + freeexpr(ep2); + break; + + case TOK_GOTO: + gettok(); + if (findlabelsym()) { + if (curtokmeaning->ctx != curctx) { + curtokmeaning->val.i = 1; + *spp = close_files_to_ctx(curtokmeaning->ctx); + while (*spp) + spp = &((*spp)->next); + newstmt(SK_ASSIGN); + var_reference(curtokmeaning->xnext); + if (curtokmeaning->ctx->kind == MK_MODULE && + !curtokmeaning->xnext->wasdeclared) { + outsection(minorspace); + declarevar(curtokmeaning->xnext, 0x7); + curtokmeaning->xnext->wasdeclared = 1; + outsection(minorspace); + } + sp->exp1 = makeexpr_bicall_2("longjmp", tp_void, + makeexpr_var(curtokmeaning->xnext), + makeexpr_long(1)); + } else { + newstmt(SK_GOTO); + sp->exp1 = makeexpr_name(format_s(name_LABEL, + curtokmeaning->name), + tp_integer); + } + } else { + warning("Expected a label [263]"); + } + gettok(); + break; + + case TOK_IF: + gettok(); + newstmt(SK_IF); + saveserial = curserial; + curserial = ++serialcount; + sp->exp1 = p_expr(tp_boolean); + wneedtok(TOK_THEN); + sp->stm1 = p_stmt(NULL, SF_SAVESER|SF_IF); + changecomments(curcomments, -1, saveserial+1, -1, saveserial); + checkkeyword(TOK_ELSIF); + while (curtok == TOK_ELSIF) { + gettok(); + sp->stm2 = makestmt(SK_IF); + sp = sp->stm2; + sp->exp1 = p_expr(tp_boolean); + wneedtok(TOK_THEN); + sp->stm1 = p_stmt(NULL, SF_SAVESER|SF_IF); + sp->exp2 = makeexpr_long(1); + } + if (curtok == TOK_ELSE) { + line1 = inf_lnum; + strlist_mix(&curcomments, grabcomment(CMT_ONELSE)); + gettok(); + line2 = (curtok == TOK_IF) ? inf_lnum : -1; + saveserial2 = curserial; + sp->stm2 = p_stmt(NULL, SF_SAVESER|SF_IF); + changecomments(curcomments, -1, saveserial2, -1, saveserial+1); + if (sp->stm2 && sp->stm2->kind == SK_IF && + !sp->stm2->next && !modula2) { + sp->stm2->exp2 = makeexpr_long(elseif > 0 || + (elseif < 0 && line1 == line2)); + } + } + if (modula2) + wneedtok(TOK_END); + curserial = saveserial; + break; + + case TOK_INLINE: + gettok(); + note("Inline assembly language encountered [254]"); + if (curtok != TOK_LPAR) { /* Macintosh style */ + newstmt(SK_ASSIGN); + sp->exp1 = makeexpr_bicall_1("inline", tp_void, + p_expr(tp_integer)); + break; + } + do { + name = getinlinepart(); + if (!*name) + break; + newstmt(SK_ASSIGN); + sp->exp1 = makeexpr_bicall_1("asm", tp_void, + makeexpr_string(format_s(" inline %s", name))); + gettok(); + } while (curtok == TOK_SLASH); + skipcloseparen(); + break; + + case TOK_LOOP: + gettok(); + newstmt(SK_WHILE); + sp->exp1 = makeexpr_long(1); + sp->stm1 = p_stmt(NULL, SF_SAVESER); + break; + + case TOK_REPEAT: + newstmt(SK_REPEAT); + saveserial = curserial; + spp2 = &(sp->stm1); + i = SF_FIRST; + do { + gettok(); + *spp2 = p_stmt(sp->stm1, i); + i = 0; + while (*spp2) + spp2 = &((*spp2)->next); + } while (curtok == TOK_SEMI); + if (!wneedtok(TOK_UNTIL)) + skippasttoken(TOK_UNTIL); + sp->exp1 = makeexpr_not(p_expr(tp_boolean)); + curserial = saveserial; + strlist_mix(&curcomments, grabcomment(CMT_ONEND)); + break; + + case TOK_RETURN: + gettok(); + newstmt(SK_RETURN); + if (curctx->isfunction) { + sp->exp1 = gentle_cast(p_expr(curctx->cbase->type), + curctx->cbase->type); + } + break; + + case TOK_TRY: + findsymbol("RECOVER")->flags &= ~KWPOSS; + newstmt(SK_TRY); + sp->exp1 = makeexpr_long(++trycount); + spp2 = &(sp->stm1); + i = SF_FIRST; + do { + gettok(); + *spp2 = p_stmt(sp->stm1, i); + i = 0; + while (*spp2) + spp2 = &((*spp2)->next); + } while (curtok == TOK_SEMI); + if (!wneedtok(TOK_RECOVER)) + skippasttoken(TOK_RECOVER); + sp->stm2 = p_stmt(NULL, SF_SAVESER); + break; + + case TOK_WHILE: + gettok(); + newstmt(SK_WHILE); + sp->exp1 = p_expr(tp_boolean); + wneedtok(TOK_DO); + sp->stm1 = p_stmt(NULL, SF_SAVESER); + break; + + case TOK_WITH: + gettok(); + if (withlevel >= MAXWITHS-1) + error("Too many nested WITHs"); + ep = p_expr(NULL); + if (ep->val.type->kind != TK_RECORD) + warning("Argument of WITH is not a RECORD [264]"); + withlist[withlevel] = ep->val.type; + if (simplewith(ep)) { + withexprs[withlevel] = ep; + mp = NULL; + } else { /* need to save a temporary pointer */ + tp = makepointertype(ep->val.type); + mp = makestmttempvar(tp, name_WITH); + withexprs[withlevel] = makeexpr_hat(makeexpr_var(mp), 0); + } + withlevel++; + if (curtok == TOK_COMMA) { + curtok = TOK_WITH; + sp2 = p_stmt(NULL, sflags & SF_FIRST); + } else { + wneedtok(TOK_DO); + sp2 = p_stmt(NULL, sflags & SF_FIRST); + } + withlevel--; + if (mp) { /* if "with p^" for constant p, don't need temp ptr */ + if (ep->kind == EK_HAT && ep->args[0]->kind == EK_VAR && + !checkvarchanged(sp2, (Meaning *)ep->args[0]->val.i)) { + replaceexpr(sp2, withexprs[withlevel]->args[0], + ep->args[0]); + freeexpr(ep); + canceltempvar(mp); + } else { + newstmt(SK_ASSIGN); + sp->exp1 = makeexpr_assign(makeexpr_var(mp), + makeexpr_addr(ep)); + } + } + freeexpr(withexprs[withlevel]); + *spp = sp2; + while (*spp) + spp = &((*spp)->next); + break; + + case TOK_INCLUDE: + badinclude(); + goto again; + + case TOK_ADDR: /* flakey Turbo "@procptr := anyptr" assignment */ + newstmt(SK_ASSIGN); + ep = p_expr(tp_void); + if (wneedtok(TOK_ASSIGN)) + sp->exp1 = makeexpr_assign(ep, p_expr(ep->val.type)); + else + sp->exp1 = ep; + break; + + case TOK_IDENT: + mp = curtokmeaning; + if (mp == mp_str_hp) + mp = curtokmeaning = mp_str_turbo; + if (mp == mp_val_modula) + mp = curtokmeaning = mp_val_turbo; + if (mp == mp_blockread_ucsd) + mp = curtokmeaning = mp_blockread_turbo; + if (mp == mp_blockwrite_ucsd) + mp = curtokmeaning = mp_blockwrite_turbo; + if (mp == mp_dec_dec) + mp = curtokmeaning = mp_dec_turbo; + if (!mp) { + sym = curtoksym; /* make a guess at what the undefined name is... */ + name = stralloc(curtokcase); + gettok(); + newstmt(SK_ASSIGN); + if (curtok == TOK_ASSIGN) { + gettok(); + ep = p_expr(NULL); + mp = addmeaning(sym, MK_VAR); + mp->name = name; + mp->type = ep->val.type; + sp->exp1 = makeexpr_assign(makeexpr_var(mp), ep); + } else if (curtok == TOK_HAT || curtok == TOK_ADDR || + curtok == TOK_LBR || curtok == TOK_DOT) { + ep = makeexpr_name(name, tp_integer); + ep = fake_dots_n_hats(ep); + if (wneedtok(TOK_ASSIGN)) + sp->exp1 = makeexpr_assign(ep, p_expr(NULL)); + else + sp->exp1 = ep; + } else if (curtok == TOK_LPAR) { + ep = makeexpr_bicall_0(name, tp_void); + do { + gettok(); + insertarg(&ep, ep->nargs, p_expr(NULL)); + } while (curtok == TOK_COMMA); + skipcloseparen(); + sp->exp1 = ep; + } else { + sp->exp1 = makeexpr_bicall_0(name, tp_void); + } + if (!tryfuncmacro(&sp->exp1, NULL)) + undefsym(sym); + } else if (mp->kind == MK_FUNCTION && !mp->isfunction) { + mp->refcount++; + gettok(); + ep = p_funccall(mp); + if (!mp->constdefn) + need_forward_decl(mp); + if (mp->handler && !(mp->sym->flags & LEAVEALONE) && + !mp->constdefn) { + prochandler = (Stmt *(*)())mp->handler; + *spp = (*prochandler)(ep, slist); + while (*spp) + spp = &((*spp)->next); + } else { + newstmt(SK_ASSIGN); + sp->exp1 = ep; + } + } else if (mp->kind == MK_SPECIAL) { + gettok(); + if (mp->handler && !mp->isfunction) { + if ((mp->sym->flags & LEAVEALONE) || mp->constdefn) { + ep = makeexpr_bicall_0(mp->name, tp_void); + if (curtok == TOK_LPAR) { + do { + gettok(); + insertarg(&ep, ep->nargs, p_expr(NULL)); + } while (curtok == TOK_COMMA); + skipcloseparen(); + } + newstmt(SK_ASSIGN); + tryfuncmacro(&ep, mp); + sp->exp1 = ep; + } else { + prochandler = (Stmt *(*)())mp->handler; + *spp = (*prochandler)(mp, slist); + while (*spp) + spp = &((*spp)->next); + } + } else + symclass(curtoksym); + } else { + newstmt(SK_ASSIGN); + if (curtokmeaning->kind == MK_FUNCTION && + peeknextchar() != '(') { + mp = curctx; + while (mp && mp != curtokmeaning) + mp = mp->ctx; + if (mp) + curtokmeaning = curtokmeaning->cbase; + } + ep = p_expr(tp_void); +#if 0 + if (!(ep->kind == EK_SPCALL || + (ep->kind == EK_COND && + ep->args[1]->kind == EK_SPCALL))) + wexpecttok(TOK_ASSIGN); +#endif + if (curtok == TOK_ASSIGN) { + gettok(); + if (curtok == TOK_IDENT && !strcicmp(curtokbuf, "ZERO") && + !curtokmeaning) { /* VAX Pascal foolishness */ + gettok(); + ep2 = makeexpr_sizeof(copyexpr(ep), 0); + sp->exp1 = makeexpr_bicall_3("memset", tp_void, + makeexpr_addr(ep), + makeexpr_long(0), ep2); + } else + sp->exp1 = makeexpr_assign(ep, p_expr(ep->val.type)); + } else + sp->exp1 = ep; + } + break; + + default: + break; /* null statement */ + } + freestmttemps(tempmark); + if (sflags & SF_SAVESER) + curserial = firstserial; + return sbase; +} + + + + + + + +#define BR_NEVER 0x1 /* never use braces */ +#define BR_FUNCTION 0x2 /* function body */ +#define BR_THENPART 0x4 /* before an "else" */ +#define BR_ALWAYS 0x8 /* always use braces */ +#define BR_REPEAT 0x10 /* "do-while" loop */ +#define BR_TRY 0x20 /* in a recover block */ +#define BR_ELSEPART 0x40 /* after an "else" */ +#define BR_CASE 0x80 /* case of a switch stmt */ + +Static int usebraces(sp, opts) +Stmt *sp; +int opts; +{ + if (opts & (BR_FUNCTION|BR_ALWAYS)) + return 1; + if (opts & BR_NEVER) + return 0; + switch (bracesalways) { + case 0: + if (sp) { + if (sp->next || + sp->kind == SK_TRY || + (sp->kind == SK_IF && !sp->stm2) || + (opts & BR_REPEAT)) + return 1; + } + break; + + case 1: + return 1; + + default: + if (sp) { + if (sp->next || + sp->kind == SK_IF || + sp->kind == SK_WHILE || + sp->kind == SK_REPEAT || + sp->kind == SK_TRY || + sp->kind == SK_CASE || + sp->kind == SK_FOR) + return 1; + } + break; + } + if (sp != NULL && + findcomment(curcomments, CMT_NOT | CMT_TRAIL, sp->serial) != NULL) + return 1; + return 0; +} + + + +#define outspnl(spflag) output((spflag) ? " " : "\n") + +#define openbrace() \ + wbraces = (!candeclare); \ + if (wbraces) { \ + output("{"); \ + outspnl(braceline <= 0); \ + candeclare = 1; \ + } + +#define closebrace() \ + if (wbraces) { \ + if (sp->next || braces) \ + output("}\n"); \ + else \ + braces = 1; \ + } + + + +Meaning *outcontext; + +Static void outnl(serial) +int serial; +{ + outtrailcomment(curcomments, serial, commentindent); +} + + +Static void out_block(spbase, opts, serial) +Stmt *spbase; +int opts, serial; +{ + int i, j, braces, always, trynum, istrail, hascmt; + int gotcomments = 0; + int saveindent, saveindent2, delta; + Stmt *sp = spbase; + Stmt *sp2, *sp3; + Meaning *ctx, *mp; + Strlist *curcmt, *cmt, *savecurcmt = curcomments; + Strlist *trailcmt, *begincmt, *endcmt; + + if (debug>1) { fprintf(outf, "out_block of:\n"); dumpstmt(spbase,5); } + if (opts & BR_FUNCTION) { + if (outcontext && outcontext->comments) { + gotcomments = 1; + curcomments = outcontext->comments; + } + attach_comments(spbase); + } + braces = usebraces(sp, opts); + trailcmt = findcomment(curcomments, CMT_TRAIL, serial); + begincmt = findcomment(curcomments, CMT_ONBEGIN, serial); + istrail = 1; + if (!trailcmt) { + trailcmt = begincmt; + begincmt = NULL; + istrail = 0; + } + endcmt = findcomment(curcomments, CMT_ONEND, serial); + if ((begincmt || endcmt) && !(opts & BR_NEVER)) + braces = 1; + if (opts & BR_ELSEPART) { + cmt = findcomment(curcomments, CMT_ONELSE, serial); + if (cmt) { + if (trailcmt) { + out_spaces(bracecommentindent, commentoverindent, + commentlen(cmt), 0); + output("\001"); + outcomment(cmt); + } else + trailcmt = cmt; + } + } + if (braces) { + j = (opts & BR_FUNCTION) ? funcopenindent : openbraceindent; + if (!line_start()) { + if (trailcmt && + cur_column() + commentlen(trailcmt) + 2 > linewidth && + outindent + commentlen(trailcmt) + 2 < linewidth) /*close enough*/ + i = 0; + else if (opts & BR_ELSEPART) + i = ((braceelseline & 2) == 0); + else if (braceline >= 0) + i = (braceline == 0); + else + i = ((opts & BR_FUNCTION) == 0); + if (trailcmt && begincmt) { + out_spaces(commentindent, commentoverindent, + commentlen(trailcmt), j); + outcomment(trailcmt); + trailcmt = begincmt; + begincmt = NULL; + istrail = 0; + } else + outspnl(i); + } + if (line_start()) + singleindent(j); + output("{"); + candeclare = 1; + } else if (!sp) { + if (!line_start()) + outspnl(!nullstmtline && !(opts & BR_TRY)); + if (line_start()) + singleindent(tabsize); + output(";"); + } + if (opts & BR_CASE) + delta = 0; + else { + delta = tabsize; + if (opts & BR_FUNCTION) + delta = adddeltas(delta, bodyindent); + else if (braces) + delta = adddeltas(delta, blockindent); + } + futureindent(delta); + if (bracecombine && braces) + i = applydelta(outindent, delta) - cur_column(); + else + i = -1; + if (commentvisible(trailcmt)) { + if (line_start()) { + singleindent(delta); + out_spaces(commentoverindent, 1000, commentlen(trailcmt), 0); + outcomment(trailcmt); + } else /*if (commentlen(trailcmt) + cur_column() + 1 <= linewidth)*/ { + out_spaces(istrail ? commentindent : bracecommentindent, + commentoverindent, commentlen(trailcmt), delta); + outcomment(trailcmt); + } /*else { + output("\n"); + singleindent(delta); + out_spaces(commentoverindent, 1000, commentlen(trailcmt), 0); + outcomment(trailcmt); + }*/ + i = -9999; + } + if (i > 0) + out_spaces(i, 0, 0, 0); + else if (i != -9999) + output("\n"); + saveindent = outindent; + moreindent(delta); + outcomment(begincmt); + while (sp) { + flushcomments(NULL, CMT_PRE, sp->serial); + if (cmtdebug) + output(format_d("[%d] ", sp->serial)); + switch (sp->kind) { + + case SK_HEADER: + ctx = (Meaning *)sp->exp1->val.i; + eatblanklines(); + if (declarevars(ctx, 0)) + outsection(minorspace); + flushcomments(NULL, CMT_NOT | CMT_ONEND, serial); + if (ctx->kind == MK_MODULE) { + if (ctx->anyvarflag) { + output(format_s(name_MAIN, "")); + if (spacefuncs) + output(" "); + output("(argc,"); + if (spacecommas) + output(" "); + output("argv);\n"); + } else { + output("static int _was_initialized = 0;\n"); + output("if (_was_initialized++)\n"); + singleindent(tabsize); + output("return;\n"); + } + while (initialcalls) { + output(initialcalls->s); + output(";\n"); + strlist_remove(&initialcalls, initialcalls->s); + } + } else { + if (ctx->varstructflag && ctx->ctx->kind == MK_FUNCTION && + ctx->ctx->varstructflag) { + output(format_s(name_VARS, ctx->name)); + output("."); + output(format_s(name_LINK, ctx->ctx->name)); + output(" = "); + output(format_s(name_LINK, ctx->ctx->name)); + output(";\n"); + } + for (mp = ctx->cbase; mp; mp = mp->cnext) { + if ((mp->kind == MK_VAR || /* these are variables with */ + mp->kind == MK_VARREF) && + ((mp->varstructflag && /* initializers which were moved */ + mp->cnext && /* into a varstruct, so they */ + mp->cnext->snext == mp && /* must be initialized now */ + mp->cnext->constdefn && + ctx->kind == MK_FUNCTION) || + (mp->constdefn && + mp->type->kind == TK_ARRAY && + mp->constdefn->val.type->kind == TK_STRING && + !initpacstrings))) { + if (mp->type->kind == TK_ARRAY) { + output("memcpy("); + out_var(mp, 2); + output(",\002"); + if (spacecommas) + output(" "); + if (mp->constdefn) { + output(makeCstring(mp->constdefn->val.s, + mp->constdefn->val.i)); + mp->constdefn = NULL; + } else + out_var(mp->cnext, 2); + output(",\002"); + if (spacecommas) + output(" "); + output("sizeof("); + out_type(mp->type, 1); + output("))"); + } else { + out_var(mp, 2); + output(" = "); + out_var(mp->cnext, 2); + } + output(";\n"); + } + } + } + break; + + case SK_RETURN: + output("return"); + if (sp->exp1) { + switch (returnparens) { + + case 0: + output(" "); + out_expr(sp->exp1); + break; + + case 1: + if (spaceexprs != 0) + output(" "); + out_expr_parens(sp->exp1); + break; + + default: + if (sp->exp1->kind == EK_VAR || + sp->exp1->kind == EK_CONST || + sp->exp1->kind == EK_LONGCONST || + sp->exp1->kind == EK_BICALL) { + output(" "); + out_expr(sp->exp1); + } else { + if (spaceexprs != 0) + output(" "); + out_expr_parens(sp->exp1); + } + break; + } + } + output(";"); + outnl(sp->serial); + break; + + case SK_ASSIGN: + out_expr_stmt(sp->exp1); + output(";"); + outnl(sp->serial); + break; + + case SK_CASE: + output("switch ("); + out_expr(sp->exp1); + output(")"); + outspnl(braceline <= 0); + output("{"); + outnl(sp->serial); + saveindent2 = outindent; + moreindent(tabsize); + moreindent(switchindent); + sp2 = sp->stm1; + while (sp2 && sp2->kind == SK_CASELABEL) { + outsection(casespacing); + sp3 = sp2; + i = 0; + hascmt = (findcomment(curcomments, -1, sp2->serial) != NULL); + singleindent(caseindent); + flushcomments(NULL, CMT_PRE, sp2->serial); + for (;;) { + if (i) + singleindent(caseindent); + i = 0; + output("case "); + out_expr(sp3->exp1); + output(":\001"); + sp3 = sp3->stm1; + if (!sp3 || sp3->kind != SK_CASELABEL) + break; + if (casetabs != 1000) + out_spaces(casetabs, 0, 0, 0); + else { + output("\n"); + i = 1; + } + } + if (sp3) + out_block(sp3, BR_NEVER|BR_CASE, sp2->serial); + else { + outnl(sp2->serial); + if (!hascmt) + output("/* blank case */\n"); + } + output("break;\n"); + flushcomments(NULL, -1, sp2->serial); + sp2 = sp2->next; + } + if (sp2) { + outsection(casespacing); + singleindent(caseindent); + flushcomments(NULL, CMT_PRE, sp2->serial); + output("default:"); + out_block(sp2, BR_NEVER|BR_CASE, sp2->serial); + output("break;\n"); + flushcomments(NULL, -1, sp2->serial); + } + outindent = saveindent2; + output("}"); + curcmt = findcomment(curcomments, CMT_ONEND, sp->serial); + if (curcmt) + outcomment(curcmt); + else + output("\n"); + break; + + case SK_CASECHECK: + output(name_CASECHECK); + output("(); /* CASE value range error */\n"); + break; + + case SK_FOR: + output("for ("); + if (for_allornone) + output("\007"); + if (sp->exp1 || sp->exp2 || sp->exp3 || spaceexprs > 0) { + if (sp->exp1) + out_expr_top(sp->exp1); + else if (spaceexprs > 0) + output(" "); + output(";\002 "); + if (sp->exp2) + out_expr(sp->exp2); + output(";\002 "); + if (sp->exp3) + out_expr_top(sp->exp3); + } else { + output(";;"); + } + output(")"); + out_block(sp->stm1, 0, sp->serial); + break; + + case SK_LABEL: + if (!line_start()) + output("\n"); + singleindent(labelindent); + out_expr(sp->exp1); + output(":"); + if (!sp->next) + output(" ;"); + outnl(sp->serial); + break; + + case SK_GOTO: + /* what about non-local goto's? */ + output("goto "); + out_expr(sp->exp1); + output(";"); + outnl(sp->serial); + break; + + case SK_IF: + sp2 = sp; + for (;;) { + output("if ("); + out_expr_bool(sp2->exp1); + output(")"); + if (sp2->stm2) { + cmt = findcomment(curcomments, CMT_ONELSE, sp->serial+1); + i = (!cmt && sp2->stm2->kind == SK_IF && + !sp2->stm2->next && + ((sp2->stm2->exp2) + ? checkconst(sp2->stm2->exp2, 1) + : (elseif > 0))); + if (braceelse && + (usebraces(sp2->stm1, 0) || + usebraces(sp2->stm2, 0) || i)) + always = BR_ALWAYS; + else + always = 0; + out_block(sp2->stm1, BR_THENPART|always, sp->serial); + output("else"); + sp2 = sp2->stm2; + if (i) { + output(" "); + } else { + out_block(sp2, BR_ELSEPART|always, sp->serial+1); + break; + } + } else { + out_block(sp2->stm1, 0, sp->serial); + break; + } + } + break; + + case SK_REPEAT: + output("do"); + out_block(sp->stm1, BR_ALWAYS|BR_REPEAT, sp->serial); + output("while ("); + out_expr_bool(sp->exp1); + output(");"); + cmt = findcomment(curcomments, CMT_ONEND, sp->serial); + if (commentvisible(cmt)) { + out_spaces(commentindent, commentoverindent, + commentlen(cmt), 0); + output("\001"); + outcomment(cmt); + } else + output("\n"); + break; + + case SK_TRY: + trynum = sp->exp1->val.i; + output(format_d("TRY(try%d);", trynum)); + out_block(sp->stm1, BR_NEVER|BR_TRY, sp->serial); + if (sp->exp2) + output(format_ds("RECOVER2(try%d,%s);", trynum, + format_s(name_LABEL, format_d("try%d", trynum)))); + else + output(format_d("RECOVER(try%d);", trynum)); + out_block(sp->stm2, BR_NEVER|BR_TRY, sp->serial); + output(format_d("ENDTRY(try%d);\n", trynum)); + break; + + case SK_WHILE: + output("while ("); + out_expr_bool(sp->exp1); + output(")"); + out_block(sp->stm1, 0, sp->serial); + break; + + case SK_BREAK: + output("break;"); + outnl(sp->serial); + break; + + case SK_CONTINUE: + output("continue;"); + outnl(sp->serial); + break; + + default: + intwarning("out_block", + format_s("Misplaced statement kind %s [265]", + stmtkindname(sp->kind))); + break; + } + flushcomments(NULL, -1, sp->serial); + candeclare = 0; + if (debug>1) { fprintf(outf, "in out_block:\n"); dumpstmt(spbase,5); } + sp = sp->next; + } + if (opts & BR_FUNCTION) { + cmt = extractcomment(&curcomments, CMT_ONEND, serial); + if (findcomment(curcomments, -1, -1) != NULL) /* check for non-DONE */ + output("\n"); + flushcomments(NULL, -1, -1); + curcomments = cmt; + } + outindent = saveindent; + if (braces) { + if (line_start()) { + if (opts & BR_FUNCTION) + singleindent(funccloseindent); + else + singleindent(closebraceindent); + } + output("}"); + i = 1; + cmt = findcomment(curcomments, CMT_ONEND, serial); + if (!(opts & BR_REPEAT) && commentvisible(cmt)) { + out_spaces(bracecommentindent, commentoverindent, + commentlen(cmt), 0); + output("\001"); + outcomment(cmt); + i = 0; + } + if (i) { + outspnl((opts & BR_REPEAT) || + ((opts & BR_THENPART) && (braceelseline & 1) == 0)); + } + candeclare = 0; + } + if (gotcomments) { + outcontext->comments = curcomments; + curcomments = savecurcmt; + } +} + + + + + +/* Should have a way to convert GOTO's to the end of the function to RETURN's */ + + +/* Convert "_RETV = foo;" at end of function to "return foo" */ + +Static int checkreturns(spp, nearret) +Stmt **spp; +int nearret; +{ + Stmt *sp; + Expr *rvar, *ex; + Meaning *mp; + int spnearret, spnextreturn; + int result = 0; + + if (debug>2) { fprintf(outf, "checkreturns on:\n"); dumpstmt(*spp, 5); } + while ((sp = *spp)) { + spnextreturn = (sp->next && + sp->next->kind == SK_RETURN && sp->next->exp1 && + isretvar(sp->next->exp1) == curctx->cbase); + spnearret = (nearret && !sp->next) || spnextreturn; + result = 0; + switch (sp->kind) { + + case SK_ASSIGN: + ex = sp->exp1; + if (ex->kind == EK_ASSIGN || structuredfunc(ex)) { + rvar = ex->args[0]; + mp = isretvar(rvar); + if (mp == curctx->cbase && spnearret) { + if (ex->kind == EK_ASSIGN) { + if (mp->kind == MK_VARPARAM) { + ex = makeexpr_comma(ex, makeexpr_var(mp)); + } else { + ex = grabarg(ex, 1); + mp->refcount--; + } + } + sp->exp1 = ex; + sp->kind = SK_RETURN; + if (spnextreturn) { + mp->refcount--; + sp->next = sp->next->next; + } + result = 1; + } + } + break; + + case SK_RETURN: + case SK_GOTO: + result = 1; + break; + + case SK_IF: + result = checkreturns(&sp->stm1, spnearret) & /* NOT && */ + checkreturns(&sp->stm2, spnearret); + break; + + case SK_TRY: + (void) checkreturns(&sp->stm1, 0); + (void) checkreturns(&sp->stm2, spnearret); + break; + + /* should handle CASE statements as well */ + + default: + (void) checkreturns(&sp->stm1, 0); + (void) checkreturns(&sp->stm2, 0); + break; + } + spp = &sp->next; + } + return result; +} + + + + + + + +/* Replace all occurrences of one expression with another expression */ + +Expr *replaceexprexpr(ex, oldex, newex, keeptype) +Expr *ex, *oldex, *newex; +int keeptype; +{ + int i; + Type *type; + + for (i = 0; i < ex->nargs; i++) + ex->args[i] = replaceexprexpr(ex->args[i], oldex, newex, keeptype); + if (exprsame(ex, oldex, 2)) { + if (ex->val.type->kind == TK_POINTER && + ex->val.type->basetype == oldex->val.type) { + freeexpr(ex); + return makeexpr_addr(copyexpr(newex)); + } else if (oldex->val.type->kind == TK_POINTER && + oldex->val.type->basetype == ex->val.type) { + freeexpr(ex); + return makeexpr_hat(copyexpr(newex), 0); + } else { + type = ex->val.type; + freeexpr(ex); + ex = copyexpr(newex); + if (keeptype) + ex->val.type = type; + return ex; + } + } + return resimplify(ex); +} + + +void replaceexpr(sp, oldex, newex) +Stmt *sp; +Expr *oldex, *newex; +{ + while (sp) { + replaceexpr(sp->stm1, oldex, newex); + replaceexpr(sp->stm2, oldex, newex); + if (sp->exp1) + sp->exp1 = replaceexprexpr(sp->exp1, oldex, newex, 1); + if (sp->exp2) + sp->exp2 = replaceexprexpr(sp->exp2, oldex, newex, 1); + if (sp->exp3) + sp->exp3 = replaceexprexpr(sp->exp3, oldex, newex, 1); + sp = sp->next; + } +} + + + + + + +Stmt *mixassignments(sp, mp) +Stmt *sp; +Meaning *mp; +{ + if (!sp) + return NULL; + sp->next = mixassignments(sp->next, mp); + if (sp->next && + sp->kind == SK_ASSIGN && + sp->exp1->kind == EK_ASSIGN && + sp->exp1->args[0]->kind == EK_VAR && + (!mp || mp == (Meaning *)sp->exp1->args[0]->val.i) && + ord_type(sp->exp1->args[0]->val.type)->kind == TK_INTEGER && + nodependencies(sp->exp1->args[1], 0) && + sp->next->kind == SK_ASSIGN && + sp->next->exp1->kind == EK_ASSIGN && + (exprsame(sp->exp1->args[0], sp->next->exp1->args[0], 1) || + (mp && mp->istemporary)) && + exproccurs(sp->next->exp1->args[1], sp->exp1->args[0]) == 1) { + sp->next->exp1->args[1] = replaceexprexpr(sp->next->exp1->args[1], + sp->exp1->args[0], + sp->exp1->args[1], 1); + if (mp && mp->istemporary) + canceltempvar(mp); + return sp->next; + } + return sp; +} + + + + + + + + +/* Do various simple (sometimes necessary) massages on the statements */ + + +Static Stmt bogusreturn = { SK_RETURN, NULL, NULL, NULL, NULL, NULL, NULL }; + + + +Static int isescape(ex) +Expr *ex; +{ + if (ex->kind == EK_BICALL && (!strcmp(ex->val.s, name_ESCAPE) || + !strcmp(ex->val.s, name_ESCIO) || + !strcmp(ex->val.s, name_OUTMEM) || + !strcmp(ex->val.s, name_CASECHECK) || + !strcmp(ex->val.s, name_NILCHECK) || + !strcmp(ex->val.s, "_exit") || + !strcmp(ex->val.s, "exit"))) + return 1; + if (ex->kind == EK_CAST) + return isescape(ex->args[0]); + return 0; +} + + +/* check if a block can never exit by falling off the end */ +Static int deadendblock(sp) +Stmt *sp; +{ + if (!sp) + return 0; + while (sp->next) + sp = sp->next; + return (sp->kind == SK_GOTO || + sp->kind == SK_BREAK || + sp->kind == SK_CONTINUE || + sp->kind == SK_RETURN || + sp->kind == SK_CASECHECK || + (sp->kind == SK_IF && deadendblock(sp->stm1) && + deadendblock(sp->stm2)) || + (sp->kind == SK_ASSIGN && isescape(sp->exp1))); +} + + + + +int expr_is_bool(ex, want) +Expr *ex; +int want; +{ + long val; + + if (ex->val.type == tp_boolean && isconstexpr(ex, &val)) + return (val == want); + return 0; +} + + + + +/* Returns 1 if c1 implies c2, 0 otherwise */ +/* If not1 is true, then checks if (!c1) implies c2; similarly for not2 */ + +/* Identities used: + c1 -> (c2a && c2b) <=> (c1 -> c2a) && (c1 -> c2b) + c1 -> (c2a || c2b) <=> (c1 -> c2a) || (c1 -> c2b) + (c1a && c1b) -> c2 <=> (c1a -> c2) || (c1b -> c2) + (c1a || c1b) -> c2 <=> (c1a -> c2) && (c1b -> c2) + (!c1) -> (!c2) <=> c2 -> c1 + (a == b) -> c2(b) <=> c2(a) + !(c1 && c2) <=> (!c1) || (!c2) + !(c1 || c2) <=> (!c1) && (!c2) +*/ +/* This could be smarter about, e.g., (a>5) -> (a>0) */ + +int implies(c1, c2, not1, not2) +Expr *c1, *c2; +int not1, not2; +{ + Expr *ex; + int i; + + if (c1->kind == EK_EQ && c1->args[0]->val.type == tp_boolean) { + if (checkconst(c1->args[0], 1)) { /* things like "flag = true" */ + return implies(c1->args[1], c2, not1, not2); + } else if (checkconst(c1->args[1], 1)) { + return implies(c1->args[0], c2, not1, not2); + } else if (checkconst(c1->args[0], 0)) { + return implies(c1->args[1], c2, !not1, not2); + } else if (checkconst(c1->args[1], 0)) { + return implies(c1->args[0], c2, !not1, not2); + } + } + if (c2->kind == EK_EQ && c2->args[0]->val.type == tp_boolean) { + if (checkconst(c2->args[0], 1)) { + return implies(c1, c2->args[1], not1, not2); + } else if (checkconst(c2->args[1], 1)) { + return implies(c1, c2->args[0], not1, not2); + } else if (checkconst(c2->args[0], 0)) { + return implies(c1, c2->args[1], not1, !not2); + } else if (checkconst(c2->args[1], 0)) { + return implies(c1, c2->args[0], not1, !not2); + } + } + switch (c2->kind) { + + case EK_AND: + if (not2) /* c1 -> (!c2a || !c2b) */ + return (implies(c1, c2->args[0], not1, 1) || + implies(c1, c2->args[1], not1, 1)); + else /* c1 -> (c2a && c2b) */ + return (implies(c1, c2->args[0], not1, 0) && + implies(c1, c2->args[1], not1, 0)); + + case EK_OR: + if (not2) /* c1 -> (!c2a && !c2b) */ + return (implies(c1, c2->args[0], not1, 1) && + implies(c1, c2->args[1], not1, 1)); + else /* c1 -> (c2a || c2b) */ + return (implies(c1, c2->args[0], not1, 0) || + implies(c1, c2->args[1], not1, 0)); + + case EK_NOT: /* c1 -> (!c2) */ + return (implies(c1, c2->args[0], not1, !not2)); + + case EK_CONST: + if ((c2->val.i != 0) != not2) /* c1 -> true */ + return 1; + break; + + default: + break; + } + switch (c1->kind) { + + case EK_AND: + if (not1) /* (!c1a || !c1b) -> c2 */ + return (implies(c1->args[0], c2, 1, not2) && + implies(c1->args[1], c2, 1, not2)); + else /* (c1a && c1b) -> c2 */ + return (implies(c1->args[0], c2, 0, not2) || + implies(c1->args[1], c2, 0, not2)); + + case EK_OR: + if (not1) /* (!c1a && !c1b) -> c2 */ + return (implies(c1->args[0], c2, 1, not2) || + implies(c1->args[1], c2, 1, not2)); + else /* (c1a || c1b) -> c2 */ + return (implies(c1->args[0], c2, 0, not2) && + implies(c1->args[1], c2, 0, not2)); + + case EK_NOT: /* (!c1) -> c2 */ + return (implies(c1->args[0], c2, !not1, not2)); + + case EK_CONST: + if ((c1->val.i != 0) == not1) /* false -> c2 */ + return 1; + break; + + case EK_EQ: /* (a=b) -> c2 */ + case EK_ASSIGN: /* (a:=b) -> c2 */ + case EK_NE: /* (a<>b) -> c2 */ + if ((c1->kind == EK_NE) == not1) { + if (c1->args[0]->kind == EK_VAR) { + ex = replaceexprexpr(copyexpr(c2), c1->args[0], c1->args[1], 1); + i = expr_is_bool(ex, !not2); + freeexpr(ex); + if (i) + return 1; + } + if (c1->args[1]->kind == EK_VAR) { + ex = replaceexprexpr(copyexpr(c2), c1->args[1], c1->args[0], 1); + i = expr_is_bool(ex, !not2); + freeexpr(ex); + if (i) + return 1; + } + } + break; + + default: + break; + } + if (not1 == not2 && exprequiv(c1, c2)) { /* c1 -> c1 */ + return 1; + } + return 0; +} + + + + + +void infiniteloop(sp) +Stmt *sp; +{ + switch (infloopstyle) { + + case 1: /* write "for (;;) ..." */ + sp->kind = SK_FOR; + freeexpr(sp->exp1); + sp->exp1 = NULL; + break; + + case 2: /* write "while (1) ..." */ + sp->kind = SK_WHILE; + freeexpr(sp->exp1); + sp->exp1 = makeexpr_val(make_ord(tp_boolean, 1)); + break; + + case 3: /* write "do ... while (1)" */ + sp->kind = SK_REPEAT; + freeexpr(sp->exp1); + sp->exp1 = makeexpr_val(make_ord(tp_boolean, 1)); + break; + + default: /* leave it alone */ + break; + + } +} + + + + + +Expr *print_func(ex) +Expr *ex; +{ + if (!ex || ex->kind != EK_BICALL) + return NULL; + if ((!strcmp(ex->val.s, "printf") && + ex->args[0]->kind == EK_CONST) || + !strcmp(ex->val.s, "putchar") || + !strcmp(ex->val.s, "puts")) + return ex_output; + if ((!strcmp(ex->val.s, "fprintf") || + !strcmp(ex->val.s, "sprintf")) && + ex->args[1]->kind == EK_CONST) + return ex->args[0]; + if (!strcmp(ex->val.s, "putc") || + !strcmp(ex->val.s, "fputc") || + !strcmp(ex->val.s, "fputs")) + return ex->args[1]; + return NULL; +} + + + +int printnl_func(ex) +Expr *ex; +{ + char *cp, ch; + int i, len; + + if (debug>2) { fprintf(outf,"printnl_func("); dumpexpr(ex); fprintf(outf, ")\n"); } + if (!strcmp(ex->val.s, "printf") || + !strcmp(ex->val.s, "puts") || + !strcmp(ex->val.s, "fputs")) { + if (ex->args[0]->kind != EK_CONST) + return 0; + cp = ex->args[0]->val.s; + len = ex->args[0]->val.i; + } else if (!strcmp(ex->val.s, "fprintf")) { + if (ex->args[1]->kind != EK_CONST) + return 0; + cp = ex->args[1]->val.s; + len = ex->args[1]->val.i; + } else if (!strcmp(ex->val.s, "putchar") || + !strcmp(ex->val.s, "putc") || + !strcmp(ex->val.s, "fputc")) { + if (ex->args[0]->kind != EK_CONST) + return 0; + ch = ex->args[0]->val.i; + cp = &ch; + len = 1; + } else + return 0; + for (i = 1; i <= len; i++) + if (*cp++ != '\n') + return 0; + return len + (!strcmp(ex->val.s, "puts")); +} + + + +Expr *chg_printf(ex) +Expr *ex; +{ + Expr *fex; + + if (debug>2) { fprintf(outf,"chg_printf("); dumpexpr(ex); fprintf(outf, ")\n"); } + if (!strcmp(ex->val.s, "putchar")) { + ex = makeexpr_sprintfify(grabarg(ex, 0)); + canceltempvar(istempvar(ex->args[0])); + strchange(&ex->val.s, "printf"); + delfreearg(&ex, 0); + ex->val.type = tp_void; + } else if (!strcmp(ex->val.s, "putc") || + !strcmp(ex->val.s, "fputc") || + !strcmp(ex->val.s, "fputs")) { + fex = copyexpr(ex->args[1]); + ex = makeexpr_sprintfify(grabarg(ex, 0)); + canceltempvar(istempvar(ex->args[0])); + strchange(&ex->val.s, "fprintf"); + ex->args[0] = fex; + ex->val.type = tp_void; + } else if (!strcmp(ex->val.s, "puts")) { + ex = makeexpr_concat(makeexpr_sprintfify(grabarg(ex, 0)), + makeexpr_string("\n"), 1); + strchange(&ex->val.s, "printf"); + delfreearg(&ex, 0); + ex->val.type = tp_void; + } + if (!strcmp(ex->val.s, "fprintf") && exprsame(ex->args[0], ex_output, 1)) { + delfreearg(&ex, 0); + strchange(&ex->val.s, "printf"); + } + return ex; +} + + +Expr *mix_printf(ex, ex2) +Expr *ex, *ex2; +{ + int i; + + ex = chg_printf(ex); + if (debug>2) { fprintf(outf,"chg_printf returns "); dumpexpr(ex); fprintf(outf, "\n"); } + ex2 = chg_printf(copyexpr(ex2)); + if (debug>2) { fprintf(outf,"chg_printf returns "); dumpexpr(ex2);fprintf(outf, "\n"); } + i = (!strcmp(ex->val.s, "printf")) ? 0 : 1; + ex->args[i] = makeexpr_concat(ex->args[i], ex2->args[i], 0); + for (i++; i < ex2->nargs; i++) { + insertarg(&ex, ex->nargs, ex2->args[i]); + } + return ex; +} + + + + + + +void eatstmt(spp) +Stmt **spp; +{ + Stmt *sp = *spp; + + if (debug>2) { fprintf(outf, "eatstmt on:\n"); dumpstmt(sp, 5); } + *spp = sp->next; + sp->next = NULL; + free_stmt(sp); +} + + + +int haslabels(sp) +Stmt *sp; +{ + if (!sp) + return 0; + if (haslabels(sp->stm1) || haslabels(sp->stm2)) + return 1; + return (sp->kind == SK_LABEL); +} + + + +void fixblock(spp, thereturn) +Stmt **spp, *thereturn; +{ + Stmt *sp, *sp1, *sp2, *sp3, **spp2, *thisreturn; + Expr *ex; + Meaning *tvar; + int save_tryblock; + short save_tryflag; + int i, j, de1, de2; + long saveserial = curserial; + + while ((sp = *spp)) { + sp2 = sp->next; + sp->next = NULL; + sp = fix_statement(*spp); + if (!sp) { + *spp = sp2; + continue; + } + *spp = sp; + for (sp3 = sp; sp3->next; sp3 = sp3->next) ; + sp3->next = sp2; + if (!sp->next) + thisreturn = thereturn; + else if (sp->next->kind == SK_RETURN || + (sp->next->kind == SK_ASSIGN && + isescape(sp->next->exp1))) + thisreturn = sp->next; + else + thisreturn = NULL; + if (sp->serial >= 0) + curserial = sp->serial; + switch (sp->kind) { + + case SK_ASSIGN: + if (sp->exp1) + sp->exp1 = fixexpr(sp->exp1, ENV_STMT); + if (!sp->exp1) + intwarning("fixblock", "sp->exp1 == NULL in SK_ASSIGN"); + if (!sp->exp1 || nosideeffects(sp->exp1, 1)) { + eatstmt(spp); + continue; + } else { + switch (sp->exp1->kind) { + + case EK_COND: + *spp = makestmt_if(sp->exp1->args[0], + makestmt_call(sp->exp1->args[1]), + makestmt_call(sp->exp1->args[2])); + (*spp)->next = sp->next; + continue; /* ... to fix this new if statement */ + + case EK_ASSIGN: + if (sp->exp1->args[1]->kind == EK_COND && usecommas != 1) { + *spp = makestmt_if(sp->exp1->args[1]->args[0], + makestmt_assign(copyexpr(sp->exp1->args[0]), + sp->exp1->args[1]->args[1]), + makestmt_assign(sp->exp1->args[0], + sp->exp1->args[1]->args[2])); + (*spp)->next = sp->next; + continue; + } + if (isescape(sp->exp1->args[1])) { + sp->exp1 = grabarg(sp->exp1, 1); + continue; + } + if (exprsame(sp->exp1->args[0], sp->exp1->args[1], 1)) { + /* *spp = sp->next; */ + sp->exp1 = grabarg(sp->exp1, 0); + continue; + } + if (sp->exp1->args[1]->kind == EK_BICALL) { + if (!strcmp(sp->exp1->args[1]->val.s, + getfbufname) && + buildreads == 1 && + sp->next && + sp->next->kind == SK_ASSIGN && + sp->next->exp1->kind == EK_BICALL && + !strcmp(sp->next->exp1->val.s, + getname) && + expr_has_address(sp->exp1->args[0]) && + similartypes(sp->exp1->args[0]->val.type, + filebasetype(sp->exp1->args[1]->args[0]->val.type)) && + exprsame(sp->exp1->args[1]->args[0], + sp->next->exp1->args[0], 1)) { + eatstmt(&sp->next); + ex = makeexpr_bicall_4("fread", tp_integer, + makeexpr_addr(sp->exp1->args[0]), + makeexpr_sizeof(sp->exp1->args[1]->args[1], 0), + makeexpr_long(1), + sp->exp1->args[1]->args[0]); + FREE(sp->exp1); + sp->exp1 = ex; + continue; + } + if (!strcmp(sp->exp1->args[1]->val.s, + chargetfbufname) && + buildreads != 0 && + sp->next && + sp->next->kind == SK_ASSIGN && + sp->next->exp1->kind == EK_BICALL && + !strcmp(sp->next->exp1->val.s, + chargetname) && + expr_has_address(sp->exp1->args[0]) && + exprsame(sp->exp1->args[1]->args[0], + sp->next->exp1->args[0], 1)) { + eatstmt(&sp->next); + strchange(&sp->exp1->args[1]->val.s, + "getc"); + continue; + } + } + break; + + case EK_BICALL: + if (!strcmp(sp->exp1->val.s, name_ESCAPE)) { + if (fixexpr_tryblock) { + *spp = makestmt_assign(makeexpr_var(mp_escapecode), + grabarg(sp->exp1, 0)); + (*spp)->next = makestmt(SK_GOTO); + (*spp)->next->exp1 = makeexpr_name(format_s(name_LABEL, + format_d("try%d", + fixexpr_tryblock)), + tp_integer); + (*spp)->next->next = sp->next; + fixexpr_tryflag = 1; + continue; + } + } else if (!strcmp(sp->exp1->val.s, name_ESCIO)) { + if (fixexpr_tryblock) { + *spp = makestmt_assign(makeexpr_var(mp_escapecode), + makeexpr_long(-10)); + (*spp)->next = makestmt_assign(makeexpr_var(mp_ioresult), + grabarg(sp->exp1, 0)); + (*spp)->next->next = makestmt(SK_GOTO); + (*spp)->next->next->exp1 = makeexpr_name(format_s(name_LABEL, + format_d("try%d", + fixexpr_tryblock)), + tp_integer); + (*spp)->next->next->next = sp->next; + fixexpr_tryflag = 1; + continue; + } + } + if (!strcmp(sp->exp1->val.s, putfbufname) && + buildwrites == 1 && + sp->next && + sp->next->kind == SK_ASSIGN && + sp->next->exp1->kind == EK_BICALL && + !strcmp(sp->next->exp1->val.s, + putname) && + exprsame(sp->exp1->args[0], + sp->next->exp1->args[0], 1)) { + eatstmt(&sp->next); + if (!expr_has_address(sp->exp1->args[2]) || + sp->exp1->args[2]->val.type != + sp->exp1->args[1]->val.type) { + tvar = maketempvar(sp->exp1->args[1]->val.type, + name_TEMP); + sp2 = makestmt_assign(makeexpr_var(tvar), + sp->exp1->args[2]); + sp2->next = sp; + *spp = sp2; + sp->exp1->args[2] = makeexpr_var(tvar); + freetempvar(tvar); + } + ex = makeexpr_bicall_4("fwrite", tp_integer, + makeexpr_addr(sp->exp1->args[2]), + makeexpr_sizeof(sp->exp1->args[1], 0), + makeexpr_long(1), + sp->exp1->args[0]); + FREE(sp->exp1); + sp->exp1 = ex; + continue; + } + if (!strcmp(sp->exp1->val.s, charputfbufname) && + buildwrites != 0 && + sp->next && + sp->next->kind == SK_ASSIGN && + sp->next->exp1->kind == EK_BICALL && + !strcmp(sp->next->exp1->val.s, + charputname) && + exprsame(sp->exp1->args[0], + sp->next->exp1->args[0], 1)) { + eatstmt(&sp->next); + swapexprs(sp->exp1->args[0], + sp->exp1->args[1]); + strchange(&sp->exp1->val.s, "putc"); + continue; + } + if ((!strcmp(sp->exp1->val.s, resetbufname) || + !strcmp(sp->exp1->val.s, setupbufname)) && + !fileisbuffered(sp->exp1->args[0], 0)) { + eatstmt(spp); + continue; + } + ex = print_func(sp->exp1); + if (ex && sp->next && mixwritelns && + sp->next->kind == SK_ASSIGN && + exprsame(ex, print_func(sp->next->exp1), 1) && + (printnl_func(sp->exp1) || + printnl_func(sp->next->exp1))) { + sp->exp1 = mix_printf(sp->exp1, + sp->next->exp1); + eatstmt(&sp->next); + continue; + } + break; + + case EK_FUNCTION: + case EK_SPCALL: + case EK_POSTINC: + case EK_POSTDEC: + case EK_AND: + case EK_OR: + break; + + default: + spp2 = spp; + for (i = 0; i < sp->exp1->nargs; i++) { + *spp2 = makestmt_call(sp->exp1->args[i]); + spp2 = &(*spp2)->next; + } + *spp2 = sp->next; + continue; /* ... to fix these new statements */ + + } + } + break; + + case SK_IF: + fixblock(&sp->stm1, thisreturn); + fixblock(&sp->stm2, thisreturn); + if (!sp->stm1) { + if (!sp->stm2) { + sp->kind = SK_ASSIGN; + continue; + } else { + if (sp->stm2->kind == SK_IF && sp->stm2->exp2) { + freeexpr(sp->stm2->exp2); + sp->stm2->exp2 = NULL; + } + sp->exp1 = makeexpr_not(sp->exp1); /* if (x) else foo => if (!x) foo */ + swapstmts(sp->stm1, sp->stm2); + /* Ought to exchange comments for then/else parts */ + } + } + /* At this point we know sp1 != NULL */ + if (thisreturn) { + if (thisreturn->kind == SK_WHILE) { + if (usebreaks) { + sp1 = sp->stm1; + while (sp1->next) + sp1 = sp1->next; + if (sp->stm2) { + sp2 = sp->stm2; + while (sp2->next) + sp2 = sp2->next; + i = stmtcount(sp->stm1); + j = stmtcount(sp->stm2); + if (j >= breaklimit && i <= 2 && j > i*2 && + ((implies(sp->exp1, thisreturn->exp1, 0, 1) && + !checkexprchanged(sp->stm1, sp->exp1)) || + (sp1->kind == SK_ASSIGN && + implies(sp1->exp1, thisreturn->exp1, 0, 1)))) { + sp1->next = makestmt(SK_BREAK); + } else if (i >= breaklimit && j <= 2 && i > j*2 && + ((implies(sp->exp1, thisreturn->exp1, 1, 1) && + !checkexprchanged(sp->stm2, sp->exp1)) || + (sp2->kind == SK_ASSIGN && + implies(sp2->exp1, thisreturn->exp1, 0, 1)))) { + sp2->next = makestmt(SK_BREAK); + } else if (!checkconst(sp->exp2, 1)) { + /* not part of an else-if */ + if (j >= continuelimit) { + sp1->next = makestmt(SK_CONTINUE); + } else if (i >= continuelimit) { + sp2->next = makestmt(SK_CONTINUE); + } + } + } else { + i = stmtcount(sp->stm1); + if (i >= breaklimit && + implies(sp->exp1, thisreturn->exp1, 1, 1)) { + sp->exp1 = makeexpr_not(sp->exp1); + sp1->next = sp->next; + sp->next = sp->stm1; + sp->stm1 = makestmt(SK_BREAK); + } else if (i >= continuelimit) { + sp->exp1 = makeexpr_not(sp->exp1); + sp1->next = sp->next; + sp->next = sp->stm1; + sp->stm1 = makestmt(SK_CONTINUE); + } + } + } + } else { + if (usereturns) { + sp2 = sp->stm1; + while (sp2->next) + sp2 = sp2->next; + if (sp->stm2) { + /* if (x) foo; else bar; (return;) => if (x) {foo; return;} bar; */ + if (stmtcount(sp->stm2) >= returnlimit) { + if (!deadendblock(sp->stm1)) + sp2->next = copystmt(thisreturn); + } else if (stmtcount(sp->stm1) >= returnlimit) { + sp2 = sp->stm2; + while (sp2->next) + sp2 = sp2->next; + if (!deadendblock(sp->stm2)) + sp2->next = copystmt(thisreturn); + } + } else { /* if (x) foo; (return;) => if (!x) return; foo; */ + if (stmtcount(sp->stm1) >= returnlimit) { + sp->exp1 = makeexpr_not(sp->exp1); + sp2->next = sp->next; + sp->next = sp->stm1; + sp->stm1 = copystmt(thisreturn); + } + } + } + } + } + if (!checkconst(sp->exp2, 1)) { /* not part of an else-if */ + de1 = deadendblock(sp->stm1); + de2 = deadendblock(sp->stm2); + if (de2 && !de1) { + sp->exp1 = makeexpr_not(sp->exp1); + swapstmts(sp->stm1, sp->stm2); + de1 = 1, de2 = 0; + } + if (de1 && !de2 && sp->stm2) { + if (sp->stm2->kind == SK_IF && sp->stm2->exp2) { + freeexpr(sp->stm2->exp2); + sp->stm2->exp2 = NULL; + } + for (sp2 = sp->stm2; sp2->next; sp2 = sp2->next) ; + sp2->next = sp->next; + sp->next = sp->stm2; /* if (x) ESCAPE else foo => if (x) ESCAPE; foo */ + sp->stm2 = NULL; + } + } + sp->exp1 = fixexpr(sp->exp1, ENV_BOOL); + if (elimdeadcode > 1 && checkconst(sp->exp1, 0)) { + note("Eliminated \"if false\" statement [326]"); + splicestmt(sp, sp->stm2); + continue; + } else if (elimdeadcode > 1 && checkconst(sp->exp1, 1)) { + note("Eliminated \"if true\" statement [327]"); + splicestmt(sp, sp->stm1); + continue; + } + break; + + case SK_WHILE: + if (whilefgets && /* handle "while eof(f) do readln(f,...)" */ + sp->stm1 && + sp->stm1->kind == SK_ASSIGN && + sp->stm1->exp1->kind == EK_BICALL && + !strcmp(sp->stm1->exp1->val.s, "fgets") && + nosideeffects(sp->stm1->exp1->args[0], 1) && + nosideeffects(sp->stm1->exp1->args[1], 1) && + nosideeffects(sp->stm1->exp1->args[2], 1)) { + if ((sp->exp1->kind == EK_NOT && + sp->exp1->args[0]->kind == EK_BICALL && *eofname && + !strcmp(sp->exp1->args[0]->val.s, eofname) && + exprsame(sp->exp1->args[0]->args[0], + sp->stm1->exp1->args[2], 1)) || + (sp->exp1->kind == EK_EQ && + sp->exp1->args[0]->kind == EK_BICALL && + !strcmp(sp->exp1->args[0]->val.s, "feof") && + checkconst(sp->exp1->args[1], 0) && + exprsame(sp->exp1->args[0]->args[0], + sp->stm1->exp1->args[2], 1))) { + sp->stm1->exp1->val.type = tp_strptr; + sp->exp1 = makeexpr_rel(EK_NE, + sp->stm1->exp1, + makeexpr_nil()); + sp->stm1 = sp->stm1->next; + } + } + fixblock(&sp->stm1, sp); + sp->exp1 = fixexpr(sp->exp1, ENV_BOOL); + if (checkconst(sp->exp1, 1)) + infiniteloop(sp); + break; + + case SK_REPEAT: + fixblock(&sp->stm1, NULL); + sp->exp1 = fixexpr(sp->exp1, ENV_BOOL); + if (checkconst(sp->exp1, 1)) + infiniteloop(sp); + break; + + case SK_TRY: + save_tryblock = fixexpr_tryblock; + save_tryflag = fixexpr_tryflag; + fixexpr_tryblock = sp->exp1->val.i; + fixexpr_tryflag = 0; + fixblock(&sp->stm1, NULL); + if (fixexpr_tryflag) + sp->exp2 = makeexpr_long(1); + fixexpr_tryblock = save_tryblock; + fixexpr_tryflag = save_tryflag; + fixblock(&sp->stm2, NULL); + break; + + case SK_BODY: + fixblock(&sp->stm1, thisreturn); + break; + + case SK_CASE: + fixblock(&sp->stm1, NULL); + sp->exp1 = fixexpr(sp->exp1, ENV_EXPR); + if (!sp->stm1) { /* empty case */ + sp->kind = SK_ASSIGN; + continue; + } else if (sp->stm1->kind != SK_CASELABEL) { /* default only */ + for (sp2 = sp->stm1; sp2->next; sp2 = sp2->next) ; + sp2->next = sp->next; + sp->next = sp->stm1; + sp->kind = SK_ASSIGN; + sp->stm1 = NULL; + continue; + } + break; + + default: + fixblock(&sp->stm1, NULL); + fixblock(&sp->stm2, NULL); + sp->exp1 = fixexpr(sp->exp1, ENV_EXPR); + sp->exp2 = fixexpr(sp->exp2, ENV_EXPR); + sp->exp3 = fixexpr(sp->exp3, ENV_EXPR); + if (sp->next && + (sp->kind == SK_GOTO || + sp->kind == SK_BREAK || + sp->kind == SK_CONTINUE || + sp->kind == SK_RETURN) && + !haslabels(sp->next)) { + if (elimdeadcode) { + note("Deleting unreachable code [255]"); + while (sp->next && !haslabels(sp->next)) + eatstmt(&sp->next); + } else { + note("Code is unreachable [256]"); + } + } else if (sp->kind == SK_RETURN && + thisreturn && + thisreturn->kind == SK_RETURN && + exprsame(sp->exp1, thisreturn->exp1, 1)) { + eatstmt(spp); + continue; + } + break; + } + spp = &sp->next; + } + saveserial = curserial; +} + + + + +/* Convert comma expressions into multiple statements */ + +Static int checkcomma_expr(spp, exp) +Stmt **spp; +Expr **exp; +{ + Stmt *sp; + Expr *ex = *exp; + int i, res; + + switch (ex->kind) { + + case EK_COMMA: + if (spp) { + res = checkcomma_expr(spp, &ex->args[ex->nargs-1]); + for (i = ex->nargs-1; --i >= 0; ) { + sp = makestmt(SK_ASSIGN); + sp->exp1 = ex->args[i]; + sp->next = *spp; + *spp = sp; + res = checkcomma_expr(spp, &ex->args[i]); + } + *exp = ex->args[ex->nargs-1]; + } + return 1; + + case EK_COND: + if (isescape(ex->args[1]) && spp && + !isescape(ex->args[2])) { + swapexprs(ex->args[1], ex->args[2]); + ex->args[0] = makeexpr_not(ex->args[0]); + } + if (isescape(ex->args[2])) { + if (spp) { + res = checkcomma_expr(spp, &ex->args[1]); + if (ex->args[0]->kind == EK_ASSIGN) { + sp = makestmt(SK_ASSIGN); + sp->exp1 = copyexpr(ex->args[0]); + sp->next = makestmt(SK_IF); + sp->next->next = *spp; + *spp = sp; + res = checkcomma_expr(spp, &sp->exp1); + ex->args[0] = grabarg(ex->args[0], 0); + sp = sp->next; + } else { + sp = makestmt(SK_IF); + sp->next = *spp; + *spp = sp; + } + sp->exp1 = makeexpr_not(ex->args[0]); + sp->stm1 = makestmt(SK_ASSIGN); + sp->stm1->exp1 = eatcasts(ex->args[2]); + res = checkcomma_expr(&sp->stm1, &ex->args[2]); + res = checkcomma_expr(spp, &sp->exp1); + *exp = ex->args[1]; + } + return 1; + } + return checkcomma_expr(spp, &ex->args[0]); + + case EK_AND: + case EK_OR: + return checkcomma_expr(spp, &ex->args[0]); + + default: + res = 0; + for (i = ex->nargs; --i >= 0; ) { + res += checkcomma_expr(spp, &ex->args[i]); + } + return res; + + } +} + + + +Static void checkcommas(spp) +Stmt **spp; +{ + Stmt *sp; + int res; + + while ((sp = *spp)) { + checkcommas(&sp->stm1); + checkcommas(&sp->stm2); + switch (sp->kind) { + + case SK_ASSIGN: + case SK_IF: + case SK_CASE: + case SK_RETURN: + if (sp->exp1) + res = checkcomma_expr(spp, &sp->exp1); + break; + + case SK_WHILE: + /* handle the argument */ + break; + + case SK_REPEAT: + /* handle the argument */ + break; + + case SK_FOR: + if (sp->exp1) + res = checkcomma_expr(spp, &sp->exp1); + /* handle the other arguments */ + break; + + default: + break; + } + spp = &sp->next; + } +} + + + + +Static int checkvarchangeable(ex, mp) +Expr *ex; +Meaning *mp; +{ + switch (ex->kind) { + + case EK_VAR: + return (mp == (Meaning *)ex->val.i); + + case EK_DOT: + case EK_INDEX: + return checkvarchangeable(ex->args[0], mp); + + default: + return 0; + } +} + + + +int checkvarchangedexpr(ex, mp, addrokay) +Expr *ex; +Meaning *mp; +int addrokay; +{ + int i; + Meaning *mp3; + unsigned int safemask = 0; + + switch (ex->kind) { + + case EK_FUNCTION: + case EK_SPCALL: + if (ex->kind == EK_FUNCTION) { + i = 0; + mp3 = ((Meaning *)ex->val.i)->type->fbase; + } else { + i = 1; + if (ex->args[0]->val.type->kind != TK_PROCPTR) + return 1; + mp3 = ex->args[0]->val.type->basetype->fbase; + } + for ( ; i < ex->nargs && i < 16; i++) { + if (!mp3) { + intwarning("checkvarchangedexpr", "Too many arguments for EK_FUNCTION [266]"); + break; + } + if (mp3->kind == MK_PARAM && + (mp3->type->kind == TK_ARRAY || + mp3->type->kind == TK_STRING || + mp3->type->kind == TK_SET)) + safemask |= 1<<i; + if (mp3->kind == MK_VARPARAM && + mp3->type == tp_strptr && mp3->anyvarflag) + i++; + mp3 = mp3->xnext; + } + if (mp3) + intwarning("checkvarchangedexpr", "Too few arguments for EK_FUNCTION [267]"); + break; + + case EK_VAR: + if (mp == (Meaning *)ex->val.i) { + if ((mp->type->kind == TK_ARRAY || + mp->type->kind == TK_STRING || + mp->type->kind == TK_SET) && + ex->val.type->kind == TK_POINTER && !addrokay) + return 1; /* must be an implicit & */ + } + break; + + case EK_ADDR: + case EK_ASSIGN: + case EK_POSTINC: + case EK_POSTDEC: + if (checkvarchangeable(ex->args[0], mp)) + return 1; + break; + + case EK_BICALL: + if (structuredfunc(ex) && checkvarchangeable(ex->args[0], mp)) + return 1; + safemask = safemask_bicall(ex->val.s); + break; + /* In case calls to these functions were lazy and passed + the array rather than its (implicit) address. Other + BICALLs had better be careful about their arguments. */ + + case EK_PLUS: + if (addrokay) /* to keep from being scared by pointer */ + safemask = ~0; /* arithmetic on string being passed */ + break; /* to functions. */ + + default: + break; + } + for (i = 0; i < ex->nargs; i++) { + if (checkvarchangedexpr(ex->args[i], mp, safemask&1)) + return 1; + safemask >>= 1; + } + return 0; +} + + + +int checkvarchanged(sp, mp) +Stmt *sp; +Meaning *mp; +{ + if (mp->constqual) + return 0; + if (mp->varstructflag || !mp->ctx || mp->ctx->kind != MK_FUNCTION || + mp->volatilequal || alwayscopyvalues) + return 1; + while (sp) { + if (/* sp->kind == SK_GOTO || */ + sp->kind == SK_LABEL || + checkvarchanged(sp->stm1, mp) || + checkvarchanged(sp->stm2, mp) || + (sp->exp1 && checkvarchangedexpr(sp->exp1, mp, 1)) || + (sp->exp2 && checkvarchangedexpr(sp->exp2, mp, 1)) || + (sp->exp3 && checkvarchangedexpr(sp->exp3, mp, 1))) + return 1; + sp = sp->next; + } + return 0; +} + + + +int checkexprchanged(sp, ex) +Stmt *sp; +Expr *ex; +{ + Meaning *mp; + int i; + + for (i = 0; i < ex->nargs; i++) { + if (checkexprchanged(sp, ex->args[i])) + return 1; + } + switch (ex->kind) { + + case EK_VAR: + mp = (Meaning *)ex->val.i; + if (mp->kind == MK_CONST) + return 0; + else + return checkvarchanged(sp, mp); + + case EK_HAT: + case EK_INDEX: + case EK_SPCALL: + return 1; + + case EK_FUNCTION: + case EK_BICALL: + return !nosideeffects_func(ex); + + default: + return 0; + } +} + + + + + +/* Check if a variable always occurs with a certain offset added, e.g. "i+1" */ + +Static int theoffset, numoffsets, numzerooffsets; +#define BadOffset (-999) + +void checkvaroffsetexpr(ex, mp, myoffset) +Expr *ex; +Meaning *mp; +int myoffset; +{ + int i, nextoffset = 0; + Expr *ex2; + + if (!ex) + return; + switch (ex->kind) { + + case EK_VAR: + if (ex->val.i == (long)mp) { + if (myoffset == 0) + numzerooffsets++; + else if (numoffsets == 0 || myoffset == theoffset) { + theoffset = myoffset; + numoffsets++; + } else + theoffset = BadOffset; + } + break; + + case EK_PLUS: + ex2 = ex->args[ex->nargs-1]; + if (ex2->kind == EK_CONST && + ex2->val.type->kind == TK_INTEGER) { + nextoffset = ex2->val.i; + } + break; + + case EK_HAT: + case EK_POSTINC: + case EK_POSTDEC: + nextoffset = BadOffset; + break; + + case EK_ASSIGN: + checkvaroffsetexpr(ex->args[0], mp, BadOffset); + checkvaroffsetexpr(ex->args[1], mp, 0); + return; + + default: + break; + } + i = ex->nargs; + while (--i >= 0) + checkvaroffsetexpr(ex->args[i], mp, nextoffset); +} + + +void checkvaroffsetstmt(sp, mp) +Stmt *sp; +Meaning *mp; +{ + while (sp) { + checkvaroffsetstmt(sp->stm1, mp); + checkvaroffsetstmt(sp->stm1, mp); + checkvaroffsetexpr(sp->exp1, mp, 0); + checkvaroffsetexpr(sp->exp2, mp, 0); + checkvaroffsetexpr(sp->exp3, mp, 0); + sp = sp->next; + } +} + + +int checkvaroffset(sp, mp) +Stmt *sp; +Meaning *mp; +{ + if (mp->varstructflag || !mp->ctx || mp->ctx->kind != MK_FUNCTION) + return 0; + numoffsets = 0; + numzerooffsets = 0; + checkvaroffsetstmt(sp, mp); + if (numoffsets == 0 || theoffset == BadOffset || + numoffsets <= numzerooffsets * 3) + return 0; + else + return theoffset; +} + + + + +Expr *initfilevar(ex) +Expr *ex; +{ + Expr *ex2; + Meaning *mp; + char *name; + + if (ex->val.type->kind == TK_BIGFILE) { + ex2 = copyexpr(ex); + if (ex->kind == EK_VAR && + (mp = (Meaning *)ex->val.i)->kind == MK_VAR && + mp->ctx->kind != MK_FUNCTION && + !is_std_file(ex) && + literalfilesflag > 0 && + (literalfilesflag == 1 || + strlist_cifind(literalfiles, mp->name))) + name = mp->name; + else + name = ""; + return makeexpr_comma(makeexpr_assign(filebasename(ex), + makeexpr_nil()), + makeexpr_assign(makeexpr_dotq(ex2, "name", + tp_str255), + makeexpr_string(name))); + } else { + return makeexpr_assign(ex, makeexpr_nil()); + } +} + + +void initfilevars(mp, sppp, exbase) +Meaning *mp; +Stmt ***sppp; +Expr *exbase; +{ + Stmt *sp; + Type *tp; + Expr *ex; + + while (mp) { + if ((mp->kind == MK_VAR && mp->refcount > 0 && !mp->istemporary) || + mp->kind == MK_FIELD) { + tp = mp->type; + if (isfiletype(tp, -1)) { + mp->refcount++; + sp = makestmt(SK_ASSIGN); + sp->next = **sppp; + **sppp = sp; + if (exbase) + ex = makeexpr_dot(copyexpr(exbase), mp); + else + ex = makeexpr_var(mp); + sp->exp1 = initfilevar(copyexpr(ex)); + } else if (tp->kind == TK_RECORD) { + if (exbase) + ex = makeexpr_dot(copyexpr(exbase), mp); + else + ex = makeexpr_var(mp); + initfilevars(tp->fbase, sppp, ex); + freeexpr(ex); + } else if (tp->kind == TK_ARRAY) { + while (tp->kind == TK_ARRAY) + tp = tp->basetype; + if (isfiletype(tp, -1)) + note(format_s("Array of files %s should be initialized [257]", + mp->name)); + } + } + mp = mp->cnext; + } +} + + + + + +Static Stmt *p_body() +{ + Stmt *sp, **spp, *spbody, **sppbody, *spbase, *thereturn; + Meaning *mp; + Expr *ex; + int haspostamble; + long saveserial; + + if (verbose) + fprintf(logf, "%s, %d/%d: Translating %s (in %s)\n", + infname, inf_lnum, outf_lnum, + curctx->name, curctx->ctx->name); + notephase = 1; + spp = &spbase; + addstmt(SK_HEADER); + sp->exp1 = makeexpr_var(curctx); + checkkeyword(TOK_INLINE); + if (curtok != TOK_END && curtok != TOK_BEGIN && curtok != TOK_INLINE) { + if (curctx->kind == MK_FUNCTION || curctx->anyvarflag) + wexpecttok(TOK_BEGIN); + else + wexpecttok(TOK_END); + skiptotoken2(TOK_BEGIN, TOK_END); + } + if (curtok == TOK_END) { + gettok(); + spbody = NULL; + } else { + spbody = p_stmt(NULL, SF_FUNC); /* parse the procedure/program body */ + } + if (curtok == TOK_IDENT && curtokmeaning == curctx) { + gettok(); /* Modula-2 */ + } + notephase = 2; + saveserial = curserial; + curserial = 10000; + if (curctx->kind == MK_FUNCTION) { /* handle copy parameters */ + for (mp = curctx->type->fbase; mp; mp = mp->xnext) { + if (!mp->othername && mp->varstructflag) { + mp->othername = stralloc(format_s(name_COPYPAR, mp->name)); + mp->rectype = mp->type; + addstmt(SK_ASSIGN); + sp->exp1 = makeexpr_assign(makeexpr_var(mp), + makeexpr_name(mp->othername, mp->rectype)); + mp->refcount++; + } else if (mp->othername) { + if (checkvarchanged(spbody, mp)) { + addstmt(SK_ASSIGN); + sp->exp1 = makeexpr_assign(makeexpr_var(mp), + makeexpr_hat(makeexpr_name(mp->othername, + mp->rectype), 0)); + mp->refcount++; + } else { /* don't need to copy it after all */ + strchange(&mp->othername, mp->name); + ex = makeexpr_var(mp); + ex->val.type = mp->rectype; + replaceexpr(spbody, makeexpr_var(mp), makeexpr_hat(ex, 0)); + } + } + } + } + for (mp = curctx->cbase; mp; mp = mp->cnext) { + if (mp->kind == MK_LABEL && mp->val.i) { + addstmt(SK_IF); + sp->exp1 = makeexpr_bicall_1("setjmp", tp_int, + makeexpr_var(mp->xnext)); + sp->stm1 = makestmt(SK_GOTO); + sp->stm1->exp1 = makeexpr_name(format_s(name_LABEL, mp->name), + tp_integer); + } + } + *spp = spbody; + sppbody = spp; + while (*spp) + spp = &((*spp)->next); + haspostamble = 0; + initfilevars(curctx->cbase, &sppbody, NULL); + for (mp = curctx->cbase; mp; mp = mp->cnext) { + if (mp->kind == MK_VAR && mp->refcount > 0 && + isfiletype(mp->type, -1) && + !mp->istemporary) { + if (curctx->kind != MK_MODULE || curctx->anyvarflag) { + addstmt(SK_IF); /* close file variables */ + sp->exp1 = makeexpr_rel(EK_NE, filebasename(makeexpr_var(mp)), + makeexpr_nil()); + sp->stm1 = makestmt(SK_ASSIGN); + sp->stm1->exp1 = makeexpr_bicall_1("fclose", tp_void, + filebasename(makeexpr_var(mp))); + } + haspostamble = 1; + } + } + thereturn = &bogusreturn; + if (curctx->kind == MK_FUNCTION && curctx->type->basetype != tp_void) { + if ((haspostamble || !checkreturns(&spbase, 1)) && + curctx->cbase->refcount > 0) { /* add function return code */ + addstmt(SK_RETURN); + sp->exp1 = makeexpr_var(curctx->cbase); + } + thereturn = NULL; + } else if (curctx->kind == MK_MODULE && curctx->anyvarflag) { + addstmt(SK_ASSIGN); + sp->exp1 = makeexpr_bicall_1("exit", tp_void, + makeexpr_name("EXIT_SUCCESS", + tp_integer)); + thereturn = NULL; + } + if (debug>2) { fprintf(outf, "calling fixblock/usecommas on:\n"); dumpstmt(spbase, 5); } + curserial = saveserial; + sp = makestmt(SK_BODY); + sp->stm1 = spbase; + fixblock(&sp, thereturn); /* finishing touches to statements and expressions */ + spbase = sp->stm1; + FREE(sp); + if (usecommas != 1) + checkcommas(&spbase); /* unroll ugly EK_COMMA and EK_COND expressions */ + if (debug>1) { fprintf(outf, "p_body returns:\n"); dumpstmt(spbase, 5); } + notephase = 0; + return spbase; +} + + + + +#define checkWord() if (anywords) output(" "); anywords = 1 + +Static void out_function(func) +Meaning *func; +{ + Meaning *mp; + Symbol *sym; + int opts, anywords, spacing, saveindent; + + if (func->varstructflag) { + makevarstruct(func); + } + if (collectnest) { + for (mp = func->cbase; mp; mp = mp->cnext) { + if (mp->kind == MK_FUNCTION && mp->isforward) { + forward_decl(mp, 0); + } + } + for (mp = func->cbase; mp; mp = mp->cnext) { + if (mp->kind == MK_FUNCTION && mp->type && !mp->exported) { + pushctx(mp); + out_function(mp); /* generate the sub-procedures first */ + popctx(); + } + } + } + spacing = functionspace; + for (mp = func; mp->ctx->kind == MK_FUNCTION; mp = mp->ctx) { + if (spacing > minfuncspace) + spacing--; + } + outsection(spacing); + flushcomments(&func->comments, -1, 0); + if (usePPMacros == 1) { + forward_decl(func, 0); + outsection(minorspace); + } + opts = ODECL_HEADER; + anywords = 0; + if (func->namedfile) { + checkWord(); + if (useAnyptrMacros || ansiC < 2) + output("Inline"); + else + output("inline"); + } + if (!func->exported) { + if (func->ctx->kind == MK_FUNCTION) { + if (useAnyptrMacros) { + checkWord(); + output("Local"); + } else if (use_static) { + checkWord(); + output("static"); + } + } else if ((findsymbol(func->name)->flags & NEEDSTATIC) || + (use_static != 0 && !useAnyptrMacros)) { + checkWord(); + output("static"); + } else if (useAnyptrMacros) { + checkWord(); + output("Static"); + } + } + if (func->type->basetype != tp_void || ansiC != 0) { + checkWord(); + outbasetype(func->type, 0); + } + if (anywords) { + if (newlinefunctions) + opts |= ODECL_FUNCTION; + else + output(" "); + } + outdeclarator(func->type, func->name, opts); + if (fullprototyping == 0) { + saveindent = outindent; + moreindent(argindent); + out_argdecls(func->type); + outindent = saveindent; + } + for (mp = func->type->fbase; mp; mp = mp->xnext) { + if (mp->othername && strcmp(mp->name, mp->othername)) + mp->wasdeclared = 0; /* make sure we also declare the copy */ + } + func->wasdeclared = 1; + outcontext = func; + out_block((Stmt *)func->val.i, BR_FUNCTION, 10000); + if (useundef) { + anywords = 0; + for (mp = func->cbase; mp; mp = mp->cnext) { + if (mp->kind == MK_CONST && + mp->isreturn) { /* the was-#defined flag */ + if (!anywords) + outsection(minorspace); + anywords++; + output(format_s("#undef %s\n", mp->name)); + sym = findsymbol(mp->name); + sym->flags &= ~AVOIDNAME; + } + } + } + if (conserve_mem) { + free_stmt((Stmt *)func->val.i); /* is this safe? */ + func->val.i = 0; + forget_ctx(func, 0); + } + outsection(spacing); +} + + + + +void movetoend(mp) +Meaning *mp; +{ + Meaning **mpp; + + if (mp->ctx != curctx) { + intwarning("movetoend", "curctx is wrong [268]"); + } else { + mpp = &mp->ctx->cbase; /* move a meaning to end of its parent context */ + while (*mpp != mp) { + if (!*mpp) { + intwarning("movetoend", "meaning not on its context list [269]"); + return; + } + mpp = &(*mpp)->cnext; + } + *mpp = mp->cnext; /* Remove from present position in list */ + while (*mpp) + mpp = &(*mpp)->cnext; + *mpp = mp; /* Insert at end of list */ + mp->cnext = NULL; + curctxlast = mp; + } +} + + + +Static void scanfwdparams(mp) +Meaning *mp; +{ + Symbol *sym; + + mp = mp->type->fbase; + while (mp) { + sym = findsymbol(mp->name); + sym->flags |= FWDPARAM; + mp = mp->xnext; + } +} + + + +Static void p_function(isfunc) +int isfunc; +{ + Meaning *func; + Type *type; + Stmt *sp; + Strlist *sl, *comments, *savecmt; + int initializeattr = 0, isinline = 0; + + if ((sl = strlist_find(attrlist, "INITIALIZE")) != NULL) { + initializeattr = 1; + strlist_delete(&attrlist, sl); + } + if ((sl = strlist_find(attrlist, "OPTIMIZE")) != NULL && + sl->value != -1 && + !strcmp((char *)(sl->value), "INLINE")) { + isinline = 1; + strlist_delete(&attrlist, sl); + } + ignore_attributes(); + comments = extractcomment(&curcomments, -1, curserial); + changecomments(comments, -1, -1, -1, 0); + if (curctx->kind == MK_FUNCTION) { /* sub-procedure */ + savecmt = curcomments; + } else { + savecmt = NULL; + flushcomments(&curcomments, -1, -1); + } + curcomments = comments; + curserial = serialcount = 1; + gettok(); + if (!wexpecttok(TOK_IDENT)) + skiptotoken(TOK_IDENT); + if (curtokmeaning && curtokmeaning->ctx == curctx && + curtokmeaning->kind == MK_FUNCTION) { + func = curtokmeaning; + if (!func->isforward || func->val.i) + warning(format_s("Redeclaration of function %s [270]", func->name)); + skiptotoken(TOK_SEMI); + movetoend(func); + pushctx(func); + type = func->type; + } else { + func = addmeaning(curtoksym, MK_FUNCTION); + gettok(); + func->val.i = 0; + pushctx(func); + func->type = type = p_funcdecl(&isfunc, 0); + func->isfunction = isfunc; + func->namedfile = isinline; + type->meaning = func; + } + if (blockkind == TOK_EXPORT) + flushcomments(NULL, -1, -1); + wneedtok(TOK_SEMI); + if (initializeattr) { + sl = strlist_append(&initialcalls, format_s("%s()", func->name)); + sl->value = 1; + } + if (curtok == TOK_IDENT && !strcmp(curtokbuf, "C")) { + gettok(); + wneedtok(TOK_SEMI); + } + if (blockkind == TOK_IMPORT) { + strlist_empty(&curcomments); + if (curtok == TOK_IDENT && + (!strcicmp(curtokbuf, "FORWARD") || + strlist_cifind(externwords, curtokbuf) || + strlist_cifind(cexternwords, curtokbuf))) { + gettok(); + while (curtok == TOK_IDENT) + gettok(); + wneedtok(TOK_SEMI); + } + /* do nothing more */ + } else if (blockkind == TOK_EXPORT) { + func->isforward = 1; + scanfwdparams(func); + forward_decl(func, 1); + } else { + checkkeyword(TOK_INTERRUPT); + checkkeyword(TOK_INLINE); + if (curtok == TOK_INTERRUPT) { + note("Ignoring INTERRUPT keyword [258]"); + gettok(); + wneedtok(TOK_SEMI); + } + if (curtok == TOK_IDENT && !strcicmp(curtokbuf, "FORWARD")) { + func->isforward = 1; + scanfwdparams(func); + gettok(); + if (func->ctx->kind != MK_FUNCTION) { + outsection(minorspace); + flushcomments(NULL, -1, -1); + forward_decl(func, 0); + outsection(minorspace); + } + } else if (curtok == TOK_IDENT && + (strlist_cifind(externwords, curtokbuf) || + strlist_cifind(cexternwords, curtokbuf))) { + if (*externalias && my_strchr(externalias, '%')) { + strchange(&func->name, format_s(externalias, func->name)); + } else if (strlist_cifind(cexternwords, curtokbuf)) { + if (func->name[0] == '_') + strchange(&func->name, func->name + 1); + if (func->name[strlen(func->name)-1] == '_') + func->name[strlen(func->name)-1] = 0; + } + func->isforward = 1; /* for Oregon Software Pascal-2 */ + func->exported = 1; + gettok(); + while (curtok == TOK_IDENT) + gettok(); + outsection(minorspace); + flushcomments(NULL, -1, -1); + scanfwdparams(func); + forward_decl(func, 1); + outsection(minorspace); + } else if (curtok == TOK_IDENT) { + wexpecttok(TOK_BEGIN); /* print warning */ + gettok(); + outsection(minorspace); + flushcomments(NULL, -1, -1); + scanfwdparams(func); + forward_decl(func, 1); + outsection(minorspace); + } else { + if (func->ctx->kind == MK_FUNCTION) + func->ctx->needvarstruct = 1; + func->comments = curcomments; + curcomments = NULL; + p_block(TOK_FUNCTION); + echoprocname(func); + changecomments(curcomments, -1, curserial, -1, 10000); + sp = p_body(); + func->ctx->needvarstruct = 0; + func->val.i = (long)sp; + strlist_mix(&func->comments, curcomments); + curcomments = NULL; + if (func->ctx->kind != MK_FUNCTION || !collectnest) { + out_function(func); /* output top-level procedures immediately */ + } /* (sub-procedures are output later) */ + } + if (!wneedtok(TOK_SEMI)) + skippasttoken(TOK_SEMI); + } + strlist_mix(&curcomments, savecmt); + popctx(); +} + + + +Static void out_include(name, quoted) +char *name; +int quoted; +{ + if (*name == '"' || *name == '<') + output(format_s("#include %s\n", name)); + else if (quoted) + output(format_s("#include \"%s\"\n", name)); + else + output(format_s("#include <%s>\n", name)); +} + + +Static void cleanheadername(dest, name) +char *dest, *name; +{ + char *cp; + int len; + + if (*name == '<' || *name == '"') + name++; + cp = my_strrchr(name, '/'); + if (cp) + cp++; + else + cp = name; + strcpy(dest, cp); + len = strlen(dest); + if (dest[len-1] == '>' || dest[len-1] == '"') + dest[len-1] = 0; +} + + + + +Static int tryimport(sym, fname, ext, need) +Symbol *sym; +char *fname, *ext; +int need; +{ + int found = 0; + Meaning *savectx, *savectxlast; + + savectx = curctx; + savectxlast = curctxlast; + curctx = nullctx; + curctxlast = curctx->cbase; + while (curctxlast && curctxlast->cnext) + curctxlast = curctxlast->cnext; + if (p_search(fname, ext, need)) { + curtokmeaning = sym->mbase; + while (curtokmeaning && !curtokmeaning->isactive) + curtokmeaning = curtokmeaning->snext; + if (curtokmeaning) + found = 1; + } + curctx = savectx; + curctxlast = savectxlast; + return found; +} + + + +Static void p_import(inheader) +int inheader; +{ + Strlist *sl; + Symbol *sym; + char *name; + int found, isfrom = (curtok == TOK_FROM); + + outsection(minorspace); + do { + gettok(); + if (!wexpecttok(TOK_IDENT)) { + skiptotoken(TOK_SEMI); + break; + } + sym = curtoksym; + if (curtokmeaning && curtokmeaning->kind == MK_MODULE) { + found = 1; + } else if (strlist_cifind(permimports, sym->name)) { + found = 2; /* built-in module, there already! */ + } else { + found = 0; + sl = strlist_cifind(importfrom, sym->name); + name = (sl) ? format_none((char *)sl->value) : NULL; + if (name) { + if (tryimport(sym, name, "pas", 1)) + found = 1; + } else { + for (sl = importdirs; sl && !found; sl = sl->next) { + if (tryimport(sym, format_s(sl->s, curtokcase), NULL, 0)) + found = 1; + } + } + } + if (found == 1) { + if (!inheader) { + sl = strlist_cifind(includefrom, curtokmeaning->name); + name = (sl) ? (char *)sl->value : + format_ss(*headerfnfmt2 ? headerfnfmt2 : headerfnfmt, + infname, curtokmeaning->name); + if (name && !strlist_find(includedfiles, name)) { + strlist_insert(&includedfiles, name); + if (*name_HSYMBOL) + output(format_s("#ifndef %s\n", format_s(name_HSYMBOL, sym->name))); + out_include(name, quoteincludes); + if (*name_HSYMBOL) + output("#endif\n"); + outsection(minorspace); + } + } + import_ctx(curtokmeaning); + } else if (curtokmeaning) { + /* Modula-2, importing a single ident */ + /* Ignored for now, since we always import whole modules */ + } else if (found == 0) { + warning(format_s("Could not find module %s [271]", sym->name)); + if (!inheader) { + out_include(format_ss(*headerfnfmt2?headerfnfmt2:headerfnfmt, + sym->name, sym->name), + quoteincludes); + } + } + gettok(); + } while (curtok == TOK_COMMA); + if (isfrom) { + checkkeyword(TOK_IMPORT); + if (wneedtok(TOK_IMPORT)) { + do { + gettok(); + if (curtok == TOK_IDENT) + gettok(); + } while (curtok == TOK_COMMA); + } + } + if (!wneedtok(TOK_SEMI)) + skippasttoken(TOK_SEMI); + outsection(minorspace); +} + + + + +void do_include(blkind) +Token blkind; +{ + FILE *oldfile = outf; + int savelnum = outf_lnum; + char fname[256]; + + outsection(majorspace); + strcpy(fname, curtokbuf); + removesuffix(fname); + strcat(fname, ".c"); + if (!strcmp(fname, codefname)) { + warning("Include file name conflict! [272]"); + badinclude(); + return; + } + saveoldfile(fname); + outf = fopen(fname, "w"); + if (!outf) { + outf = oldfile; + perror(fname); + badinclude(); + return; + } + outf_lnum = 1; + if (nobanner) + output("\n"); + else + output(format_ss("\n/* Include file %s from %s */\n\n", + fname, codefname)); + if (blkind == TOK_END) + gettok(); + else + curtok = blkind; + p_block(blockkind); + if (nobanner) + output("\n"); + else + output("\n\n/* End. */\n\n"); + fclose(outf); + outf = oldfile; + outf_lnum = savelnum; + if (curtok != TOK_EOF) { + warning("Junk at end of include file ignored [273]"); + } + outsection(majorspace); + if (*includefnfmt) + out_include(format_s(includefnfmt, fname), 1); + else + out_include(fname, 1); + outsection(majorspace); + pop_input(); + p2c_getline(); + gettok(); +} + + + + +/* blockkind is one of: + TOK_PROGRAM: Global declarations of a program + TOK_FUNCTION: Declarations local to a procedure or function + TOK_IMPORT: Import text read from a module + TOK_EXPORT: Export section of a module + TOK_IMPLEMENT: Implementation section of a module + TOK_END: None of the above +*/ + +void p_block(blkind) +Token blkind; +{ + Token saveblockkind = blockkind; + Token lastblockkind = TOK_END; + + blockkind = blkind; + for (;;) { + while (curtok == TOK_INTFONLY) { + include_as_import(); + gettok(); + } + if (curtok == TOK_CONST || curtok == TOK_TYPE || + curtok == TOK_VAR || curtok == TOK_VALUE) { + while (curtok == TOK_CONST || curtok == TOK_TYPE || + curtok == TOK_VAR || curtok == TOK_VALUE) { + lastblockkind = curtok; + switch (curtok) { + + case TOK_CONST: + p_constdecl(); + break; + + case TOK_TYPE: + p_typedecl(); + break; + + case TOK_VAR: + p_vardecl(); + break; + + case TOK_VALUE: + p_valuedecl(); + break; + + default: + break; + } + } + if ((blkind == TOK_PROGRAM || + blkind == TOK_EXPORT || + blkind == TOK_IMPLEMENT) && + (curtok != TOK_BEGIN || !mainlocals)) { + outsection(majorspace); + if (declarevars(curctx, 0)) + outsection(majorspace); + } + } else { + checkmodulewords(); + checkkeyword(TOK_SEGMENT); + if (curtok == TOK_SEGMENT) { + note("SEGMENT or OVERLAY keyword ignored [259]"); + gettok(); + } + p_attributes(); + switch (curtok) { + + case TOK_LABEL: + p_labeldecl(); + break; + + case TOK_IMPORT: + case TOK_FROM: + p_import(0); + break; + + case TOK_EXPORT: + do { + gettok(); + checkkeyword(TOK_QUALIFIED); + if (curtok == TOK_QUALIFIED) + gettok(); + wneedtok(TOK_IDENT); + } while (curtok == TOK_COMMA); + if (!wneedtok(TOK_SEMI)) + skippasttoken(TOK_SEMI); + break; + + case TOK_MODULE: + p_nested_module(); + break; + + case TOK_PROCEDURE: + p_function(0); + break; + + case TOK_FUNCTION: + p_function(1); + break; + + case TOK_INCLUDE: + if (blockkind == TOK_PROGRAM || + blockkind == TOK_IMPLEMENT || + (blockkind == TOK_FUNCTION && !collectnest)) { + do_include(lastblockkind); + } else { + badinclude(); + } + break; + + default: + if (curtok == TOK_BEGIN && blockkind == TOK_IMPORT) { + warning("BEGIN encountered in interface text [274]"); + skipparens(); + if (curtok == TOK_SEMI) + gettok(); + break; + } + blockkind = saveblockkind; + return; + } + lastblockkind = TOK_END; + } + } +} + + + + +Static void skipunitheader() +{ + if (curtok == TOK_LPAR || curtok == TOK_LBR) { + skipparens(); + } +} + + +Static void skiptomodule() +{ + skipping_module++; + while (curtok != TOK_MODULE) { + if (curtok == TOK_END) { + gettok(); + if (curtok == TOK_DOT) + break; + } else + gettok(); + } + skipping_module--; +} + + + +Static void p_moduleinit(mod) +Meaning *mod; +{ + Stmt *sp; + Strlist *sl; + + if (curtok != TOK_BEGIN && curtok != TOK_END) { + wexpecttok(TOK_END); + skiptotoken2(TOK_BEGIN, TOK_END); + } + if (curtok == TOK_BEGIN || initialcalls) { + echoprocname(mod); + sp = p_body(); + strlist_mix(&mod->comments, curcomments); + curcomments = NULL; + if (ansiC != 0) + output("void "); + output(format_s(name_UNITINIT, mod->name)); + if (void_args) + output("(void)\n"); + else + output("()\n"); + outcontext = mod; + out_block(sp, BR_FUNCTION, 10000); + free_stmt(sp); + /* The following must come after out_block! */ + sl = strlist_append(&initialcalls, + format_s("%s()", + format_s(name_UNITINIT, mod->name))); + sl->value = 1; + } else + wneedtok(TOK_END); +} + + + +Static void p_nested_module() +{ + Meaning *mp; + + if (!modula2) { + note("Ignoring nested module [260]"); + p_module(1, 0); + return; + } + note("Nested modules not fully supported [261]"); + checkmodulewords(); + wneedtok(TOK_MODULE); + wexpecttok(TOK_IDENT); + mp = addmeaning(curtoksym, MK_MODULE); + mp->anyvarflag = 0; + gettok(); + skipunitheader(); + wneedtok(TOK_SEMI); + p_block(TOK_IMPLEMENT); + p_moduleinit(mp); + if (curtok == TOK_IDENT) + gettok(); + wneedtok(TOK_SEMI); +} + + + +Static int p_module(ignoreit, isdefn) +int ignoreit; +int isdefn; /* Modula-2: 0=local module, 1=DEFINITION, 2=IMPLEMENTATION */ +{ + Meaning *mod, *mp; + Strlist *sl; + int kind; + char *cp; + + checkmodulewords(); + wneedtok(TOK_MODULE); + wexpecttok(TOK_IDENT); + if (curtokmeaning && curtokmeaning->kind == MK_MODULE && isdefn == 2) { + mod = curtokmeaning; + import_ctx(mod); + for (mp = mod->cbase; mp; mp = mp->cnext) + if (mp->kind == MK_FUNCTION) + mp->isforward = 1; + } else { + mod = addmeaning(curtoksym, MK_MODULE); + } + mod->anyvarflag = 0; + pushctx(mod); + gettok(); + skipunitheader(); + wneedtok(TOK_SEMI); + if (ignoreit || + (requested_module && strcicmp(requested_module, mod->name))) { + if (!quietmode) + if (outf == stdout) + fprintf(stderr, "Skipping over module \"%s\"\n", mod->name); + else + printf("Skipping over module \"%s\"\n", mod->name); + checkmodulewords(); + while (curtok == TOK_IMPORT || curtok == TOK_FROM) + p_import(1); + checkmodulewords(); + if (curtok == TOK_EXPORT) + gettok(); + strlist_empty(&curcomments); + p_block(TOK_IMPORT); + setup_module(mod->sym->name, 0); + checkmodulewords(); + if (curtok == TOK_IMPLEMENT) { + skiptomodule(); + } else { + if (!wneedtok(TOK_END)) + skippasttoken(TOK_END); + if (curtok == TOK_SEMI) + gettok(); + } + popctx(); + strlist_empty(&curcomments); + return 0; + } + found_module = 1; + if (isdefn != 2) { + if (!*hdrfname) { + sl = strlist_cifind(includefrom, mod->name); + if (sl) + cleanheadername(hdrfname, (char *)sl->value); + else + strcpy(hdrfname, format_ss(headerfnfmt, infname, mod->name)); + } + saveoldfile(hdrfname); + hdrf = fopen(hdrfname, "w"); + if (!hdrf) { + perror(hdrfname); + error("Could not open output file for header"); + } + outsection(majorspace); + if (usevextern && my_strchr(name_GSYMBOL, '%')) + output(format_s("#define %s\n", format_s(name_GSYMBOL, mod->sym->name))); + if (*selfincludefmt) + cp = format_s(selfincludefmt, hdrfname); + else + cp = hdrfname; + out_include(cp, quoteincludes); + outsection(majorspace); + select_outfile(hdrf); + if (nobanner) + output("\n"); + else + output(format_s("/* Header for module %s, generated by p2c */\n", + mod->name)); + if (*name_HSYMBOL) { + cp = format_s(name_HSYMBOL, mod->sym->name); + output(format_ss("#ifndef %s\n#define %s\n", cp, cp)); + } + outsection(majorspace); + checkmodulewords(); + while (curtok == TOK_IMPORT || curtok == TOK_FROM) + p_import(0); + checkmodulewords(); + if (curtok == TOK_EXPORT) + gettok(); + checkmodulewords(); + while (curtok == TOK_IMPORT || curtok == TOK_FROM) + p_import(0); + outsection(majorspace); + if (usevextern) { + output(format_s("#ifdef %s\n# define vextern\n#else\n", + format_s(name_GSYMBOL, mod->sym->name))); + output("# define vextern extern\n#endif\n"); + } + checkmodulewords(); + p_block(TOK_EXPORT); + flushcomments(NULL, -1, -1); + setup_module(mod->sym->name, 1); + outsection(majorspace); + if (usevextern) + output("#undef vextern\n"); + outsection(minorspace); + if (*name_HSYMBOL) + output(format_s("#endif /*%s*/\n", format_s(name_HSYMBOL, mod->sym->name))); + if (nobanner) + output("\n"); + else + output("\n/* End. */\n\n"); + select_outfile(codef); + fclose(hdrf); + *hdrfname = 0; + redeclarevars(mod); + declarevars(mod, 0); + } + checkmodulewords(); + if (curtok != TOK_END) { + if (!modula2 && !implementationmodules) + wneedtok(TOK_IMPLEMENT); + import_ctx(mod); + p_block(TOK_IMPLEMENT); + flushcomments(NULL, -1, -1); + p_moduleinit(mod); + kind = 1; + } else { + kind = 0; + if (!wneedtok(TOK_END)) + skippasttoken(TOK_END); + } + if (curtok == TOK_IDENT) + gettok(); + if (curtok == TOK_SEMI) + gettok(); + popctx(); + return kind; +} + + + + +int p_search(fname, ext, need) +char *fname, *ext; +int need; +{ + char infnbuf[300]; + FILE *fp; + Meaning *mod; + int savesysprog, savecopysource; + int outerimportmark, importmark, mypermflag; + + strcpy(infnbuf, fname); + fixfname(infnbuf, ext); + fp = fopen(infnbuf, "r"); + if (!fp) { + if (need) + perror(infnbuf); + if (logf) + fprintf(logf, "(Unable to open search file \"%s\")\n", infnbuf); + return 0; + } + flushcomments(NULL, -1, -1); + ignore_directives++; + savesysprog = sysprog_flag; + sysprog_flag |= 3; + savecopysource = copysource; + copysource = 0; + outerimportmark = numimports; /*obsolete*/ + importmark = push_imports(); + clearprogress(); + push_input_file(fp, infnbuf, 0); + do { + strlist_empty(&curcomments); + checkmodulewords(); + permflag = 0; + if (curtok == TOK_DEFINITION) { + gettok(); + checkmodulewords(); + } else if (curtok == TOK_IMPLEMENT && modula2) { + gettok(); + checkmodulewords(); + warning("IMPLEMENTATION module in search text! [275]"); + } + if (!wneedtok(TOK_MODULE)) + break; + if (!wexpecttok(TOK_IDENT)) + break; + mod = addmeaning(curtoksym, MK_MODULE); + mod->anyvarflag = 0; + if (!quietmode && !showprogress) + if (outf == stdout) + fprintf(stderr, "Reading import text for \"%s\"\n", mod->name); + else + printf("Reading import text for \"%s\"\n", mod->name); + if (verbose) + fprintf(logf, "%s, %d/%d: Reading import text for \"%s\"\n", + infname, inf_lnum, outf_lnum, mod->name); + pushctx(mod); + gettok(); + skipunitheader(); + wneedtok(TOK_SEMI); + mypermflag = permflag; + if (debug>0) printf("Found module %s\n", mod->name); + checkmodulewords(); + while (curtok == TOK_IMPORT || curtok == TOK_FROM) + p_import(1); + checkmodulewords(); + if (curtok == TOK_EXPORT) + gettok(); + strlist_empty(&curcomments); + p_block(TOK_IMPORT); + setup_module(mod->sym->name, 0); + if (mypermflag) { + strlist_add(&permimports, mod->sym->name)->value = (long)mod; + perm_import(mod); + } + checkmodulewords(); + if (curtok == TOK_END) { + gettok(); + if (curtok == TOK_SEMI) + gettok(); + } else { + wexpecttok(TOK_IMPLEMENT); + if (importall) { + skiptomodule(); + } + } + popctx(); + } while (curtok == TOK_MODULE); + pop_imports(importmark); + unimport(outerimportmark); + sysprog_flag = savesysprog; + copysource = savecopysource; + ignore_directives--; + pop_input(); + strlist_empty(&curcomments); + clearprogress(); + return 1; +} + + + + +void p_program() +{ + Meaning *prog; + Stmt *sp; + int nummods, isdefn = 0; + + flushcomments(NULL, -1, -1); + output(format_s("\n#include %s\n", p2c_h_name)); + outsection(majorspace); + p_attributes(); + ignore_attributes(); + checkmodulewords(); + if (modula2) { + if (curtok == TOK_MODULE) { + curtok = TOK_PROGRAM; + } else { + if (curtok == TOK_DEFINITION) { + isdefn = 1; + gettok(); + checkmodulewords(); + } else if (curtok == TOK_IMPLEMENT) { + isdefn = 2; + gettok(); + checkmodulewords(); + } + } + } + switch (curtok) { + + case TOK_MODULE: + if (implementationmodules) + isdefn = 2; + nummods = 0; + while (curtok == TOK_MODULE) { + if (p_module(0, isdefn)) { + nummods++; + if (nummods == 2 && !requested_module) + warning("Multiple modules in one source file may not work correctly [276]"); + } + } + wneedtok(TOK_DOT); + break; + + default: + if (curtok == TOK_PROGRAM) { + gettok(); + if (!wexpecttok(TOK_IDENT)) + skiptotoken(TOK_IDENT); + prog = addmeaning(curtoksym, MK_MODULE); + gettok(); + if (curtok == TOK_LPAR) { + while (curtok != TOK_RPAR) { + if (curtok == TOK_IDENT && + strcicmp(curtokbuf, "INPUT") && + strcicmp(curtokbuf, "OUTPUT") && + strcicmp(curtokbuf, "KEYBOARD") && + strcicmp(curtokbuf, "LISTING")) { + if (literalfilesflag == 2) { + strlist_add(&literalfiles, curtokbuf); + } else + note(format_s("Unexpected name \"%s\" in program header [262]", + curtokcase)); + } + gettok(); + } + gettok(); + } + if (curtok == TOK_LBR) + skipparens(); + wneedtok(TOK_SEMI); + } else { + prog = addmeaning(findsymbol("program"), MK_MODULE); + } + prog->anyvarflag = 1; + if (requested_module && strcicmp(requested_module, prog->name) && + strcicmp(requested_module, "program")) { + for (;;) { + skiptomodule(); + if (curtok == TOK_DOT) + break; + (void)p_module(0, 2); + } + gettok(); + break; + } + pushctx(prog); + p_block(TOK_PROGRAM); + echoprocname(prog); + flushcomments(NULL, -1, -1); + if (curtok != TOK_EOF) { + sp = p_body(); + strlist_mix(&prog->comments, curcomments); + curcomments = NULL; + if (fullprototyping > 0) { + output(format_sss("main%s(int argc,%s%s *argv[])", + spacefuncs ? " " : "", + spacecommas ? " " : "", + charname)); + } else { + output("main"); + if (spacefuncs) + output(" "); + output("(argc,"); + if (spacecommas) + output(" "); + output("argv)\n"); + singleindent(argindent); + output("int argc;\n"); + singleindent(argindent); + output(format_s("%s *argv[];\n", charname)); + } + outcontext = prog; + out_block(sp, BR_FUNCTION, 10000); + free_stmt(sp); + popctx(); + if (curtok == TOK_SEMI) + gettok(); + else + wneedtok(TOK_DOT); + } + break; + + } + if (curtok != TOK_EOF) { + warning("Junk at end of input file ignored [277]"); + } +} + + + + + +/* End. */ + + diff --git a/MultiSource/Benchmarks/MallocBench/p2c/pexpr.c b/MultiSource/Benchmarks/MallocBench/p2c/pexpr.c new file mode 100644 index 00000000..ed8c7c50 --- /dev/null +++ b/MultiSource/Benchmarks/MallocBench/p2c/pexpr.c @@ -0,0 +1,3626 @@ +/* "p2c", a Pascal to C translator. + Copyright (C) 1989, 1990, 1991 Free Software Foundation. + Author's address: daveg@csvax.caltech.edu; 256-80 Caltech/Pasadena CA 91125. + +This program is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation (any version). + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; see the file COPYING. If not, write to +the Free Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ + + + +#define PROTO_PEXPR_C +#include "trans.h" + + + + +Expr *dots_n_hats(ex, target) +Expr *ex; +Type *target; +{ + Expr *ex2, *ex3; + Type *tp, *tp2; + Meaning *mp, *tvar; + int hassl; + + for (;;) { + if ((ex->val.type->kind == TK_PROCPTR || + ex->val.type->kind == TK_CPROCPTR) && + curtok != TOK_ASSIGN && + ((mp = (tp2 = ex->val.type)->basetype->fbase) == NULL || + (mp->isreturn && mp->xnext == NULL) || + curtok == TOK_LPAR) && + (tp2->basetype->basetype != tp_void || target == tp_void) && + (!target || (target->kind != TK_PROCPTR && + target->kind != TK_CPROCPTR))) { + hassl = tp2->escale; + ex2 = ex; + ex3 = copyexpr(ex2); + if (hassl != 0) + ex3 = makeexpr_cast(makeexpr_dotq(ex3, "proc", tp_anyptr), + makepointertype(tp2->basetype)); + ex = makeexpr_un(EK_SPCALL, tp2->basetype->basetype, ex3); + if (mp && mp->isreturn) { /* pointer to buffer for return value */ + tvar = makestmttempvar(ex->val.type->basetype, + (ex->val.type->basetype->kind == TK_STRING) ? name_STRING : name_TEMP); + insertarg(&ex, 1, makeexpr_addr(makeexpr_var(tvar))); + mp = mp->xnext; + } + if (mp) { + if (wneedtok(TOK_LPAR)) { + ex = p_funcarglist(ex, mp, 0, 0); + skipcloseparen(); + } + } else if (curtok == TOK_LPAR) { + gettok(); + if (!wneedtok(TOK_RPAR)) + skippasttoken(TOK_RPAR); + } + if (hassl != 1 || hasstaticlinks == 2) { + freeexpr(ex2); + } else { + ex2 = makeexpr_dotq(ex2, "link", tp_anyptr), + ex3 = copyexpr(ex); + insertarg(&ex3, ex3->nargs, copyexpr(ex2)); + tp = maketype(TK_FUNCTION); + tp->basetype = tp2->basetype->basetype; + tp->fbase = tp2->basetype->fbase; + tp->issigned = 1; + ex3->args[0]->val.type = makepointertype(tp); + ex = makeexpr_cond(makeexpr_rel(EK_NE, ex2, makeexpr_nil()), + ex3, ex); + } + if (tp2->basetype->fbase && + tp2->basetype->fbase->isreturn && + tp2->basetype->fbase->kind == MK_VARPARAM) + ex = makeexpr_hat(ex, 0); /* returns pointer to structured result */ + continue; + } + switch (curtok) { + + case TOK_HAT: + case TOK_ADDR: + gettok(); + ex = makeexpr_hat(ex, 1); + break; + + case TOK_LBR: + do { + gettok(); + ex2 = p_ord_expr(); + ex = p_index(ex, ex2); + } while (curtok == TOK_COMMA); + if (!wneedtok(TOK_RBR)) + skippasttotoken(TOK_RBR, TOK_SEMI); + break; + + case TOK_DOT: + gettok(); + if (!wexpecttok(TOK_IDENT)) + break; + if (ex->val.type->kind == TK_STRING) { + if (!strcicmp(curtokbuf, "LENGTH")) { + ex = makeexpr_bicall_1("strlen", tp_int, ex); + } else if (!strcicmp(curtokbuf, "BODY")) { + /* nothing to do */ + } + gettok(); + break; + } + mp = curtoksym->fbase; + while (mp && mp->rectype != ex->val.type) + mp = mp->snext; + if (mp) + ex = makeexpr_dot(ex, mp); + else { + warning(format_s("No field called %s in that record [288]", curtokbuf)); + ex = makeexpr_dotq(ex, curtokcase, tp_integer); + } + gettok(); + break; + + case TOK_COLONCOLON: + gettok(); + if (wexpecttok(TOK_IDENT)) { + ex = pascaltypecast(curtokmeaning->type, ex); + gettok(); + } + break; + + default: + return ex; + } + } +} + + +Expr *p_index(ex, ex2) +Expr *ex, *ex2; +{ + Expr *ex3; + Type *tp, *ot; + Meaning *mp; + int bits; + + tp = ex->val.type; + if (tp->kind == TK_STRING) { + if (checkconst(ex2, 0)) /* is it "s[0]"? */ + return makeexpr_bicall_1("strlen", tp_char, ex); + else + return makeexpr_index(ex, ex2, makeexpr_long(1)); + } else if (tp->kind == TK_ARRAY || + tp->kind == TK_SMALLARRAY) { + if (tp->smax) { + ord_range_expr(tp->indextype, &ex3, NULL); + ex2 = makeexpr_minus(ex2, copyexpr(ex3)); + if (!nodependencies(ex2, 0) && + *getbitsname == '*') { + mp = makestmttempvar(tp_integer, name_TEMP); + ex3 = makeexpr_assign(makeexpr_var(mp), ex2); + ex2 = makeexpr_var(mp); + } else + ex3 = NULL; + ex = makeexpr_bicall_3(getbitsname, tp_int, + ex, ex2, + makeexpr_long(tp->escale)); + if (tp->kind == TK_ARRAY) { + if (tp->basetype == tp_sshort) + bits = 4; + else + bits = 3; + insertarg(&ex, 3, makeexpr_long(bits)); + } + ex = makeexpr_comma(ex3, ex); + ot = ord_type(tp->smax->val.type); + if (ot->kind == TK_ENUM && ot->meaning && useenum) + ex = makeexpr_cast(ex, tp->smax->val.type); + ex->val.type = tp->smax->val.type; + return ex; + } else { + ord_range_expr(ex->val.type->indextype, &ex3, NULL); + if (debug>2) { fprintf(outf, "ord_range_expr returns "); dumpexpr(ex3); fprintf(outf, "\n"); } + return makeexpr_index(ex, ex2, copyexpr(ex3)); + } + } else { + warning("Index on a non-array variable [287]"); + return makeexpr_bin(EK_INDEX, tp_integer, ex, ex2); + } +} + + +Expr *fake_dots_n_hats(ex) +Expr *ex; +{ + for (;;) { + switch (curtok) { + + case TOK_HAT: + case TOK_ADDR: + if (ex->val.type->kind == TK_POINTER) + ex = makeexpr_hat(ex, 0); + else { + ex->val.type = makepointertype(ex->val.type); + ex = makeexpr_un(EK_HAT, ex->val.type->basetype, ex); + } + gettok(); + break; + + case TOK_LBR: + do { + gettok(); + ex = makeexpr_bin(EK_INDEX, tp_integer, ex, p_expr(tp_integer)); + } while (curtok == TOK_COMMA); + if (!wneedtok(TOK_RBR)) + skippasttotoken(TOK_RBR, TOK_SEMI); + break; + + case TOK_DOT: + gettok(); + if (!wexpecttok(TOK_IDENT)) + break; + ex = makeexpr_dotq(ex, curtokcase, tp_integer); + gettok(); + break; + + case TOK_COLONCOLON: + gettok(); + if (wexpecttok(TOK_IDENT)) { + ex = pascaltypecast(curtokmeaning->type, ex); + gettok(); + } + break; + + default: + return ex; + } + } +} + + + +Static void bindnames(ex) +Expr *ex; +{ + int i; + Symbol *sp; + Meaning *mp; + + if (ex->kind == EK_NAME) { + sp = findsymbol_opt(fixpascalname(ex->val.s)); + if (sp) { + mp = sp->mbase; + while (mp && !mp->isactive) + mp = mp->snext; + if (mp && !strcmp(mp->name, ex->val.s)) { + ex->kind = EK_VAR; + ex->val.i = (long)mp; + ex->val.type = mp->type; + } + } + } + i = ex->nargs; + while (--i >= 0) + bindnames(ex->args[i]); +} + + + +void var_reference(mp) +Meaning *mp; +{ + Meaning *mp2; + + mp->refcount++; + if (mp->ctx && mp->ctx->kind == MK_FUNCTION && + mp->ctx->needvarstruct && + (mp->kind == MK_VAR || + mp->kind == MK_VARREF || + mp->kind == MK_VARMAC || + mp->kind == MK_PARAM || + mp->kind == MK_VARPARAM || + (mp->kind == MK_CONST && + (mp->type->kind == TK_ARRAY || + mp->type->kind == TK_RECORD)))) { + if (debug>1) { fprintf(outf, "varstruct'ing %s\n", mp->name); } + if (!mp->varstructflag) { + mp->varstructflag = 1; + if (mp->constdefn && /* move init code into function body */ + mp->kind != MK_VARMAC) { + mp2 = addmeaningafter(mp, curtoksym, MK_VAR); + curtoksym->mbase = mp2->snext; /* hide this fake variable */ + mp2->snext = mp; /* remember true variable */ + mp2->type = mp->type; + mp2->constdefn = mp->constdefn; + mp2->isforward = 1; /* declare it "static" */ + mp2->refcount++; /* so it won't be purged! */ + mp->constdefn = NULL; + mp->isforward = 0; + } + } + for (mp2 = curctx->ctx; mp2 != mp->ctx; mp2 = mp2->ctx) + mp2->varstructflag = 1; + mp2->varstructflag = 1; + } +} + + + +Static Expr *p_variable(target) +Type *target; +{ + Expr *ex, *ex2; + Meaning *mp; + Symbol *sym; + + if (curtok != TOK_IDENT) { + warning("Expected a variable [289]"); + return makeexpr_long(0); + } + if (!curtokmeaning) { + sym = curtoksym; + ex = makeexpr_name(curtokcase, tp_integer); + gettok(); + if (curtok == TOK_LPAR) { + ex = makeexpr_bicall_0(ex->val.s, tp_integer); + do { + gettok(); + insertarg(&ex, ex->nargs, p_expr(NULL)); + } while (curtok == TOK_COMMA || curtok == TOK_ASSIGN); + if (!wneedtok(TOK_RPAR)) + skippasttotoken(TOK_RPAR, TOK_SEMI); + } + if (!tryfuncmacro(&ex, NULL)) + undefsym(sym); + return fake_dots_n_hats(ex); + } + var_reference(curtokmeaning); + mp = curtokmeaning; + if (mp->kind == MK_FIELD) { + ex = makeexpr_dot(copyexpr(withexprs[curtokint]), mp); + } else if (mp->kind == MK_CONST && + mp->type->kind == TK_SET && + mp->constdefn) { + ex = copyexpr(mp->constdefn); + mp = makestmttempvar(ex->val.type, name_SET); + ex2 = makeexpr(EK_MACARG, 0); + ex2->val.type = ex->val.type; + ex = replaceexprexpr(ex, ex2, makeexpr_var(mp), 0); + freeexpr(ex2); + } else if (mp->kind == MK_CONST && + (mp == mp_false || + mp == mp_true || + mp->anyvarflag || + (foldconsts > 0 && + (mp->type->kind == TK_INTEGER || + mp->type->kind == TK_BOOLEAN || + mp->type->kind == TK_CHAR || + mp->type->kind == TK_ENUM || + mp->type->kind == TK_SUBR || + mp->type->kind == TK_REAL)) || + (foldstrconsts > 0 && + (mp->type->kind == TK_STRING)))) { + if (mp->constdefn) { + ex = copyexpr(mp->constdefn); + if (ex->val.type == tp_int) /* kludge! */ + ex->val.type = tp_integer; + } else + ex = makeexpr_val(copyvalue(mp->val)); + } else if (mp->kind == MK_VARPARAM || + mp->kind == MK_VARREF) { + ex = makeexpr_hat(makeexpr_var(mp), 0); + } else if (mp->kind == MK_VARMAC) { + ex = copyexpr(mp->constdefn); + bindnames(ex); + ex = gentle_cast(ex, mp->type); + ex->val.type = mp->type; + } else if (mp->kind == MK_SPVAR && mp->handler) { + gettok(); + ex = (*mp->handler)(mp); + return dots_n_hats(ex, target); + } else if (mp->kind == MK_VAR || + mp->kind == MK_CONST || + mp->kind == MK_PARAM) { + ex = makeexpr_var(mp); + } else { + symclass(mp->sym); + ex = makeexpr_name(mp->name, tp_integer); + } + gettok(); + return dots_n_hats(ex, target); +} + + + + +Expr *p_ord_expr() +{ + return makeexpr_charcast(p_expr(tp_integer)); +} + + + +Static Expr *makesmallsetconst(bits, type) +long bits; +Type *type; +{ + Expr *ex; + + ex = makeexpr_long(bits); + ex->val.type = type; + if (smallsetconst != 2) + insertarg(&ex, 0, makeexpr_name("%#lx", tp_integer)); + return ex; +} + + + +Expr *packset(ex, type) +Expr *ex; +Type *type; +{ + Meaning *mp; + Expr *ex2; + long max2; + + if (ex->kind == EK_BICALL) { + if (!strcmp(ex->val.s, setexpandname) && + (mp = istempvar(ex->args[0])) != NULL) { + canceltempvar(mp); + return grabarg(ex, 1); + } + if (!strcmp(ex->val.s, setunionname) && + (mp = istempvar(ex->args[0])) != NULL && + !exproccurs(ex->args[1], ex->args[0]) && + !exproccurs(ex->args[2], ex->args[0])) { + canceltempvar(mp); + return makeexpr_bin(EK_BOR, type, packset(ex->args[1], type), + packset(ex->args[2], type)); + } + if (!strcmp(ex->val.s, setaddname)) { + ex2 = makeexpr_bin(EK_LSH, type, + makeexpr_longcast(makeexpr_long(1), 1), + ex->args[1]); + ex = packset(ex->args[0], type); + if (checkconst(ex, 0)) + return ex2; + else + return makeexpr_bin(EK_BOR, type, ex, ex2); + } + if (!strcmp(ex->val.s, setaddrangename)) { + if (ord_range(type->indextype, NULL, &max2) && max2 == setbits-1) + note("Range construction was implemented by a subtraction which may overflow [278]"); + ex2 = makeexpr_minus(makeexpr_bin(EK_LSH, type, + makeexpr_longcast(makeexpr_long(1), 1), + makeexpr_plus(ex->args[2], + makeexpr_long(1))), + makeexpr_bin(EK_LSH, type, + makeexpr_longcast(makeexpr_long(1), 1), + ex->args[1])); + ex = packset(ex->args[0], type); + if (checkconst(ex, 0)) + return ex2; + else + return makeexpr_bin(EK_BOR, type, ex, ex2); + } + } + return makeexpr_bicall_1(setpackname, type, ex); +} + + + +#define MAXSETLIT 400 + +Expr *p_setfactor(target, sure) +Type *target; +int sure; +{ + Expr *ex, *exmax = NULL, *ex2; + Expr *first[MAXSETLIT], *last[MAXSETLIT]; + char doneflag[MAXSETLIT]; + int i, j, num, donecount; + int isconst, guesstype; + long maxv, max2; + Value val; + Type *tp, *type; + Meaning *tvar; + + if (curtok == TOK_LBRACE) + gettok(); + else if (!wneedtok(TOK_LBR)) + return makeexpr_long(0); + if (curtok == TOK_RBR || curtok == TOK_RBRACE) { /* empty set */ + gettok(); + val.type = tp_smallset; + val.i = 0; + val.s = NULL; + return makeexpr_val(val); + } + type = target; + guesstype = !sure; + maxv = -1; + isconst = 1; + num = 0; + for (;;) { + if (num >= MAXSETLIT) { + warning(format_d("Too many elements in set literal; max=%d [290]", MAXSETLIT)); + ex = p_expr(type); + while (curtok != TOK_RBR && curtok != TOK_RBRACE) { + gettok(); + ex = p_expr(type); + } + break; + } + if (guesstype && num == 0) { + ex = p_ord_expr(); + type = ex->val.type; + } else { + ex = p_expr(type); + } + first[num] = ex = gentle_cast(ex, type); + doneflag[num] = 0; + if (curtok == TOK_DOTS || curtok == TOK_COLON) { /* UCSD? */ + val = eval_expr(ex); + if (val.type) { + if (val.i > maxv) { /* In case of [127..0] */ + maxv = val.i; + exmax = ex; + } + } else + isconst = 0; + gettok(); + last[num] = ex = gentle_cast(p_expr(type), type); + } else { + last[num] = NULL; + } + val = eval_expr(ex); + if (val.type) { + if (val.i > maxv) { + maxv = val.i; + exmax = ex; + } + } else { + isconst = 0; + maxv = LONG_MAX; + } + num++; + if (curtok == TOK_COMMA) + gettok(); + else + break; + } + if (curtok == TOK_RBRACE) + gettok(); + else if (!wneedtok(TOK_RBR)) + skippasttotoken(TOK_RBR, TOK_SEMI); + tp = first[0]->val.type; + if (guesstype) { /* must determine type */ + if (maxv == LONG_MAX) { + if (target && ord_range(target, NULL, &max2)) + maxv = max2; + else if (ord_range(tp, NULL, &max2) && max2 < 1000000 && + (max2 >= defaultsetsize || num == 1)) + maxv = max2; + else + maxv = defaultsetsize-1; + exmax = makeexpr_long(maxv); + } else + exmax = copyexpr(exmax); + if (!ord_range(tp, NULL, &max2) || maxv != max2) + tp = makesubrangetype(tp, makeexpr_long(0), exmax); + type = makesettype(tp); + } else + type = makesettype(type); + donecount = 0; + if (smallsetconst > 0) { + val.i = 0; + for (i = 0; i < num; i++) { + if (first[i]->kind == EK_CONST && first[i]->val.i < setbits && + (!last[i] || (last[i]->kind == EK_CONST && + last[i]->val.i >= 0 && + last[i]->val.i < setbits))) { + if (last[i]) { + for (j = first[i]->val.i; j <= last[i]->val.i; j++) + val.i |= 1<<j; + } else + val.i |= 1 << first[i]->val.i; + doneflag[i] = 1; + donecount++; + } + } + } + if (donecount) { + ex = makesmallsetconst(val.i, tp_smallset); + } else + ex = NULL; + if (type->kind == TK_SMALLSET) { + for (i = 0; i < num; i++) { + if (!doneflag[i]) { + ex2 = makeexpr_bin(EK_LSH, type, + makeexpr_longcast(makeexpr_long(1), 1), + enum_to_int(first[i])); + if (last[i]) { + if (ord_range(type->indextype, NULL, &max2) && max2 == setbits-1) + note("Range construction was implemented by a subtraction which may overflow [278]"); + ex2 = makeexpr_minus(makeexpr_bin(EK_LSH, type, + makeexpr_longcast(makeexpr_long(1), 1), + makeexpr_plus(enum_to_int(last[i]), + makeexpr_long(1))), + ex2); + } + if (ex) + ex = makeexpr_bin(EK_BOR, type, makeexpr_longcast(ex, 1), ex2); + else + ex = ex2; + } + } + } else { + tvar = makestmttempvar(type, name_SET); + if (!ex) { + val.type = tp_smallset; + val.i = 0; + val.s = NULL; + ex = makeexpr_val(val); + } + ex = makeexpr_bicall_2(setexpandname, type, + makeexpr_var(tvar), makeexpr_arglong(ex, 1)); + for (i = 0; i < num; i++) { + if (!doneflag[i]) { + if (last[i]) + ex = makeexpr_bicall_3(setaddrangename, type, + ex, makeexpr_arglong(enum_to_int(first[i]), 0), + makeexpr_arglong(enum_to_int(last[i]), 0)); + else + ex = makeexpr_bicall_2(setaddname, type, + ex, makeexpr_arglong(enum_to_int(first[i]), 0)); + } + } + } + return ex; +} + + + + +Expr *p_funcarglist(ex, args, firstarg, ismacro) +Expr *ex; +Meaning *args; +int firstarg, ismacro; +{ + Meaning *mp, *mp2, *arglist = args, *prevarg = NULL; + Expr *ex2; + int i, fi, fakenum = -1, castit, isconf, isnonpos = 0; + Type *tp, *tp2; + char *name; + + castit = castargs; + if (castit < 0) + castit = (prototypes == 0); + while (args) { + if (isnonpos) { + while (curtok == TOK_COMMA) + gettok(); + if (curtok == TOK_RPAR) { + args = arglist; + i = firstarg; + while (args) { + if (ex->nargs <= i) + insertarg(&ex, ex->nargs, NULL); + if (!ex->args[i]) { + if (args->constdefn) + ex->args[i] = copyexpr(args->constdefn); + else { + warning(format_s("Missing value for parameter %s [291]", + args->name)); + ex->args[i] = makeexpr_long(0); + } + } + args = args->xnext; + i++; + } + break; + } + } + if (args->isreturn || args->fakeparam) { + if (args->fakeparam) { + if (fakenum < 0) + fakenum = ex->nargs; + if (args->constdefn) + insertarg(&ex, ex->nargs, copyexpr(args->constdefn)); + else + insertarg(&ex, ex->nargs, makeexpr_long(0)); + } + args = args->xnext; /* return value parameter */ + continue; + } + if (curtok == TOK_RPAR) { + if (args->constdefn) { + insertarg(&ex, ex->nargs, copyexpr(args->constdefn)); + args = args->xnext; + continue; + } else { + if (ex->kind == EK_FUNCTION) { + name = ((Meaning *)ex->val.i)->name; + ex->kind = EK_BICALL; + ex->val.s = stralloc(name); + } else + name = "function"; + warning(format_s("Too few arguments for %s [292]", name)); + return ex; + } + } + if (curtok == TOK_COMMA) { + if (args->constdefn) + insertarg(&ex, ex->nargs, copyexpr(args->constdefn)); + else { + warning(format_s("Missing parameter %s [293]", args->name)); + insertarg(&ex, ex->nargs, makeexpr_long(0)); + } + gettok(); + args = args->xnext; + continue; + } + p_mech_spec(0); + if (curtok == TOK_IDENT) { + mp = arglist; + mp2 = NULL; + i = firstarg; + fi = -1; + while (mp && strcmp(curtokbuf, mp->sym->name)) { + if (mp->fakeparam) { + if (fi < 0) + fi = i; + } else + fi = -1; + i++; + mp2 = mp; + mp = mp->xnext; + } + if (mp && + (peeknextchar() == ':' || !curtokmeaning || isnonpos)) { + gettok(); + wneedtok(TOK_ASSIGN); + prevarg = mp2; + args = mp; + fakenum = fi; + isnonpos = 1; + } else + i = ex->nargs; + } else + i = ex->nargs; + while (ex->nargs <= i) + insertarg(&ex, ex->nargs, NULL); + if (ex->args[i]) + warning(format_s("Multiple values for parameter %s [294]", + args->name)); + tp = args->type; + ex2 = p_expr(tp); + if (args->kind == MK_VARPARAM) + tp = tp->basetype; + if (isfiletype(tp, 1) && is_std_file(ex2)) { + mp2 = makestmttempvar(tp_bigtext, name_TEMP); + ex2 = makeexpr_comma( + makeexpr_comma(makeexpr_assign(filebasename(makeexpr_var(mp2)), + ex2), + makeexpr_assign(filenamepart(makeexpr_var(mp2)), + makeexpr_string(""))), + makeexpr_var(mp2)); + } + tp2 = ex2->val.type; + isconf = ((tp->kind == TK_ARRAY || + tp->kind == TK_STRING) && tp->structdefd); + switch (args->kind) { + + case MK_PARAM: + if (castit && tp->kind == TK_REAL && + ex2->val.type->kind != TK_REAL) + ex2 = makeexpr_cast(ex2, tp); + else if (ord_type(tp)->kind == TK_INTEGER && !ismacro) + ex2 = makeexpr_arglong(ex2, long_type(tp)); + else if (args->othername && args->rectype != tp && + tp->kind != TK_STRING && args->type == tp2) + ex2 = makeexpr_addr(ex2); + else + ex2 = gentle_cast(ex2, tp); + ex->args[i] = ex2; + break; + + case MK_VARPARAM: + if (args->type == tp_strptr && args->anyvarflag) { + ex->args[i] = strmax_func(ex2); + insertarg(&ex, ex->nargs-1, makeexpr_addr(ex2)); + if (isnonpos) + note("Non-positional conformant parameters may not work [279]"); + } else { /* regular VAR parameter */ + if (!expr_is_lvalue(ex2) || + (tp->kind == TK_REAL && + ord_type(tp2)->kind == TK_INTEGER)) { + mp2 = makestmttempvar(tp, name_TEMP); + ex2 = makeexpr_comma(makeexpr_assign(makeexpr_var(mp2), + ex2), + makeexpr_addrf(makeexpr_var(mp2))); + } else + ex2 = makeexpr_addrf(ex2); + if (args->anyvarflag || + (tp->kind == TK_POINTER && tp2->kind == TK_POINTER && + (tp == tp_anyptr || tp2 == tp_anyptr))) { + if (!ismacro) + ex2 = makeexpr_cast(ex2, args->type); + } else { + if (tp2 != tp && !isconf && + (tp2->kind != TK_STRING || + tp->kind != TK_STRING)) + warning(format_s("Type mismatch in VAR parameter %s [295]", + args->name)); + } + ex->args[i] = ex2; + } + break; + + default: + intwarning("p_funcarglist", + format_s("Parameter type is %s [296]", + meaningkindname(args->kind))); + break; + } + if (isconf && /* conformant array or string */ + (!prevarg || prevarg->type != args->type)) { + while (tp->kind == TK_ARRAY && tp->structdefd) { + if (tp2->kind == TK_SMALLARRAY) { + warning("Trying to pass a small-array for a conformant array [297]"); + /* this has a chance of working... */ + ex->args[ex->nargs-1] = + makeexpr_addr(ex->args[ex->nargs-1]); + } else if (tp2->kind == TK_STRING) { + ex->args[fakenum++] = + makeexpr_arglong(makeexpr_long(1), integer16 == 0); + ex->args[fakenum++] = + makeexpr_arglong(strmax_func(ex->args[ex->nargs-1]), + integer16 == 0); + break; + } else if (tp2->kind != TK_ARRAY) { + warning("Type mismatch for conformant array [298]"); + break; + } + ex->args[fakenum++] = + makeexpr_arglong(copyexpr(tp2->indextype->smin), + integer16 == 0); + ex->args[fakenum++] = + makeexpr_arglong(copyexpr(tp2->indextype->smax), + integer16 == 0); + tp = tp->basetype; + tp2 = tp2->basetype; + } + if (tp->kind == TK_STRING && tp->structdefd) { + ex->args[fakenum] = + makeexpr_arglong(strmax_func(ex->args[ex->nargs-1]), + integer16 == 0); + } + } + fakenum = -1; + if (!isnonpos) { + prevarg = args; + args = args->xnext; + if (args) { + if (curtok != TOK_RPAR && !wneedtok(TOK_COMMA)) + skiptotoken2(TOK_RPAR, TOK_SEMI); + } + } + } + if (curtok == TOK_COMMA) { + if (ex->kind == EK_FUNCTION) { + name = ((Meaning *)ex->val.i)->name; + ex->kind = EK_BICALL; + ex->val.s = stralloc(name); + } else + name = "function"; + warning(format_s("Too many arguments for %s [299]", name)); + while (curtok == TOK_COMMA) { + gettok(); + insertarg(&ex, ex->nargs, p_expr(tp_integer)); + } + } + return ex; +} + + + +Expr *replacemacargs(ex, fex) +Expr *ex, *fex; +{ + int i; + Expr *ex2; + + for (i = 0; i < ex->nargs; i++) + ex->args[i] = replacemacargs(ex->args[i], fex); + if (ex->kind == EK_MACARG) { + if (ex->val.i <= fex->nargs) { + ex2 = copyexpr(fex->args[ex->val.i - 1]); + } else { + ex2 = makeexpr_name("<meef>", tp_integer); + note("FuncMacro specified more arguments than call [280]"); + } + freeexpr(ex); + return ex2; + } + return resimplify(ex); +} + + +Expr *p_noarglist(ex, mp, args) +Expr *ex; +Meaning *mp, *args; +{ + while (args && args->constdefn) { + insertarg(&ex, ex->nargs, copyexpr(args->constdefn)); + args = args->xnext; + } + if (args) { + warning(format_s("Expected an argument list for %s [300]", mp->name)); + ex->kind = EK_BICALL; + ex->val.s = stralloc(mp->name); + } + return ex; +} + + +void func_reference(func) +Meaning *func; +{ + Meaning *mp; + + if (func->ctx && func->ctx != curctx &&func->ctx->kind == MK_FUNCTION && + func->ctx->varstructflag && !curctx->ctx->varstructflag) { + for (mp = curctx->ctx; mp != func->ctx; mp = mp->ctx) + mp->varstructflag = 1; + } +} + + +Expr *p_funccall(mp) +Meaning *mp; +{ + Meaning *mp2, *tvar; + Expr *ex, *ex2; + int firstarg = 0; + + func_reference(mp); + ex = makeexpr(EK_FUNCTION, 0); + ex->val.i = (long)mp; + ex->val.type = mp->type->basetype; + mp2 = mp->type->fbase; + if (mp2 && mp2->isreturn) { /* pointer to buffer for return value */ + tvar = makestmttempvar(ex->val.type->basetype, + (ex->val.type->basetype->kind == TK_STRING) ? name_STRING : name_TEMP); + insertarg(&ex, 0, makeexpr_addr(makeexpr_var(tvar))); + mp2 = mp2->xnext; + firstarg++; + } + if (mp2 && curtok != TOK_LPAR) { + ex = p_noarglist(ex, mp, mp2); + } else if (curtok == TOK_LPAR) { + gettok(); + ex = p_funcarglist(ex, mp2, firstarg, (mp->constdefn != NULL)); + skipcloseparen(); + } + if (mp->constdefn) { + ex2 = replacemacargs(copyexpr(mp->constdefn), ex); + ex2 = gentle_cast(ex2, ex->val.type); + ex2->val.type = ex->val.type; + freeexpr(ex); + return ex2; + } + return ex; +} + + + + + + +Expr *accumulate_strlit() +{ + char buf[256], ch, *cp, *cp2; + int len, i, danger = 0; + + len = 0; + cp = buf; + for (;;) { + if (curtok == TOK_STRLIT) { + cp2 = curtokbuf; + i = curtokint; + while (--i >= 0) { + if (++len <= 255) { + ch = *cp++ = *cp2++; + if (ch & 128) + danger++; + } + } + } else if (curtok == TOK_HAT) { /* Turbo */ + i = getchartok() & 0x1f; + if (++len <= 255) + *cp++ = i; + } else if (curtok == TOK_LPAR) { /* VAX */ + Value val; + do { + gettok(); + val = p_constant(tp_integer); + if (++len <= 255) + *cp++ = val.i; + } while (curtok == TOK_COMMA); + skipcloseparen(); + continue; + } else + break; + gettok(); + } + if (len > 255) { + warning("String literal too long [301]"); + len = 255; + } + if (danger && + !(unsignedchar == 1 || + (unsignedchar != 0 && signedchars == 0))) + note(format_s("Character%s >= 128 encountered [281]", (danger > 1) ? "s" : "")); + return makeexpr_lstring(buf, len); +} + + + +Expr *pascaltypecast(type, ex2) +Type *type; +Expr *ex2; +{ + if (type->kind == TK_POINTER || type->kind == TK_STRING || + type->kind == TK_ARRAY) + ex2 = makeexpr_stringcast(ex2); + else + ex2 = makeexpr_charcast(ex2); + if ((ex2->val.type->kind == TK_INTEGER || + ex2->val.type->kind == TK_CHAR || + ex2->val.type->kind == TK_BOOLEAN || + ex2->val.type->kind == TK_ENUM || + ex2->val.type->kind == TK_SUBR || + ex2->val.type->kind == TK_REAL || + ex2->val.type->kind == TK_POINTER || + ex2->val.type->kind == TK_STRING) && + (type->kind == TK_INTEGER || + type->kind == TK_CHAR || + type->kind == TK_BOOLEAN || + type->kind == TK_ENUM || + type->kind == TK_SUBR || + type->kind == TK_REAL || + type->kind == TK_POINTER)) { + if (type->kind == TK_POINTER || ex2->val.type->kind == TK_POINTER) + return makeexpr_un(EK_CAST, type, ex2); + else + return makeexpr_un(EK_ACTCAST, type, ex2); + } else { + return makeexpr_hat(makeexpr_cast(makeexpr_addr(ex2), + makepointertype(type)), 0); + } +} + + + + +Static Expr *p_factor(target) +Type *target; +{ + Expr *ex, *ex2; + Type *type; + Meaning *mp, *mp2; + + switch (curtok) { + + case TOK_INTLIT: + ex = makeexpr_long(curtokint); + gettok(); + return ex; + + case TOK_HEXLIT: + ex = makeexpr_long(curtokint); + insertarg(&ex, 0, makeexpr_name("%#lx", tp_integer)); + gettok(); + return ex; + + case TOK_OCTLIT: + ex = makeexpr_long(curtokint); + insertarg(&ex, 0, makeexpr_name("%#lo", tp_integer)); + gettok(); + return ex; + + case TOK_MININT: + strcat(curtokbuf, ".0"); + + /* fall through */ + case TOK_REALLIT: + ex = makeexpr_real(curtokbuf); + gettok(); + return ex; + + case TOK_HAT: + case TOK_STRLIT: + ex = accumulate_strlit(); + return ex; + + case TOK_LPAR: + gettok(); + ex = p_expr(target); + skipcloseparen(); + return dots_n_hats(ex, target); + + case TOK_NOT: + case TOK_TWIDDLE: + gettok(); + ex = p_factor(tp_integer); + if (ord_type(ex->val.type)->kind == TK_INTEGER) + return makeexpr_un(EK_BNOT, tp_integer, ex); + else + return makeexpr_not(ex); + + case TOK_MINUS: + gettok(); + if (curtok == TOK_MININT) { + gettok(); + return makeexpr_long(MININT); + } else + return makeexpr_neg(p_factor(target)); + + case TOK_PLUS: + gettok(); + return p_factor(target); + + case TOK_ADDR: + gettok(); + if (curtok == TOK_ADDR) { + gettok(); + ex = p_factor(tp_proc); + if (ex->val.type->kind == TK_PROCPTR && ex->kind == EK_COMMA) + return grabarg(grabarg(grabarg(ex, 0), 1), 0); + if (ex->val.type->kind != TK_CPROCPTR) + warning("@@ allowed only for procedure pointers [302]"); + return makeexpr_addrf(ex); + } + if (curtok == TOK_IDENT && 0 && /***/ + curtokmeaning && (curtokmeaning->kind == MK_FUNCTION || + curtokmeaning->kind == MK_SPECIAL)) { + if (curtokmeaning->ctx == nullctx) + warning(format_s("Can't take address of predefined object %s [303]", + curtokmeaning->name)); + ex = makeexpr_name(curtokmeaning->name, tp_anyptr); + gettok(); + } else { + ex = p_factor(tp_proc); + if (ex->val.type->kind == TK_PROCPTR) { + /* ex = makeexpr_dotq(ex, "proc", tp_anyptr); */ + } else if (ex->val.type->kind == TK_CPROCPTR) { + ex = makeexpr_cast(ex, tp_anyptr); + } else + ex = makeexpr_addrf(ex); + } + return ex; + + case TOK_LBR: + case TOK_LBRACE: + return p_setfactor(target && target->kind == TK_SET + ? target->indextype : NULL, 0); + + case TOK_NIL: + gettok(); + return makeexpr_nil(); + + case TOK_IF: /* nifty Pascal extension */ + gettok(); + ex = p_expr(tp_boolean); + wneedtok(TOK_THEN); + ex2 = p_expr(tp_integer); + if (wneedtok(TOK_ELSE)) + return makeexpr_cond(ex, ex2, p_factor(ex2->val.type)); + else + return makeexpr_cond(ex, ex2, makeexpr_long(0)); + + case TOK_IDENT: + mp = curtokmeaning; + switch ((mp) ? mp->kind : MK_VAR) { + + case MK_TYPE: + gettok(); + type = mp->type; + switch (curtok) { + + case TOK_LPAR: /* Turbo type cast */ + gettok(); + ex2 = p_expr(type); + ex = pascaltypecast(type, ex2); + skipcloseparen(); + return dots_n_hats(ex, target); + + case TOK_LBR: + case TOK_LBRACE: + switch (type->kind) { + + case TK_SET: + case TK_SMALLSET: + return p_setfactor(type->indextype, 1); + + case TK_RECORD: + return p_constrecord(type, 0); + + case TK_ARRAY: + case TK_SMALLARRAY: + return p_constarray(type, 0); + + case TK_STRING: + return p_conststring(type, 0); + + default: + warning("Bad type for constructor [304]"); + skipparens(); + return makeexpr_name(mp->name, mp->type); + } + + default: + wexpected("an expression"); + return makeexpr_name(mp->name, mp->type); + } + + case MK_SPECIAL: + if (mp->handler && mp->isfunction && + (curtok == TOK_LPAR || !target || + (target->kind != TK_PROCPTR && + target->kind != TK_CPROCPTR))) { + gettok(); + if ((mp->sym->flags & LEAVEALONE) || mp->constdefn) { + ex = makeexpr_bicall_0(mp->name, tp_integer); + if (curtok == TOK_LPAR) { + do { + gettok(); + insertarg(&ex, ex->nargs, p_expr(NULL)); + } while (curtok == TOK_COMMA); + skipcloseparen(); + } + tryfuncmacro(&ex, mp); + return ex; + } + ex = (*mp->handler)(mp); + if (!ex) + ex = makeexpr_long(0); + return ex; + } else { + if (target && + (target->kind == TK_PROCPTR || + target->kind == TK_CPROCPTR)) + note("Using a built-in procedure as a procedure pointer [316]"); + else + symclass(curtoksym); + gettok(); + return makeexpr_name(mp->name, tp_integer); + } + + case MK_FUNCTION: + mp->refcount++; + need_forward_decl(mp); + gettok(); + if (mp->isfunction && + (curtok == TOK_LPAR || !target || + (target->kind != TK_PROCPTR && + target->kind != TK_CPROCPTR))) { + ex = p_funccall(mp); + if (!mp->constdefn) { + if (mp->handler && !(mp->sym->flags & LEAVEALONE)) + ex = (*mp->handler)(ex); + } + if (mp->cbase->kind == MK_VARPARAM) { + ex = makeexpr_hat(ex, 0); /* returns pointer to structured result */ + } + return dots_n_hats(ex, target); + } else { + if (mp->handler && !(mp->sym->flags & LEAVEALONE)) + note("Using a built-in procedure as a procedure pointer [316]"); + if (target && target->kind == TK_CPROCPTR) { + type = maketype(TK_CPROCPTR); + type->basetype = mp->type; + type->escale = 0; + mp2 = makestmttempvar(type, name_TEMP); + ex = makeexpr_comma( + makeexpr_assign( + makeexpr_var(mp2), + makeexpr_name(mp->name, tp_text)), + makeexpr_var(mp2)); + if (mp->ctx->kind == MK_FUNCTION) + warning("Procedure pointer to nested procedure [305]"); + } else { + type = maketype(TK_PROCPTR); + type->basetype = mp->type; + type->escale = 1; + mp2 = makestmttempvar(type, name_TEMP); + ex = makeexpr_comma( + makeexpr_comma( + makeexpr_assign( + makeexpr_dotq(makeexpr_var(mp2), + "proc", + tp_anyptr), + makeexpr_name(mp->name, tp_text)), + /* handy pointer type */ + makeexpr_assign( + makeexpr_dotq(makeexpr_var(mp2), + "link", + tp_anyptr), + makeexpr_ctx(mp->ctx))), + makeexpr_var(mp2)); + } + return ex; + } + + default: + return p_variable(target); + } + + default: + wexpected("an expression"); + return makeexpr_long(0); + + } +} + + + + +Static Expr *p_powterm(target) +Type *target; +{ + Expr *ex = p_factor(target); + Expr *ex2; + int i, castit; + long v; + + if (curtok == TOK_STARSTAR) { + gettok(); + ex2 = p_powterm(target); + if (ex->val.type->kind == TK_REAL || + ex2->val.type->kind == TK_REAL) { + if (checkconst(ex2, 2)) { + ex = makeexpr_sqr(ex, 0); + } else if (checkconst(ex2, 3)) { + ex = makeexpr_sqr(ex, 1); + } else { + castit = castargs >= 0 ? castargs : (prototypes == 0); + if (ex->val.type->kind != TK_REAL && castit) + ex = makeexpr_cast(ex, tp_longreal); + if (ex2->val.type->kind != TK_REAL && castit) + ex2 = makeexpr_cast(ex2, tp_longreal); + ex = makeexpr_bicall_2("pow", tp_longreal, ex, ex2); + } + } else if (checkconst(ex, 2)) { + freeexpr(ex); + ex = makeexpr_bin(EK_LSH, tp_integer, + makeexpr_longcast(makeexpr_long(1), 1), ex2); + } else if (checkconst(ex, 0) || + checkconst(ex, 1) || + checkconst(ex2, 1)) { + freeexpr(ex2); + } else if (checkconst(ex2, 0)) { + freeexpr(ex); + freeexpr(ex2); + ex = makeexpr_long(1); + } else if (isliteralconst(ex, NULL) == 2 && + isliteralconst(ex2, NULL) == 2 && + ex2->val.i > 0) { + v = ex->val.i; + i = ex2->val.i; + while (--i > 0) + v *= ex->val.i; + freeexpr(ex); + freeexpr(ex2); + ex = makeexpr_long(v); + } else if (checkconst(ex2, 2)) { + ex = makeexpr_sqr(ex, 0); + } else if (checkconst(ex2, 3)) { + ex = makeexpr_sqr(ex, 1); + } else { + ex = makeexpr_bicall_2("ipow", tp_integer, + makeexpr_arglong(ex, 1), + makeexpr_arglong(ex2, 1)); + } + } + return ex; +} + + +Static Expr *p_term(target) +Type *target; +{ + Expr *ex = p_powterm(target); + Expr *ex2; + Type *type; + Meaning *tvar; + int useshort; + + for (;;) { + checkkeyword(TOK_SHL); + checkkeyword(TOK_SHR); + checkkeyword(TOK_REM); + switch (curtok) { + + case TOK_STAR: + gettok(); + if (ex->val.type->kind == TK_SET || + ex->val.type->kind == TK_SMALLSET) { + ex2 = p_powterm(ex->val.type); + type = mixsets(&ex, &ex2); + if (type->kind == TK_SMALLSET) { + ex = makeexpr_bin(EK_BAND, type, ex, ex2); + } else { + tvar = makestmttempvar(type, name_SET); + ex = makeexpr_bicall_3(setintname, type, + makeexpr_var(tvar), + ex, ex2); + } + } else + ex = makeexpr_times(ex, p_powterm(tp_integer)); + break; + + case TOK_SLASH: + gettok(); + if (ex->val.type->kind == TK_SET || + ex->val.type->kind == TK_SMALLSET) { + ex2 = p_powterm(ex->val.type); + type = mixsets(&ex, &ex2); + if (type->kind == TK_SMALLSET) { + ex = makeexpr_bin(EK_BXOR, type, ex, ex2); + } else { + tvar = makestmttempvar(type, name_SET); + ex = makeexpr_bicall_3(setxorname, type, + makeexpr_var(tvar), + ex, ex2); + } + } else + ex = makeexpr_divide(ex, p_powterm(tp_integer)); + break; + + case TOK_DIV: + gettok(); + ex = makeexpr_div(ex, p_powterm(tp_integer)); + break; + + case TOK_REM: + gettok(); + ex = makeexpr_rem(ex, p_powterm(tp_integer)); + break; + + case TOK_MOD: + gettok(); + ex = makeexpr_mod(ex, p_powterm(tp_integer)); + break; + + case TOK_AND: + case TOK_AMP: + useshort = (curtok == TOK_AMP); + gettok(); + ex2 = p_powterm(tp_integer); + if (ord_type(ex->val.type)->kind == TK_INTEGER) + ex = makeexpr_bin(EK_BAND, ex->val.type, ex, ex2); + else if (partial_eval_flag || useshort || + (shortopt && nosideeffects(ex2, 1))) + ex = makeexpr_and(ex, ex2); + else + ex = makeexpr_bin(EK_BAND, tp_boolean, ex, ex2); + break; + + case TOK_SHL: + gettok(); + ex = makeexpr_bin(EK_LSH, ex->val.type, ex, p_powterm(tp_integer)); + break; + + case TOK_SHR: + gettok(); + ex = force_unsigned(ex); + ex = makeexpr_bin(EK_RSH, ex->val.type, ex, p_powterm(tp_integer)); + break; + + default: + return ex; + } + } +} + + + +Static Expr *p_sexpr(target) +Type *target; +{ + Expr *ex, *ex2; + Type *type; + Meaning *tvar; + int useshort; + + switch (curtok) { + case TOK_MINUS: + gettok(); + if (curtok == TOK_MININT) { + gettok(); + ex = makeexpr_long(MININT); + break; + } + ex = makeexpr_neg(p_term(target)); + break; + case TOK_PLUS: + gettok(); + /* fall through */ + default: + ex = p_term(target); + break; + } + if (curtok == TOK_PLUS && + (ex->val.type->kind == TK_STRING || + ord_type(ex->val.type)->kind == TK_CHAR || + ex->val.type->kind == TK_ARRAY)) { + while (curtok == TOK_PLUS) { + gettok(); + ex = makeexpr_concat(ex, p_term(NULL), 0); + } + return ex; + } else { + for (;;) { + checkkeyword(TOK_XOR); + switch (curtok) { + + case TOK_PLUS: + gettok(); + if (ex->val.type->kind == TK_SET || + ex->val.type->kind == TK_SMALLSET) { + ex2 = p_term(ex->val.type); + type = mixsets(&ex, &ex2); + if (type->kind == TK_SMALLSET) { + ex = makeexpr_bin(EK_BOR, type, ex, ex2); + } else { + tvar = makestmttempvar(type, name_SET); + ex = makeexpr_bicall_3(setunionname, type, + makeexpr_var(tvar), + ex, ex2); + } + } else + ex = makeexpr_plus(ex, p_term(tp_integer)); + break; + + case TOK_MINUS: + gettok(); + if (ex->val.type->kind == TK_SET || + ex->val.type->kind == TK_SMALLSET) { + ex2 = p_term(tp_integer); + type = mixsets(&ex, &ex2); + if (type->kind == TK_SMALLSET) { + ex = makeexpr_bin(EK_BAND, type, ex, + makeexpr_un(EK_BNOT, type, ex2)); + } else { + tvar = makestmttempvar(type, name_SET); + ex = makeexpr_bicall_3(setdiffname, type, + makeexpr_var(tvar), ex, ex2); + } + } else + ex = makeexpr_minus(ex, p_term(tp_integer)); + break; + + case TOK_VBAR: + if (modula2) + return ex; + /* fall through */ + + case TOK_OR: + useshort = (curtok == TOK_VBAR); + gettok(); + ex2 = p_term(tp_integer); + if (ord_type(ex->val.type)->kind == TK_INTEGER) + ex = makeexpr_bin(EK_BOR, ex->val.type, ex, ex2); + else if (partial_eval_flag || useshort || + (shortopt && nosideeffects(ex2, 1))) + ex = makeexpr_or(ex, ex2); + else + ex = makeexpr_bin(EK_BOR, tp_boolean, ex, ex2); + break; + + case TOK_XOR: + gettok(); + ex2 = p_term(tp_integer); + ex = makeexpr_bin(EK_BXOR, ex->val.type, ex, ex2); + break; + + default: + return ex; + } + } + } +} + + + +Expr *p_expr(target) +Type *target; +{ + Expr *ex = p_sexpr(target); + Expr *ex2, *ex3, *ex4; + Type *type; + Meaning *tvar; + long mask, smin, smax; + int i, j; + + switch (curtok) { + + case TOK_EQ: + gettok(); + return makeexpr_rel(EK_EQ, ex, p_sexpr(ex->val.type)); + + case TOK_NE: + gettok(); + return makeexpr_rel(EK_NE, ex, p_sexpr(ex->val.type)); + + case TOK_LT: + gettok(); + return makeexpr_rel(EK_LT, ex, p_sexpr(ex->val.type)); + + case TOK_GT: + gettok(); + return makeexpr_rel(EK_GT, ex, p_sexpr(ex->val.type)); + + case TOK_LE: + gettok(); + return makeexpr_rel(EK_LE, ex, p_sexpr(ex->val.type)); + + case TOK_GE: + gettok(); + return makeexpr_rel(EK_GE, ex, p_sexpr(ex->val.type)); + + case TOK_IN: + gettok(); + ex2 = p_sexpr(tp_smallset); + ex = gentle_cast(ex, ex2->val.type->indextype); + if (ex2->val.type->kind == TK_SMALLSET) { + if (!ord_range(ex->val.type, &smin, &smax)) { + smin = -1; + smax = setbits; + } + if (!nosideeffects(ex, 0)) { + tvar = makestmttempvar(ex->val.type, name_TEMP); + ex3 = makeexpr_assign(makeexpr_var(tvar), ex); + ex = makeexpr_var(tvar); + } else + ex3 = NULL; + ex4 = copyexpr(ex); + if (ex->kind == EK_CONST && smallsetconst) + ex = makesmallsetconst(1<<ex->val.i, ex2->val.type); + else + ex = makeexpr_bin(EK_LSH, ex2->val.type, + makeexpr_longcast(makeexpr_long(1), 1), + enum_to_int(ex)); + ex = makeexpr_rel(EK_NE, makeexpr_bin(EK_BAND, tp_integer, ex, ex2), + makeexpr_long(0)); + if (*name_SETBITS || + ((ex4->kind == EK_CONST) ? ((unsigned long)ex4->val.i >= setbits) + : !(0 <= smin && smax < setbits))) { + ex = makeexpr_and(makeexpr_range(enum_to_int(ex4), + makeexpr_long(0), + makeexpr_setbits(), 0), + ex); + } else + freeexpr(ex4); + ex = makeexpr_comma(ex3, ex); + return ex; + } else { + ex3 = ex2; + while (ex3->kind == EK_BICALL && + (!strcmp(ex3->val.s, setaddname) || + !strcmp(ex3->val.s, setaddrangename))) + ex3 = ex3->args[0]; + if (ex3->kind == EK_BICALL && !strcmp(ex3->val.s, setexpandname) && + (tvar = istempvar(ex3->args[0])) != NULL && + isconstexpr(ex3->args[1], &mask)) { + canceltempvar(tvar); + if (!nosideeffects(ex, 0)) { + tvar = makestmttempvar(ex->val.type, name_TEMP); + ex3 = makeexpr_assign(makeexpr_var(tvar), ex); + ex = makeexpr_var(tvar); + } else + ex3 = NULL; + type = ord_type(ex2->val.type->indextype); + ex4 = NULL; + i = 0; + while (i < setbits) { + if (mask & (1<<i++)) { + if (i+1 < setbits && (mask & (2<<i))) { + for (j = i; j < setbits && (mask & (1<<j)); j++) ; + ex4 = makeexpr_or(ex4, + makeexpr_range(copyexpr(ex), + makeexpr_val(make_ord(type, i-1)), + makeexpr_val(make_ord(type, j-1)), 1)); + i = j; + } else { + ex4 = makeexpr_or(ex4, + makeexpr_rel(EK_EQ, copyexpr(ex), + makeexpr_val(make_ord(type, i-1)))); + } + } + } + mask = 0; + for (;;) { + if (!strcmp(ex2->val.s, setaddrangename)) { + if (checkconst(ex2->args[1], 'a') && + checkconst(ex2->args[2], 'z')) { + mask |= 0x1; + } else if (checkconst(ex2->args[1], 'A') && + checkconst(ex2->args[2], 'Z')) { + mask |= 0x2; + } else if (checkconst(ex2->args[1], '0') && + checkconst(ex2->args[2], '9')) { + mask |= 0x4; + } else { + ex4 = makeexpr_or(ex4, + makeexpr_range(copyexpr(ex), ex2->args[1], ex2->args[2], 1)); + } + } else if (!strcmp(ex2->val.s, setaddname)) { + ex4 = makeexpr_or(ex4, + makeexpr_rel(EK_EQ, copyexpr(ex), ex2->args[1])); + } else + break; + ex2 = ex2->args[0]; + } + /* do these now so that EK_OR optimizations will work: */ + if (mask & 0x1) + ex4 = makeexpr_or(ex4, makeexpr_range(copyexpr(ex), + makeexpr_char('a'), + makeexpr_char('z'), 1)); + if (mask & 0x2) + ex4 = makeexpr_or(ex4, makeexpr_range(copyexpr(ex), + makeexpr_char('A'), + makeexpr_char('Z'), 1)); + if (mask & 0x4) + ex4 = makeexpr_or(ex4, makeexpr_range(copyexpr(ex), + makeexpr_char('0'), + makeexpr_char('9'), 1)); + freeexpr(ex); + return makeexpr_comma(ex3, ex4); + } + return makeexpr_bicall_2(setinname, tp_boolean, + makeexpr_arglong(ex, 0), ex2); + } + + default: + return ex; + } +} + + + + + + + +/* Parse a C expression; used by VarMacro, etc. */ + +Type *nametotype(name) +char *name; +{ + if (!strcicmp(name, "malloc") || + !strcicmp(name, mallocname)) { + return tp_anyptr; + } + return tp_integer; +} + + +int istypespec() +{ + switch (curtok) { + + case TOK_CONST: + return 1; + + case TOK_IDENT: + return !strcmp(curtokcase, "volatile") || + !strcmp(curtokcase, "void") || + !strcmp(curtokcase, "char") || + !strcmp(curtokcase, "short") || + !strcmp(curtokcase, "int") || + !strcmp(curtokcase, "long") || + !strcmp(curtokcase, "float") || + !strcmp(curtokcase, "double") || + !strcmp(curtokcase, "signed") || + !strcmp(curtokcase, "unsigned") || + !strcmp(curtokcase, "struct") || + !strcmp(curtokcase, "union") || + !strcmp(curtokcase, "class") || + !strcmp(curtokcase, "enum") || + !strcmp(curtokcase, "typedef") || + (curtokmeaning && + curtokmeaning->kind == MK_TYPE); + + default: + return 0; + } +} + + + +Expr *pc_parentype(cp) +char *cp; +{ + Expr *ex; + + if (curtok == TOK_IDENT && + curtokmeaning && + curtokmeaning->kind == MK_TYPE) { + ex = makeexpr_type(curtokmeaning->type); + gettok(); + skipcloseparen(); + } else if (curtok == TOK_IDENT && !strcmp(curtokcase, "typedef")) { + ex = makeexpr_name(getparenstr(inbufptr), tp_integer); + gettok(); + } else { + ex = makeexpr_name(getparenstr(cp), tp_integer); + gettok(); + } + return ex; +} + + + + +Expr *pc_expr2(); + +Expr *pc_factor() +{ + Expr *ex; + char *cp; + Strlist *sl; + int i; + + switch (curtok) { + + case TOK_BANG: + gettok(); + return makeexpr_not(pc_expr2(14)); + + case TOK_TWIDDLE: + gettok(); + return makeexpr_un(EK_BNOT, tp_integer, pc_expr2(14)); + + case TOK_PLPL: + gettok(); + ex = pc_expr2(14); + return makeexpr_assign(ex, makeexpr_plus(copyexpr(ex), makeexpr_long(1))); + + case TOK_MIMI: + gettok(); + ex = pc_expr2(14); + return makeexpr_assign(ex, makeexpr_minus(copyexpr(ex), makeexpr_long(1))); + + case TOK_STAR: + gettok(); + ex = pc_expr2(14); + if (ex->val.type->kind != TK_POINTER) + ex->val.type = makepointertype(ex->val.type); + return makeexpr_hat(ex, 0); + + case TOK_AMP: + gettok(); + return makeexpr_addr(pc_expr2(14)); + + case TOK_PLUS: + gettok(); + return pc_expr2(14); + + case TOK_MINUS: + gettok(); + return makeexpr_neg(pc_expr2(14)); + + case TOK_LPAR: + cp = inbufptr; + gettok(); + if (istypespec()) { + ex = pc_parentype(cp); + return makeexpr_bin(EK_LITCAST, tp_integer, ex, pc_expr2(14)); + } + ex = pc_expr(); + skipcloseparen(); + return ex; + + case TOK_IDENT: + if (!strcmp(curtokcase, "sizeof")) { + gettok(); + if (curtok != TOK_LPAR) + return makeexpr_sizeof(pc_expr2(14), 1); + cp = inbufptr; + gettok(); + if (istypespec()) { + ex = makeexpr_sizeof(pc_parentype(cp), 1); + } else { + ex = makeexpr_sizeof(pc_expr(), 1); + skipcloseparen(); + } + return ex; + } + if (curtoksym->flags & FMACREC) { + ex = makeexpr(EK_MACARG, 0); + ex->val.type = tp_integer; + ex->val.i = 0; + for (sl = funcmacroargs, i = 1; sl; sl = sl->next, i++) { + if (sl->value == (long)curtoksym) { + ex->val.i = i; + break; + } + } + } else + ex = makeexpr_name(curtokcase, nametotype(curtokcase)); + gettok(); + return ex; + + case TOK_INTLIT: + ex = makeexpr_long(curtokint); + if (curtokbuf[strlen(curtokbuf)-1] == 'L') + ex = makeexpr_longcast(ex, 1); + gettok(); + return ex; + + case TOK_HEXLIT: + ex = makeexpr_long(curtokint); + insertarg(&ex, 0, makeexpr_name("%#lx", tp_integer)); + if (curtokbuf[strlen(curtokbuf)-1] == 'L') + ex = makeexpr_longcast(ex, 1); + gettok(); + return ex; + + case TOK_OCTLIT: + ex = makeexpr_long(curtokint); + insertarg(&ex, 0, makeexpr_name("%#lo", tp_integer)); + if (curtokbuf[strlen(curtokbuf)-1] == 'L') + ex = makeexpr_longcast(ex, 1); + gettok(); + return ex; + + case TOK_REALLIT: + ex = makeexpr_real(curtokbuf); + gettok(); + return ex; + + case TOK_STRLIT: + ex = makeexpr_lstring(curtokbuf, curtokint); + gettok(); + return ex; + + case TOK_CHARLIT: + ex = makeexpr_char(curtokint); + gettok(); + return ex; + + default: + wexpected("a C expression"); + return makeexpr_long(0); + } +} + + + + +#define pc_prec(pr) if (prec > (pr)) return ex; gettok(); + +Expr *pc_expr2(prec) +int prec; +{ + Expr *ex, *ex2; + int i; + + ex = pc_factor(); + for (;;) { + switch (curtok) { + + case TOK_COMMA: + pc_prec(1); + ex = makeexpr_comma(ex, pc_expr2(2)); + break; + + case TOK_EQ: + pc_prec(2); + ex = makeexpr_assign(ex, pc_expr2(2)); + break; + + case TOK_QM: + pc_prec(3); + ex2 = pc_expr(); + if (wneedtok(TOK_COLON)) + ex = makeexpr_cond(ex, ex2, pc_expr2(3)); + else + ex = makeexpr_cond(ex, ex2, makeexpr_long(0)); + break; + + case TOK_OROR: + pc_prec(4); + ex = makeexpr_or(ex, pc_expr2(5)); + break; + + case TOK_ANDAND: + pc_prec(5); + ex = makeexpr_and(ex, pc_expr2(6)); + break; + + case TOK_VBAR: + pc_prec(6); + ex = makeexpr_bin(EK_BOR, tp_integer, ex, pc_expr2(7)); + break; + + case TOK_HAT: + pc_prec(7); + ex = makeexpr_bin(EK_BXOR, tp_integer, ex, pc_expr2(8)); + break; + + case TOK_AMP: + pc_prec(8); + ex = makeexpr_bin(EK_BAND, tp_integer, ex, pc_expr2(9)); + break; + + case TOK_EQEQ: + pc_prec(9); + ex = makeexpr_rel(EK_EQ, ex, pc_expr2(10)); + break; + + case TOK_BANGEQ: + pc_prec(9); + ex = makeexpr_rel(EK_NE, ex, pc_expr2(10)); + break; + + case TOK_LT: + pc_prec(10); + ex = makeexpr_rel(EK_LT, ex, pc_expr2(11)); + break; + + case TOK_LE: + pc_prec(10); + ex = makeexpr_rel(EK_LE, ex, pc_expr2(11)); + break; + + case TOK_GT: + pc_prec(10); + ex = makeexpr_rel(EK_GT, ex, pc_expr2(11)); + break; + + case TOK_GE: + pc_prec(10); + ex = makeexpr_rel(EK_GE, ex, pc_expr2(11)); + break; + + case TOK_LTLT: + pc_prec(11); + ex = makeexpr_bin(EK_LSH, tp_integer, ex, pc_expr2(12)); + break; + + case TOK_GTGT: + pc_prec(11); + ex = makeexpr_bin(EK_RSH, tp_integer, ex, pc_expr2(12)); + break; + + case TOK_PLUS: + pc_prec(12); + ex = makeexpr_plus(ex, pc_expr2(13)); + break; + + case TOK_MINUS: + pc_prec(12); + ex = makeexpr_minus(ex, pc_expr2(13)); + break; + + case TOK_STAR: + pc_prec(13); + ex = makeexpr_times(ex, pc_expr2(14)); + break; + + case TOK_SLASH: + pc_prec(13); + ex = makeexpr_div(ex, pc_expr2(14)); + break; + + case TOK_PERC: + pc_prec(13); + ex = makeexpr_mod(ex, pc_expr2(14)); + break; + + case TOK_PLPL: + pc_prec(15); + ex = makeexpr_un(EK_POSTINC, tp_integer, ex); + break; + + case TOK_MIMI: + pc_prec(15); + ex = makeexpr_un(EK_POSTDEC, tp_integer, ex); + break; + + case TOK_LPAR: + pc_prec(16); + if (ex->kind == EK_NAME) { + ex->kind = EK_BICALL; + } else { + ex = makeexpr_un(EK_SPCALL, tp_integer, ex); + } + while (curtok != TOK_RPAR) { + insertarg(&ex, ex->nargs, pc_expr2(2)); + if (curtok != TOK_RPAR) + if (!wneedtok(TOK_COMMA)) + skiptotoken2(TOK_RPAR, TOK_SEMI); + } + gettok(); + break; + + case TOK_LBR: + pc_prec(16); + ex = makeexpr_index(ex, pc_expr(), NULL); + if (!wneedtok(TOK_RBR)) + skippasttoken(TOK_RBR); + break; + + case TOK_ARROW: + pc_prec(16); + if (!wexpecttok(TOK_IDENT)) + break; + if (ex->val.type->kind != TK_POINTER) + ex->val.type = makepointertype(ex->val.type); + ex = makeexpr_dotq(makeexpr_hat(ex, 0), + curtokcase, tp_integer); + gettok(); + break; + + case TOK_DOT: + pc_prec(16); + if (!wexpecttok(TOK_IDENT)) + break; + ex = makeexpr_dotq(ex, curtokcase, tp_integer); + gettok(); + break; + + case TOK_COLONCOLON: + if (prec > 16) + return ex; + i = C_lex; + C_lex = 0; + gettok(); + if (curtok == TOK_IDENT && + curtokmeaning && curtokmeaning->kind == MK_TYPE) { + ex->val.type = curtokmeaning->type; + } else if (curtok == TOK_LPAR) { + gettok(); + ex->val.type = p_type(NULL); + if (!wexpecttok(TOK_RPAR)) + skiptotoken(TOK_RPAR); + } else + wexpected("a type name"); + C_lex = i; + gettok(); + break; + + default: + return ex; + } + } +} + + + + +Expr *pc_expr() +{ + return pc_expr2(0); +} + + + +Expr *pc_expr_str(buf) +char *buf; +{ + Strlist *defsl, *sl; + Expr *ex; + + defsl = NULL; + sl = strlist_append(&defsl, buf); + C_lex++; + push_input_strlist(defsl, buf); + ex = pc_expr(); + if (curtok != TOK_EOF) + warning(format_s("Junk (%s) at end of C expression [306]", + tok_name(curtok))); + pop_input(); + C_lex--; + strlist_empty(&defsl); + return ex; +} + + + + + + +/* Simplify an expression */ + +Expr *fixexpr(ex, env) +Expr *ex; +int env; +{ + Expr *ex2, *ex3; + Type *type, *type2; + char *cp; + char sbuf[5]; + int i, j; + Value val; + + if (!ex) + return NULL; + if (debug>4) {fprintf(outf, "fixexpr("); dumpexpr(ex); fprintf(outf, ")\n");} + switch (ex->kind) { + + case EK_BICALL: + ex2 = fix_bicall(ex, env); + if (ex2) { + ex = ex2; + break; + } + cp = ex->val.s; + if (!strcmp(cp, "strlen")) { + if (ex->args[0]->kind == EK_BICALL && + !strcmp(ex->args[0]->val.s, "sprintf") && + sprintf_value == 0) { /* does sprintf return char count? */ + ex = grabarg(ex, 0); + strchange(&ex->val.s, "*sprintf"); + ex = fixexpr(ex, env); + } else { + ex->args[0] = fixexpr(ex->args[0], ENV_EXPR); + } + } else if (!strcmp(cp, name_SETIO)) { + ex->args[0] = fixexpr(ex->args[0], ENV_BOOL); + } else if (!strcmp(cp, "~~SETIO")) { + ex->args[0] = fixexpr(ex->args[0], ENV_BOOL); + ex = makeexpr_cond(ex->args[0], + makeexpr_long(0), + makeexpr_bicall_1(name_ESCIO, tp_int, ex->args[1])); + } else if (!strcmp(cp, name_CHKIO)) { + ex->args[0] = fixexpr(ex->args[0], ENV_BOOL); + ex->args[2] = fixexpr(ex->args[2], env); + ex->args[3] = fixexpr(ex->args[3], env); + } else if (!strcmp(cp, "~~CHKIO")) { + ex->args[0] = fixexpr(ex->args[0], ENV_BOOL); + ex->args[2] = fixexpr(ex->args[2], env); + ex->args[3] = fixexpr(ex->args[3], env); + ex2 = makeexpr_bicall_1(name_ESCIO, tp_int, ex->args[1]); + if (ord_type(ex->args[3]->val.type)->kind != TK_INTEGER) + ex2 = makeexpr_cast(ex2, ex->args[3]->val.type); + ex = makeexpr_cond(ex->args[0], ex->args[2], ex2); + } else if (!strcmp(cp, "assert")) { + ex->args[0] = fixexpr(ex->args[0], ENV_BOOL); + } else if ((!strcmp(cp, setaddname) || + !strcmp(cp, setaddrangename)) && + (ex2 = ex->args[0])->kind == EK_BICALL && + (!strcmp(ex2->val.s, setaddname) || + !strcmp(ex2->val.s, setaddrangename))) { + while (ex2->kind == EK_BICALL && + (!strcmp(ex2->val.s, setaddname) || + !strcmp(ex2->val.s, setaddrangename) || + !strcmp(ex2->val.s, setexpandname))) + ex2 = ex2->args[0]; + if (nosideeffects(ex2, 1)) { + ex = makeexpr_comma(ex->args[0], ex); + ex->args[1]->args[0] = ex2; + ex = fixexpr(ex, env); + } else + for (i = 0; i < ex->nargs; i++) + ex->args[i] = fixexpr(ex->args[i], ENV_EXPR); + } else if (!strcmp(cp, setunionname) && + (ex3 = singlevar(ex->args[0])) != NULL && + ((i=1, exprsame(ex->args[0], ex->args[i], 0)) || + (i=2, exprsame(ex->args[0], ex->args[i], 0))) && + !exproccurs(ex3, ex->args[3-i]) && + ex->args[3-i]->kind == EK_BICALL && + (!strcmp(ex->args[3-i]->val.s, setaddname) || + !strcmp(ex->args[3-i]->val.s, setaddrangename) || + (!strcmp(ex->args[3-i]->val.s, setexpandname) && + checkconst(ex->args[3-i]->args[1], 0))) && + totempvar(ex->args[3-i])) { + if (!strcmp(ex->args[3-i]->val.s, setexpandname)) { + ex = grabarg(ex, 0); + } else { + ex = makeexpr_comma(ex, ex->args[3-i]); + ex->args[0]->args[3-i] = ex->args[1]->args[0]; + ex->args[1]->args[0] = copyexpr(ex->args[0]->args[0]); + } + ex = fixexpr(ex, env); + } else if (!strcmp(cp, setdiffname) && *setremname && + (ex3 = singlevar(ex->args[0])) != NULL && + exprsame(ex->args[0], ex->args[1], 0) && + !exproccurs(ex3, ex->args[2]) && + ex->args[2]->kind == EK_BICALL && + (!strcmp(ex->args[2]->val.s, setaddname) || + (!strcmp(ex->args[2]->val.s, setexpandname) && + checkconst(ex->args[2]->args[1], 0))) && + totempvar(ex->args[2])) { + if (!strcmp(ex->args[2]->val.s, setexpandname)) { + ex = grabarg(ex, 0); + } else { + ex = makeexpr_comma(ex, ex->args[2]); + ex->args[0]->args[2] = ex->args[1]->args[0]; + ex->args[1]->args[0] = copyexpr(ex->args[0]->args[0]); + strchange(&ex->args[1]->val.s, setremname); + } + ex = fixexpr(ex, env); + } else { + for (i = 0; i < ex->nargs; i++) + ex->args[i] = fixexpr(ex->args[i], ENV_EXPR); + ex = cleansprintf(ex); + if (!strcmp(cp, "sprintf")) { + if (checkstring(ex->args[1], "%s")) { + delfreearg(&ex, 1); + strchange(&ex->val.s, "strcpy"); + ex = fixexpr(ex, env); + } else if (sprintf_value != 1 && env != ENV_STMT) { + if (*sprintfname) { + strchange(&ex->val.s, format_s("*%s", sprintfname)); + } else { + strchange(&ex->val.s, "*sprintf"); + ex = makeexpr_comma(ex, copyexpr(ex->args[0])); + } + } + } else if (!strcmp(cp, "strcpy")) { + if (env == ENV_STMT && + ex->args[1]->kind == EK_BICALL && + !strcmp(ex->args[1]->val.s, "strcpy") && + nosideeffects(ex->args[1]->args[0], 1)) { + ex2 = ex->args[1]; + ex->args[1] = copyexpr(ex2->args[0]); + ex = makeexpr_comma(ex2, ex); + } + } else if (!strcmp(cp, "memcpy")) { + strchange(&ex->val.s, format_s("*%s", memcpyname)); + if (!strcmp(memcpyname, "*bcopy")) { + swapexprs(ex->args[0], ex->args[1]); + if (env != ENV_STMT) + ex = makeexpr_comma(ex, copyexpr(ex->args[1])); + } +#if 0 + } else if (!strcmp(cp, setunionname) && + (ex3 = singlevar(ex->args[0])) != NULL && + ((i=1, exprsame(ex->args[0], ex->args[i], 0)) || + (i=2, exprsame(ex->args[0], ex->args[i], 0))) && + !exproccurs(ex3, ex->args[3-i])) { + ep = &ex->args[3-i]; + while ((ex2 = *ep)->kind == EK_BICALL && + (!strcmp(ex2->val.s, setaddname) || + !strcmp(ex2->val.s, setaddrangename))) + ep = &ex2->args[0]; + if (ex2->kind == EK_BICALL && + !strcmp(ex2->val.s, setexpandname) && + checkconst(ex2->args[1], 0) && + (mp = istempvar(ex2->args[0])) != NULL) { + if (ex2 == ex->args[3-i]) { + ex = grabarg(ex, i); + } else { + freeexpr(ex2); + *ep = ex->args[i]; + ex = ex->args[3-i]; + } + } + } else if (!strcmp(cp, setdiffname) && *setremname && + (ex3 = singlevar(ex->args[0])) != NULL && + exprsame(ex->args[0], ex->args[1], 0) && + !exproccurs(ex3, ex->args[2])) { + ep = &ex->args[2]; + while ((ex2 = *ep)->kind == EK_BICALL && + !strcmp(ex2->val.s, setaddname)) + ep = &ex2->args[0]; + if (ex2->kind == EK_BICALL && + !strcmp(ex2->val.s, setexpandname) && + checkconst(ex2->args[1], 0) && + (mp = istempvar(ex2->args[0])) != NULL) { + if (ex2 == ex->args[2]) { + ex = grabarg(ex, 1); + } else { + ex2 = ex->args[2]; + while (ex2->kind == EK_BICALL && + !strcmp(ex2->val.s, setaddname)) { + strchange(&ex2->val.s, setremname); + ex2 = ex2->args[0]; + } + freeexpr(ex2); + *ep = ex->args[1]; + ex = ex->args[2]; + } + } +#endif + } else if (!strcmp(cp, setexpandname) && env == ENV_STMT && + checkconst(ex->args[1], 0)) { + ex = makeexpr_assign(makeexpr_hat(ex->args[0], 0), + ex->args[1]); + } else if (!strcmp(cp, getbitsname)) { + type = ex->args[0]->val.type; + if (type->kind == TK_POINTER) + type = type->basetype; + sbuf[0] = (type->issigned) ? 'S' : 'U'; + sbuf[1] = (type->kind == TK_ARRAY) ? 'B' : 'S'; + sbuf[2] = 0; + if (sbuf[1] == 'S' && + type->smax->val.type == tp_boolean) { + ex = makeexpr_rel(EK_NE, + makeexpr_bin(EK_BAND, tp_integer, + ex->args[0], + makeexpr_bin(EK_LSH, tp_integer, + makeexpr_longcast(makeexpr_long(1), + type->basetype + == tp_unsigned), + ex->args[1])), + makeexpr_long(0)); + ex = fixexpr(ex, env); + } else + strchange(&ex->val.s, format_s(cp, sbuf)); + } else if (!strcmp(cp, putbitsname)) { + type = ex->args[0]->val.type; + if (type->kind == TK_POINTER) + type = type->basetype; + sbuf[0] = (type->issigned) ? 'S' : 'U'; + sbuf[1] = (type->kind == TK_ARRAY) ? 'B' : 'S'; + sbuf[2] = 0; + if (sbuf[1] == 'S' && + type->smax->val.type == tp_boolean) { + ex = makeexpr_assign(ex->args[0], + makeexpr_bin(EK_BOR, tp_integer, + copyexpr(ex->args[0]), + makeexpr_bin(EK_LSH, tp_integer, + makeexpr_longcast(ex->args[2], + type->basetype + == tp_unsigned), + ex->args[1]))); + } else + strchange(&ex->val.s, format_s(cp, sbuf)); + } else if (!strcmp(cp, storebitsname)) { + type = ex->args[0]->val.type; + if (type->kind == TK_POINTER) + type = type->basetype; + sbuf[0] = (type->issigned) ? 'S' : 'U'; + sbuf[1] = (type->kind == TK_ARRAY) ? 'B' : 'S'; + sbuf[2] = 0; + strchange(&ex->val.s, format_s(cp, sbuf)); + } else if (!strcmp(cp, clrbitsname)) { + type = ex->args[0]->val.type; + if (type->kind == TK_POINTER) + type = type->basetype; + sbuf[0] = (type->kind == TK_ARRAY) ? 'B' : 'S'; + sbuf[1] = 0; + if (sbuf[0] == 'S' && + type->smax->val.type == tp_boolean) { + ex = makeexpr_assign(ex->args[0], + makeexpr_bin(EK_BAND, tp_integer, + copyexpr(ex->args[0]), + makeexpr_un(EK_BNOT, tp_integer, + makeexpr_bin(EK_LSH, tp_integer, + makeexpr_longcast(makeexpr_long(1), + type->basetype + == tp_unsigned), + ex->args[1])))); + } else + strchange(&ex->val.s, format_s(cp, sbuf)); + } else if (!strcmp(cp, "fopen")) { + if (which_lang == LANG_HP && + ex->args[0]->kind == EK_CONST && + ex->args[0]->val.type->kind == TK_STRING && + ex->args[0]->val.i >= 1 && + ex->args[0]->val.i <= 2 && + isdigit(ex->args[0]->val.s[0]) && + (ex->args[0]->val.i == 1 || + isdigit(ex->args[0]->val.s[1]))) { + strchange(&ex->val.s, "fdopen"); + ex->args[0] = makeexpr_long(atoi(ex->args[0]->val.s)); + } + } + } + break; + + case EK_NOT: + ex = makeexpr_not(fixexpr(grabarg(ex, 0), ENV_BOOL)); + break; + + case EK_AND: + case EK_OR: + for (i = 0; i < ex->nargs; ) { + ex->args[i] = fixexpr(ex->args[i], ENV_BOOL); + if (checkconst(ex->args[i], (ex->kind == EK_OR) ? 0 : 1) && + ex->nargs > 1) + delfreearg(&ex, i); + else if (checkconst(ex->args[i], (ex->kind == EK_OR) ? 1 : 0)) + return grabarg(ex, i); + else + i++; + } + if (ex->nargs == 1) + ex = grabarg(ex, 0); + break; + + case EK_EQ: + case EK_NE: + ex->args[0] = fixexpr(ex->args[0], ENV_EXPR); + ex->args[1] = fixexpr(ex->args[1], ENV_EXPR); + if (checkconst(ex->args[1], 0) && env == ENV_BOOL && + ord_type(ex->args[1]->val.type)->kind != TK_ENUM && + (implicitzero > 0 || + (implicitzero < 0 && ex->args[0]->kind == EK_BICALL && + boolean_bicall(ex->args[0]->val.s)))) { + if (ex->kind == EK_EQ) + ex = makeexpr_not(grabarg(ex, 0)); + else { + ex = grabarg(ex, 0); + ex->val.type = tp_boolean; + } + } + break; + + case EK_COND: + ex->args[0] = fixexpr(ex->args[0], ENV_BOOL); +#if 0 + val = eval_expr(ex->args[0]); +#else + val = ex->args[0]->val; + if (ex->args[0]->kind != EK_CONST) + val.type = NULL; +#endif + if (val.type == tp_boolean) { + ex = grabarg(ex, (val.i) ? 1 : 2); + ex = fixexpr(ex, env); + } else { + ex->args[1] = fixexpr(ex->args[1], env); + ex->args[2] = fixexpr(ex->args[2], env); + } + break; + + case EK_COMMA: + for (i = 0; i < ex->nargs; ) { + j = (i < ex->nargs-1); + ex->args[i] = fixexpr(ex->args[i], j ? ENV_STMT : env); + if (nosideeffects(ex->args[i], 1) && j) { + delfreearg(&ex, i); + } else if (ex->args[i]->kind == EK_COMMA) { + ex2 = ex->args[i]; + ex->args[i++] = ex2->args[0]; + for (j = 1; j < ex2->nargs; j++) + insertarg(&ex, i++, ex2->args[j]); + FREE(ex2); + } else + i++; + } + if (ex->nargs == 1) + ex = grabarg(ex, 0); + break; + + case EK_CHECKNIL: + ex->args[0] = fixexpr(ex->args[0], ENV_EXPR); + if (ex->nargs == 2) { + ex->args[1] = fixexpr(ex->args[1], ENV_EXPR); + ex2 = makeexpr_assign(copyexpr(ex->args[1]), ex->args[0]); + ex3 = ex->args[1]; + } else { + ex2 = copyexpr(ex->args[0]); + ex3 = ex->args[0]; + } + type = ex->args[0]->val.type; + type2 = ex->val.type; + ex = makeexpr_cond(makeexpr_rel(EK_NE, ex2, makeexpr_nil()), + ex3, + makeexpr_cast(makeexpr_bicall_0(name_NILCHECK, + tp_int), + type)); + ex->val.type = type2; + ex = fixexpr(ex, env); + break; + + case EK_CAST: + case EK_ACTCAST: + if (env == ENV_STMT) { + ex = fixexpr(grabarg(ex, 0), ENV_STMT); + } else { + ex->args[0] = fixexpr(ex->args[0], ENV_EXPR); + } + break; + + default: + for (i = 0; i < ex->nargs; i++) + ex->args[i] = fixexpr(ex->args[i], ENV_EXPR); + break; + } + if (debug>4) {fprintf(outf, "fixexpr returns "); dumpexpr(ex); fprintf(outf, "\n");} + return fix_expression(ex, env); +} + + + + + + + + +/* Output an expression */ + + +#define bitOp(k) ((k)==EK_BAND || (k)==EK_BOR || (k)==EK_BXOR) + +#define shfOp(k) ((k)==EK_LSH || (k)==EK_RSH) + +#define logOp(k) ((k)==EK_AND || (k)==EK_OR) + +#define relOp(k) ((k)==EK_EQ || (k)==EK_LT || (k)==EK_GT || \ + (k)==EK_NE || (k)==EK_GE || (k)==EK_LE) + +#define mathOp(k) ((k)==EK_PLUS || (k)==EK_TIMES || (k)==EK_NEG || \ + (k)==EK_DIV || (k)==EK_DIVIDE || (k)==EK_MOD) + +#define divOp(k) ((k)==EK_DIV || (k)==EK_DIVIDE) + + +Static int incompat(ex, num, prec) +Expr *ex; +int num, prec; +{ + Expr *subex = ex->args[num]; + + if (extraparens == 0) + return prec; + if (ex->kind == subex->kind) { + if (logOp(ex->kind) || bitOp(ex->kind) || + (divOp(ex->kind) && num == 0)) + return -99; /* not even invisible parens */ + else if (extraparens != 2) + return prec; + } + if (extraparens == 2) + return 15; + if (divOp(ex->kind) && num == 0 && + (subex->kind == EK_TIMES || divOp(subex->kind))) + return -99; + if (bitOp(ex->kind) || shfOp(ex->kind)) + return 15; + if (relOp(ex->kind) && relOp(subex->kind)) + return 15; + if ((relOp(ex->kind) || logOp(ex->kind)) && bitOp(subex->kind)) + return 15; + if (ex->kind == EK_COMMA) + return 15; + if (ex->kind == EK_ASSIGN && relOp(subex->kind)) + return 15; + if (extraparens != 1) + return prec; + if (ex->kind == EK_ASSIGN) + return prec; + if (relOp(ex->kind) && mathOp(subex->kind)) + return prec; + return 15; +} + + + + +#define EXTRASPACE() if (spaceexprs == 1) output(" ") +#define NICESPACE() if (spaceexprs != 0) output(" ") + +#define setprec(p) \ + if ((subprec=(p)) <= prec) { \ + parens = 1; output("("); \ + } + +#define setprec2(p) \ + if ((subprec=(p)) <= prec) { \ + parens = 1; output("("); \ + } else if (prec != -99) { \ + parens = 2; output((breakparens == 1) ? "\010" : "\003"); \ + } + +#define setprec3(p) \ + if ((subprec=(p)) <= prec) { \ + parens = 1; output("("); \ + } else if (prec != -99) { \ + parens = 2; output((prec > 2 && breakparens != 0) ? "\010" \ + : "\003"); \ + } + + +Static void outop3(breakbefore, name) +int breakbefore; +char *name; +{ + if (breakbefore & BRK_LEFT) { + output("\002"); + if (breakbefore & BRK_RPREF) + output("\013"); + } + output(name); + if (breakbefore & BRK_HANG) + output("\015"); + if (breakbefore & BRK_RIGHT) { + output("\002"); + if (breakbefore & BRK_LPREF) + output("\013"); + } +} + +#define outop(name) do { \ + NICESPACE(); outop3(breakflag, name); NICESPACE(); \ +} while (0) + +#define outop2(name) do { \ + EXTRASPACE(); outop3(breakflag, name); EXTRASPACE(); \ +} while (0) + +#define checkbreak(code) do { \ + breakflag=(code); \ + if ((prec != -99) && (breakflag & BRK_ALLNONE)) output("\007"); \ +} while (0) + + +Static void out_ctx(ctx, address) +Meaning *ctx; +int address; +{ + Meaning *ctx2; + int breakflag = breakbeforedot; + + if (ctx->kind == MK_FUNCTION && ctx->varstructflag) { + if (curctx != ctx) { + if (address && curctx->ctx && curctx->ctx != ctx) { + output("\003"); + if (breakflag & BRK_ALLNONE) + output("\007"); + } + output(format_s(name_LINK, curctx->ctx->name)); + ctx2 = curctx->ctx; + while (ctx2 && ctx2 != ctx) { + outop2("->"); + output(format_s(name_LINK, ctx2->ctx->name)); + ctx2 = ctx2->ctx; + } + if (ctx2 != ctx) + intwarning("out_ctx", + format_s("variable from %s not present in context path [307]", + ctx->name)); + if (address && curctx->ctx && curctx->ctx != ctx) + output("\004"); + if (!address) + outop2("->"); + } else { + if (address) { + output("&"); + EXTRASPACE(); + } + output(format_s(name_VARS, curctx->name)); + if (!address) { + outop2("."); + } + } + } else { + if (address) + output("NULL"); + } +} + + + +void out_var(mp, prec) +Meaning *mp; +int prec; +{ + switch (mp->kind) { + + case MK_CONST: + output(mp->name); + return; + + case MK_VAR: + case MK_VARREF: + case MK_VARMAC: + case MK_PARAM: + case MK_VARPARAM: + if (mp->varstructflag) { + output("\003"); + out_ctx(mp->ctx, 0); + output(mp->name); + output("\004"); + } else + output(mp->name); + return; + + default: + if (mp->name) + output(mp->name); + else + intwarning("out_var", "mp->sym == NULL [308]"); + return; + } +} + + + +Static int scanfield(variants, unions, lev, mp, field) +Meaning **variants, *mp, *field; +short *unions; +int lev; +{ + int i, num, breakflag; + Value v; + + unions[lev] = (mp && mp->kind == MK_VARIANT); + while (mp && mp->kind == MK_FIELD) { + if (mp == field) { + for (i = 0; i < lev; i++) { + v = variants[i]->val; /* sidestep a Sun 386i compiler bug */ + num = ord_value(v); + breakflag = breakbeforedot; + if (!unions[i]) { + output(format_s(name_UNION, "")); + outop2("."); + } + if (variants[i]->ctx->cnext || + variants[i]->ctx->kind != MK_FIELD) { + output(format_s(name_VARIANT, variantfieldname(num))); + outop2("."); + } + } + output(mp->name); + return 1; + } + mp = mp->cnext; + } + while (mp && mp->kind == MK_VARIANT) { + variants[lev] = mp; + if (scanfield(variants, unions, lev+1, mp->ctx, field)) + return 1; + mp = mp->cnext; + } + return 0; +} + + +void out_field(mp) +Meaning *mp; +{ + Meaning *variants[50]; + short unions[51]; + + if (!scanfield(variants, unions, 0, mp->rectype->fbase, mp)) + intwarning("out_field", "field name not in tree [309]"); + else if (mp->warnifused) { + if (mp->rectype->meaning) + note(format_ss("Reference to field %s of record %s [282]", + mp->name, mp->rectype->meaning->name)); + else + note(format_s("Reference to field %s [282]", mp->name)); + } +} + + + + +Static void wrexpr(ex, prec) +Expr *ex; +int prec; +{ + short parens = 0; + int subprec, i, j, minusflag, breakflag = 0; + int saveindent; + Expr *ex2, *ex3; + char *cp; + Meaning *mp; + Symbol *sp; + + if (debug>2) { fprintf(outf,"wrexpr{"); dumpexpr(ex); fprintf(outf,", %d}\n", prec); } + switch (ex->kind) { + + case EK_VAR: + mp = (Meaning *)ex->val.i; + if (mp->warnifused) + note(format_s("Reference to %s [283]", mp->name)); + out_var(mp, prec); + break; + + case EK_NAME: + output(ex->val.s); + break; + + case EK_MACARG: + output("<meef>"); + intwarning("wrexpr", "Stray EK_MACARG encountered [310]"); + break; + + case EK_CTX: + out_ctx((Meaning *)ex->val.i, 1); + break; + + case EK_CONST: + if (ex->nargs > 0) + cp = value_name(ex->val, ex->args[0]->val.s, 0); + else + cp = value_name(ex->val, NULL, 0); + if (*cp == '-') + setprec(14); + output(cp); + break; + + case EK_LONGCONST: + if (ex->nargs > 0) + cp = value_name(ex->val, ex->args[0]->val.s, 1); + else + cp = value_name(ex->val, NULL, 1); + if (*cp == '-') + setprec(14); + output(cp); + break; + + case EK_STRUCTCONST: + ex3 = NULL; + for (i = 0; i < ex->nargs; i++) { + ex2 = ex->args[i]; + if (ex2->kind == EK_STRUCTOF) { + j = ex2->val.i; + ex2 = ex2->args[0]; + } else + j = 1; + if (ex2->kind == EK_VAR) { + mp = (Meaning *)ex2->val.i; + if (mp->kind == MK_CONST && + mp->val.type && + (mp->val.type->kind == TK_RECORD || + mp->val.type->kind == TK_ARRAY)) { + if (foldconsts != 1) + note(format_s("Expanding constant %s into another constant [284]", + mp->name)); + ex2 = (Expr *)mp->val.i; + } + } + while (--j >= 0) { + if (ex3) { + if (ex3->kind == EK_STRUCTCONST || + ex2->kind == EK_STRUCTCONST) + output(",\n"); + else if (spacecommas) + output(",\001 "); + else + output(",\001"); + } + if (ex2->kind == EK_STRUCTCONST) { + output("{ \005"); + saveindent = outindent; + moreindent(extrainitindent); + out_expr(ex2); + outindent = saveindent; + output(" }"); + } else + out_expr(ex2); + ex3 = ex2; + } + } + break; + + case EK_FUNCTION: + mp = (Meaning *)ex->val.i; + sp = findsymbol_opt(mp->name); + if ((sp && (sp->flags & WARNLIBR)) || mp->warnifused) + note(format_s("Called procedure %s [285]", mp->name)); + output(mp->name); + if (spacefuncs) + output(" "); + output("(\002"); + j = sp ? (sp->flags & FUNCBREAK) : 0; + if (j == FALLBREAK) + output("\007"); + for (i = 0; i < ex->nargs; i++) { + if ((j == FSPCARG1 && i == 1) || + (j == FSPCARG2 && i == 2) || + (j == FSPCARG3 && i == 3)) + if (spacecommas) + output(",\011 "); + else + output(",\011"); + else if (i > 0) + if (spacecommas) + output(",\002 "); + else + output(",\002"); + out_expr(ex->args[i]); + } + if (mp->ctx->kind == MK_FUNCTION && mp->ctx->varstructflag) { + if (i > 0) + if (spacecommas) + output(",\002 "); + else + output(",\002"); + out_ctx(mp->ctx, 1); + } + output(")"); + break; + + case EK_BICALL: + cp = ex->val.s; + while (*cp == '*') + cp++; + sp = findsymbol_opt(cp); + if (sp && (sp->flags & WARNLIBR)) + note(format_s("Called library procedure %s [286]", cp)); + output(cp); + if (spacefuncs) + output(" "); + output("(\002"); + j = sp ? (sp->flags & FUNCBREAK) : 0; + if (j == FALLBREAK) + output("\007"); + for (i = 0; i < ex->nargs; i++) { + if ((j == FSPCARG1 && i == 1) || + (j == FSPCARG2 && i == 2) || + (j == FSPCARG3 && i == 3)) + if (spacecommas) + output(",\011 "); + else + output(",\011"); + else if (i > 0) + if (spacecommas) + output(",\002 "); + else + output(",\002"); + out_expr(ex->args[i]); + } + output(")"); + break; + + case EK_SPCALL: + setprec(16); + if (starfunctions) { + output("(\002*"); + wrexpr(ex->args[0], 13); + output(")"); + } else + wrexpr(ex->args[0], subprec-1); + if (spacefuncs) + output(" "); + output("(\002"); + for (i = 1; i < ex->nargs; i++) { + if (i > 1) + if (spacecommas) + output(",\002 "); + else + output(",\002"); + out_expr(ex->args[i]); + } + output(")"); + break; + + case EK_INDEX: + setprec(16); + wrexpr(ex->args[0], subprec-1); + if (lookback(1) == ']') + output("\001"); + output("["); + out_expr(ex->args[1]); + output("]"); + break; + + case EK_DOT: + setprec2(16); + checkbreak(breakbeforedot); + if (ex->args[0]->kind == EK_HAT) { + wrexpr(ex->args[0]->args[0], subprec-1); + outop2("->"); + } else if (ex->args[0]->kind == EK_CTX) { + out_ctx((Meaning *)ex->args[0]->val.i, 0); + } else { + wrexpr(ex->args[0], subprec-1); + outop2("."); + } + if (ex->val.i) + out_field((Meaning *)ex->val.i); + else + output(ex->val.s); + break; + + case EK_POSTINC: + if (prec == 0 && !postincrement) { + setprec(14); + output("++"); + EXTRASPACE(); + wrexpr(ex->args[0], subprec); + } else { + setprec(15); + wrexpr(ex->args[0], subprec); + EXTRASPACE(); + output("++"); + } + break; + + case EK_POSTDEC: + if (prec == 0 && !postincrement) { + setprec(14); + output("--"); + EXTRASPACE(); + wrexpr(ex->args[0], subprec); + } else { + setprec(15); + wrexpr(ex->args[0], subprec); + EXTRASPACE(); + output("--"); + } + break; + + case EK_HAT: + setprec(14); + if (lookback_prn(1) == '/') + output(" "); + output("*"); + EXTRASPACE(); + wrexpr(ex->args[0], subprec-1); + break; + + case EK_ADDR: + setprec(14); + if (lookback_prn(1) == '&') + output(" "); + output("&"); + EXTRASPACE(); + wrexpr(ex->args[0], subprec-1); + break; + + case EK_NEG: + setprec(14); + output("-"); + EXTRASPACE(); + if (ex->args[0]->kind == EK_TIMES) + wrexpr(ex->args[0], 12); + else + wrexpr(ex->args[0], subprec-1); + break; + + case EK_NOT: + setprec(14); + output("!"); + EXTRASPACE(); + wrexpr(ex->args[0], subprec-1); + break; + + case EK_BNOT: + setprec(14); + output("~"); + EXTRASPACE(); + wrexpr(ex->args[0], subprec-1); + break; + + case EK_CAST: + case EK_ACTCAST: + if (similartypes(ex->val.type, ex->args[0]->val.type)) { + wrexpr(ex->args[0], prec); + } else if (ord_type(ex->args[0]->val.type)->kind == TK_ENUM && + ex->val.type == tp_int && !useenum) { + wrexpr(ex->args[0], prec); + } else { + setprec2(14); + output("("); + out_type(ex->val.type, 0); + output(")\002"); + EXTRASPACE(); + if (extraparens != 0) + wrexpr(ex->args[0], 15); + else + wrexpr(ex->args[0], subprec-1); + } + break; + + case EK_LITCAST: + setprec2(14); + output("("); + out_expr(ex->args[0]); + output(")\002"); + EXTRASPACE(); + if (extraparens != 0) + wrexpr(ex->args[1], 15); + else + wrexpr(ex->args[1], subprec-1); + break; + + case EK_SIZEOF: + setprec(14); + output("sizeof"); + if (spacefuncs) + output(" "); + output("("); + out_expr(ex->args[0]); + output(")"); + break; + + case EK_TYPENAME: + out_type(ex->val.type, 1); + break; + + case EK_TIMES: + setprec2(13); + checkbreak(breakbeforearith); + ex2 = copyexpr(ex); + if (expr_looks_neg(ex2->args[ex2->nargs-1])) { + ex2->args[0] = makeexpr_neg(ex2->args[0]); + ex2->args[ex2->nargs-1] = makeexpr_neg(ex2->args[ex2->nargs-1]); + } + wrexpr(ex2->args[0], incompat(ex2, 0, subprec-1)); + for (i = 1; i < ex2->nargs; i++) { + outop("*"); + wrexpr(ex2->args[i], incompat(ex2, i, subprec)); + } + freeexpr(ex2); + break; + + case EK_DIV: + case EK_DIVIDE: + setprec2(13); + checkbreak(breakbeforearith); + wrexpr(ex->args[0], incompat(ex, 0, subprec-1)); + outop("/"); + wrexpr(ex->args[1], incompat(ex, 1, subprec)); + break; + + case EK_MOD: + setprec2(13); + checkbreak(breakbeforearith); + wrexpr(ex->args[0], incompat(ex, 0, subprec-1)); + outop("%"); + wrexpr(ex->args[1], incompat(ex, 1, subprec)); + break; + + case EK_PLUS: + setprec2(12); + checkbreak(breakbeforearith); + ex2 = copyexpr(ex); + minusflag = 0; + if (expr_looks_neg(ex2->args[0])) { + j = 1; + while (j < ex2->nargs && expr_looks_neg(ex2->args[j])) j++; + if (j < ex2->nargs) + swapexprs(ex2->args[0], ex2->args[j]); + } else if (ex2->val.i && ex2->nargs == 2) { /* this was originally "a-b" */ + if (isliteralconst(ex2->args[1], NULL) != 2) { + if (expr_neg_cost(ex2->args[1]) <= 0) { + minusflag = 1; + } else if (expr_neg_cost(ex2->args[0]) <= 0) { + swapexprs(ex2->args[0], ex2->args[1]); + if (isliteralconst(ex2->args[0], NULL) != 2) + minusflag = 1; + } + } + } + wrexpr(ex2->args[0], incompat(ex, 0, subprec)); + for (i = 1; i < ex2->nargs; i++) { + if (expr_looks_neg(ex2->args[i]) || minusflag) { + outop("-"); + ex2->args[i] = makeexpr_neg(ex2->args[i]); + } else + outop("+"); + wrexpr(ex2->args[i], incompat(ex, i, subprec)); + } + freeexpr(ex2); + break; + + case EK_LSH: + setprec3(11); + checkbreak(breakbeforearith); + wrexpr(ex->args[0], incompat(ex, 0, subprec)); + outop("<<"); + wrexpr(ex->args[1], incompat(ex, 1, subprec)); + break; + + case EK_RSH: + setprec3(11); + checkbreak(breakbeforearith); + wrexpr(ex->args[0], incompat(ex, 0, subprec)); + outop(">>"); + wrexpr(ex->args[1], incompat(ex, 1, subprec)); + break; + + case EK_LT: + setprec2(10); + checkbreak(breakbeforerel); + wrexpr(ex->args[0], incompat(ex, 0, subprec)); + outop("<"); + wrexpr(ex->args[1], incompat(ex, 0, subprec)); + break; + + case EK_GT: + setprec2(10); + checkbreak(breakbeforerel); + wrexpr(ex->args[0], incompat(ex, 0, subprec)); + outop(">"); + wrexpr(ex->args[1], incompat(ex, 0, subprec)); + break; + + case EK_LE: + setprec2(10); + checkbreak(breakbeforerel); + wrexpr(ex->args[0], incompat(ex, 0, subprec)); + outop("<="); + wrexpr(ex->args[1], incompat(ex, 0, subprec)); + break; + + case EK_GE: + setprec2(10); + checkbreak(breakbeforerel); + wrexpr(ex->args[0], incompat(ex, 0, subprec)); + outop(">="); + wrexpr(ex->args[1], incompat(ex, 0, subprec)); + break; + + case EK_EQ: + setprec2(9); + checkbreak(breakbeforerel); + wrexpr(ex->args[0], incompat(ex, 0, subprec)); + outop("=="); + wrexpr(ex->args[1], incompat(ex, 0, subprec)); + break; + + case EK_NE: + setprec2(9); + checkbreak(breakbeforerel); + wrexpr(ex->args[0], incompat(ex, 0, subprec)); + outop("!="); + wrexpr(ex->args[1], incompat(ex, 0, subprec)); + break; + + case EK_BAND: + setprec3(8); + if (ex->val.type == tp_boolean) + checkbreak(breakbeforelog); + else + checkbreak(breakbeforearith); + wrexpr(ex->args[0], incompat(ex, 0, subprec-1)); + outop("&"); + wrexpr(ex->args[1], incompat(ex, 1, subprec-1)); + break; + + case EK_BXOR: + setprec3(7); + checkbreak(breakbeforearith); + wrexpr(ex->args[0], incompat(ex, 0, subprec-1)); + outop("^"); + wrexpr(ex->args[1], incompat(ex, 1, subprec-1)); + break; + + case EK_BOR: + setprec3(6); + if (ex->val.type == tp_boolean) + checkbreak(breakbeforelog); + else + checkbreak(breakbeforearith); + wrexpr(ex->args[0], incompat(ex, 0, subprec-1)); + outop("|"); + wrexpr(ex->args[1], incompat(ex, 1, subprec-1)); + break; + + case EK_AND: + setprec3(5); + checkbreak(breakbeforelog); + wrexpr(ex->args[0], incompat(ex, 0, subprec-1)); + outop("&&"); + wrexpr(ex->args[1], incompat(ex, 1, subprec-1)); + break; + + case EK_OR: + setprec3(4); + checkbreak(breakbeforelog); + wrexpr(ex->args[0], incompat(ex, 0, subprec-1)); + outop("||"); + wrexpr(ex->args[1], incompat(ex, 1, subprec-1)); + break; + + case EK_COND: + setprec3(3); + i = 0; + for (;;) { + i++; + if (extraparens != 0) + wrexpr(ex->args[0], 15); + else + wrexpr(ex->args[0], subprec); + NICESPACE(); + output("\002?"); + NICESPACE(); + out_expr(ex->args[1]); + if (ex->args[2]->kind == EK_COND) { + NICESPACE(); + output("\002:"); + NICESPACE(); + ex = ex->args[2]; + } else { + NICESPACE(); + output((i == 1) ? "\017:" : "\002:"); + NICESPACE(); + wrexpr(ex->args[2], subprec-1); + break; + } + } + break; + + case EK_ASSIGN: + if (ex->args[1]->kind == EK_PLUS && + exprsame(ex->args[1]->args[0], ex->args[0], 2) && + ex->args[1]->args[1]->kind == EK_CONST && + ex->args[1]->args[1]->val.type->kind == TK_INTEGER && + abs(ex->args[1]->args[1]->val.i) == 1) { + if (prec == 0 && postincrement) { + setprec(15); + wrexpr(ex->args[0], subprec); + EXTRASPACE(); + if (ex->args[1]->args[1]->val.i == 1) + output("++"); + else + output("--"); + } else { + setprec(14); + if (ex->args[1]->args[1]->val.i == 1) + output("++"); + else + output("--"); + EXTRASPACE(); + wrexpr(ex->args[0], subprec-1); + } + } else { + setprec2(2); + checkbreak(breakbeforeassign); + wrexpr(ex->args[0], subprec); + ex2 = copyexpr(ex->args[1]); + j = -1; + switch (ex2->kind) { + + case EK_PLUS: + case EK_TIMES: + case EK_BAND: + case EK_BOR: + case EK_BXOR: + for (i = 0; i < ex2->nargs; i++) { + if (exprsame(ex->args[0], ex2->args[i], 2)) { + j = i; + break; + } + if (ex2->val.type->kind == TK_REAL) + break; /* non-commutative */ + } + break; + + case EK_DIVIDE: + case EK_DIV: + case EK_MOD: + case EK_LSH: + case EK_RSH: + if (exprsame(ex->args[0], ex2->args[0], 2)) + j = 0; + break; + + default: + break; + } + if (j >= 0) { + if (ex2->nargs == 2) + ex2 = grabarg(ex2, 1-j); + else + delfreearg(&ex2, j); + switch (ex->args[1]->kind) { + + case EK_PLUS: + if (expr_looks_neg(ex2)) { + outop("-="); + ex2 = makeexpr_neg(ex2); + } else + outop("+="); + break; + + case EK_TIMES: + outop("*="); + break; + + case EK_DIVIDE: + case EK_DIV: + outop("/="); + break; + + case EK_MOD: + outop("%="); + break; + + case EK_LSH: + outop("<<="); + break; + + case EK_RSH: + outop(">>="); + break; + + case EK_BAND: + outop("&="); + break; + + case EK_BOR: + outop("|="); + break; + + case EK_BXOR: + outop("^="); + break; + + default: + break; + } + } else { + output(" "); + outop3(breakbeforeassign, "="); + output(" "); + } + if (extraparens != 0 && + (ex2->kind == EK_EQ || ex2->kind == EK_NE || + ex2->kind == EK_GT || ex2->kind == EK_LT || + ex2->kind == EK_GE || ex2->kind == EK_LE || + ex2->kind == EK_AND || ex2->kind == EK_OR)) + wrexpr(ex2, 16); + else + wrexpr(ex2, subprec-1); + freeexpr(ex2); + } + break; + + case EK_COMMA: + setprec3(1); + for (i = 0; i < ex->nargs-1; i++) { + wrexpr(ex->args[i], subprec); + output(",\002"); + if (spacecommas) + NICESPACE(); + } + wrexpr(ex->args[ex->nargs-1], subprec); + break; + + default: + intwarning("wrexpr", "bad ex->kind [311]"); + } + switch (parens) { + case 1: + output(")"); + break; + case 2: + output("\004"); + break; + } +} + + + +/* will parenthesize assignments and "," operators */ + +void out_expr(ex) +Expr *ex; +{ + wrexpr(ex, 2); +} + + + +/* will not parenthesize anything at top level */ + +void out_expr_top(ex) +Expr *ex; +{ + wrexpr(ex, 0); +} + + + +/* will parenthesize unless only writing a factor */ + +void out_expr_factor(ex) +Expr *ex; +{ + wrexpr(ex, 15); +} + + + +/* will parenthesize always */ + +void out_expr_parens(ex) +Expr *ex; +{ + output("("); + wrexpr(ex, 1); + output(")"); +} + + + +/* evaluate expression for side effects only */ +/* no top-level parentheses */ + +void out_expr_stmt(ex) +Expr *ex; +{ + wrexpr(ex, 0); +} + + + +/* evaluate expression for boolean (zero/non-zero) result only */ +/* parenthesizes like out_expr() */ + +void out_expr_bool(ex) +Expr *ex; +{ + wrexpr(ex, 2); +} + + + + +/* End. */ + + + diff --git a/MultiSource/Benchmarks/MallocBench/p2c/stuff.c b/MultiSource/Benchmarks/MallocBench/p2c/stuff.c new file mode 100644 index 00000000..37a0dd9f --- /dev/null +++ b/MultiSource/Benchmarks/MallocBench/p2c/stuff.c @@ -0,0 +1,839 @@ +/* "p2c", a Pascal to C translator. + Copyright (C) 1989, 1990, 1991 Free Software Foundation. + Author's address: daveg@csvax.caltech.edu; 256-80 Caltech/Pasadena CA 91125. + +This program is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation (any version). + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; see the file COPYING. If not, write to +the Free Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ + + + +#define PROTO_STUFF_C +#include "trans.h" + + + + + + +/* Called regularly, for debugging purposes */ + +void debughook() +{ +#if 0 + Symbol *sp; + Meaning *mp; + static int flag = 0; + + sp = findsymbol_opt("DEFSTIPPLES"); + if (sp) { + mp = sp->mbase; + if (mp) { + flag = 1; + if (mp->sym != sp || mp->snext) + intwarning("debughook", "Inconsistent!"); + } else + if (flag) + intwarning("debughook", "Missing!"); + } +#endif +} + + + + + + +/* The "Strlist" data type, like in NEWASM */ + + +/* Add a string to end of strlist */ + +Strlist *strlist_append(base, s) +register Strlist **base; +register char *s; +{ + register Strlist *p; + + while (*base) + base = &(*base)->next; + *base = p = ALLOCV(sizeof(Strlist) + strlen(s), Strlist, strlists); + p->next = NULL; + p->value = 0; + strcpy(p->s, s); + return p; +} + + + +/* Insert a string at front of strlist */ + +Strlist *strlist_insert(base, s) +register Strlist **base; +register char *s; +{ + register Strlist *p; + + p = ALLOCV(sizeof(Strlist) + strlen(s), Strlist, strlists); + p->next = *base; + *base = p; + p->value = 0; + strcpy(p->s, s); + return p; +} + + + +/* Add a string to a sorted strlist */ + +Strlist *strlist_add(base, s) +register Strlist **base; +register char *s; +{ + register Strlist *p; + + while ((p = *base) && strcmp(p->s, s) < 0) + base = &p->next; + if (!p || strcmp(p->s, s)) { + p = ALLOCV(sizeof(Strlist) + strlen(s), Strlist, strlists); + p->next = *base; + *base = p; + strcpy(p->s, s); + } + p->value = 0; + return p; +} + + + +/* Append two strlists together */ + +void strlist_mix(base, sl) +register Strlist **base; +Strlist *sl; +{ + if (sl) { + while (*base) + base = &(*base)->next; + *base = sl; + } +} + + + +/* Remove the first element of a strlist */ + +void strlist_eat(base) +register Strlist **base; +{ + register Strlist *p; + + if ((p = *base) != NULL) { + *base = p->next; + FREE(p); + } +} + + + +/* Remove all elements of a strlist */ + +void strlist_empty(base) +register Strlist **base; +{ + register Strlist *p; + + if (!base) { + intwarning("strlist_empty", "NULL base pointer [312]"); + return; + } + while ((p = *base) != NULL) { + *base = p->next; + FREE(p); + } +} + + + +/* Remove first occurrence of a given string */ + +void strlist_remove(base, s) +register Strlist **base; +register char *s; +{ + register Strlist *p; + + while ((p = *base) != NULL) { + if (!strcmp(p->s, s)) { + *base = p->next; + FREE(p); + } else + base = &p->next; + } +} + + + +/* Remove a given entry from a strlist */ + +void strlist_delete(base, sl) +register Strlist **base, *sl; +{ + register Strlist *p; + + while ((p = *base) && p != sl) + base = &p->next; + if (p) { + *base = p->next; + FREE(p); + } +} + + + +/* Find the first occurrence of a string */ + +Strlist *strlist_find(base, s) +register Strlist *base; +register char *s; +{ + if (!s) + return NULL; + while (base && strcmp(base->s, s)) + base = base->next; + return base; +} + + + +/* Case-insensitive version of strlist_find */ + +Strlist *strlist_cifind(base, s) +register Strlist *base; +register char *s; +{ + if (!s) + return NULL; + while (base && strcicmp(base->s, s)) + base = base->next; + return base; +} + + + + + + +/* String comparisons */ + + +int strcincmp(s1, s2, n) +register char *s1, *s2; +register int n; +{ + register unsigned char ch1, ch2; + + while (--n >= 0) { + if (!(ch1 = *s1++)) + return (*s2) ? -1 : 0; + if (!(ch2 = *s2++)) + return 1; + if (islower(ch1)) + ch1 = _toupper(ch1); + if (islower(ch2)) + ch2 = _toupper(ch2); + if (ch1 != ch2) + return ch1 - ch2; + } + return 0; +} + + + +int strcicmp(s1, s2) +register char *s1, *s2; +{ + register unsigned char ch1, ch2; + + for (;;) { + if (!(ch1 = *s1++)) + return (*s2) ? -1 : 0; + if (!(ch2 = *s2++)) + return 1; + if (islower(ch1)) + ch1 = _toupper(ch1); + if (islower(ch2)) + ch2 = _toupper(ch2); + if (ch1 != ch2) + return ch1 - ch2; + } +} + + + + + + +/* File name munching */ + + +void fixfname(fn, ext) +char *fn, *ext; +{ + char *cp, *cp2; + + if (!ext) + return; + cp = my_strrchr(fn, '.'); + cp2 = my_strrchr(fn, '/'); + if (cp && (!cp2 || cp > cp2)) { + if (!cp[1]) /* remove trailing '.' */ + *cp = 0; + } else { + strcat(fn, "."); + strcat(fn, ext); + } +} + + + +void removesuffix(fn) +char *fn; +{ + char *cp, *cp2; + + cp = my_strrchr(fn, '.'); + if (!cp) + return; +#if defined(unix) || defined(__unix) + cp2 = my_strrchr(fn, '/'); + if (cp2 && cp < cp2) + return; +#endif + *cp = 0; +} + + + + + + +/* Dynamically-allocated strings */ + + +char *stralloc(s) +char *s; +{ + register char *buf = ALLOC(strlen(s) + 1, char, strings); + strcpy(buf, s); + return buf; +} + + + +void strchange(v, s) +char **v, *s; +{ + s = stralloc(s); /* do this first in case **v and *s overlap */ + FREE(*v); + *v = s; +} + + + + + +/* Handy string formatting */ + +#define NUMBUF 8 +static char *(formatbuf[NUMBUF]); +static int nextformat = -1; + +#define getformat() ((nextformat=(nextformat+1)%NUMBUF), formatbuf[nextformat]) + + +#define FF_UCASE 0x1 +#define FF_LCASE 0x2 +#define FF_REMSUFF 0x4 +#define FF_UNDER 0x8 /* Thanks to William Bader for suggesting these */ +#define FF_PRESERVE 0x10 +#define FF_REMSLASH 0x20 +#define FF_REMUNDER 0x40 + +Static void cvcase(buf, flags) +char *buf; +int flags; +{ + char *cp, *cp2; + int ulflag, i; + + if (flags & FF_PRESERVE) { + ulflag = 0; + for (cp = buf; *cp; cp++) { + if (isupper(*cp)) + ulflag |= 1; + else if (islower(*cp)) + ulflag |= 2; + } + if (ulflag == 3) + flags &= ~(FF_UCASE | FF_LCASE); + } + if ((flags & FF_UNDER) && *buf) { + for (cp = buf + 1; *cp; cp++) { + if (isupper(*cp) && islower(cp[-1])) { + for (i = strlen(cp); i >= 0; i--) + cp[i+1] = cp[i]; + *cp++ = '_'; + } + } + } + if (flags & FF_UCASE) { + if (flags & FF_LCASE) { + for (cp = buf; *cp; cp++) { + if (cp == buf || !isalpha(cp[-1])) + *cp = toupper(*cp); + else + *cp = tolower(*cp); + } + } else + upc(buf); + } else if (flags & FF_LCASE) + lwc(buf); + if (flags & FF_REMUNDER) { + for (cp = cp2 = buf; *cp; cp++) { + if (isalnum(*cp)) + *cp2++ = *cp; + } + if (cp2 > buf) + *cp2 = 0; + } +} + + +char *format_gen(fmt, i1, i2, dbl, s1, s2, s3) +char *fmt; +long i1, i2; +double dbl; +char *s1, *s2, *s3; +{ + char *buf = getformat(); + char *dst = buf, *src = fmt, *cp, *cp2, *saves2 = s2; + int wid, prec; + int flags; + char fmtbuf[50], *fp; + + debughook(); + while (*src) { + if (*src != '%') { + *dst++ = *src++; + continue; + } + src++; + wid = -1; + prec = -1; + flags = 0; + fp = fmtbuf; + *fp++ = '%'; + for (;;) { + if (*src == '-' || *src == '+' || *src == ' ' || *src == '#') { + *fp++ = *src; + } else if (*src == '^') { + flags |= FF_UCASE; + } else if (*src == '_') { + flags |= FF_LCASE; + } else if (*src == 'R') { + flags |= FF_REMSUFF; + } else if (*src == '~') { + flags |= FF_UNDER; + } else if (*src == '!') { + flags |= FF_REMUNDER; + } else if (*src == '?') { + flags |= FF_PRESERVE; + } else if (*src == '/') { + flags |= FF_REMSLASH; + } else + break; + src++; + } + if (isdigit(*src)) { + wid = 0; + while (isdigit(*src)) + wid = wid*10 + (*fp++ = *src++) - '0'; + } else if (*src == '*') { + src++; + wid = i1; + sprintf(fp, "%d", wid); + fp = fp + strlen(fp); + if (wid < 0) + wid = -wid; + i1 = i2; + } + if (*src == '.') { + if (*++src == '*') { + prec = i1; + i1 = i2; + src++; + } else { + prec = 0; + while (isdigit(*src)) + prec = prec*10 + (*src++) - '0'; + } + sprintf(fp, ".%d", prec); + fp = fp + strlen(fp); + } + if (*src == 'l' || *src == 'h') + src++; + switch (*src) { + + case '%': + *dst++ = '%'; + break; + + case 'H': + strcpy(dst, p2c_home); + dst = dst + strlen(dst); + break; + + case 'd': + case 'i': + case 'o': + case 'u': + case 'x': + case 'X': + *fp++ = 'l'; + *fp++ = *src; + *fp = 0; + sprintf(dst, fmtbuf, i1); + i1 = i2; + cvcase(dst, flags); + dst = dst + strlen(dst); + break; + + case 'c': + *fp++ = *src; + *fp = 0; + sprintf(dst, fmtbuf, (int)i1); + i1 = i2; + cvcase(dst, flags); + dst = dst + strlen(dst); + break; + + case 'e': + case 'E': + case 'f': + case 'g': + case 'G': + *fp++ = *src; + *fp++ = 0; + sprintf(dst, fmtbuf, dbl); + cvcase(dst, flags); + dst = dst + strlen(dst); + break; + + case 's': + case 'S': + *fp++ = 's'; + *fp = 0; + if (*src == 'S' && saves2) { + cp = saves2; + } else { + cp = s1; + s1 = s2; + s2 = s3; + } + if (flags & FF_REMSUFF) { + cp = format_s("%s", cp); + removesuffix(cp); + } + if (flags & FF_REMSLASH) { + cp2 = cp + strlen(cp); + while (cp2 >= cp && + *cp2 != '/' && *cp2 != '\\' && + *cp2 != ']' && *cp2 != ':') + cp2--; + if (cp2[1]) + cp = cp2 + 1; + } + sprintf(dst, fmtbuf, cp); + cvcase(dst, flags); + dst = dst + strlen(dst); + break; + + } + src++; + } + *dst = 0; + return buf; +} + + + + +char *format_none(fmt) +char *fmt; +{ + return format_gen(fmt, 0L, 0L, 0.0, NULL, NULL, NULL); +} + + +char *format_d(fmt, a1) +char *fmt; +int a1; +{ + return format_gen(fmt, a1, 0L, (double)a1, NULL, NULL, NULL); +} + + +char *format_g(fmt, a1) +char *fmt; +double a1; +{ + return format_gen(fmt, (long)a1, 0L, a1, NULL, NULL, NULL); +} + + +char *format_s(fmt, a1) +char *fmt, *a1; +{ + return format_gen(fmt, 0L, 0L, 0.0, a1, NULL, NULL); +} + + +char *format_ss(fmt, a1, a2) +char *fmt, *a1, *a2; +{ + return format_gen(fmt, 0L, 0L, 0.0, a1, a2, NULL); +} + + +char *format_sd(fmt, a1, a2) +char *fmt, *a1; +int a2; +{ + return format_gen(fmt, a2, 0L, (double)a2, a1, NULL, NULL); +} + + +char *format_ds(fmt, a1, a2) +char *fmt, *a2; +long a1; +{ + return format_gen(fmt, a1, 0L, (double)a1, a2, NULL, NULL); +} + + +char *format_dd(fmt, a1, a2) +char *fmt; +long a1, a2; +{ + return format_gen(fmt, a1, a2, (double)a1, NULL, NULL, NULL); +} + + +char *format_sss(fmt, a1, a2, a3) +char *fmt, *a1, *a2, *a3; +{ + return format_gen(fmt, 0L, 0L, 0.0, a1, a2, a3); +} + + +char *format_ssd(fmt, a1, a2, a3) +char *fmt, *a1, *a2; +long a3; +{ + return format_gen(fmt, a3, 0L, (double)a3, a1, a2, NULL); +} + + +char *format_sds(fmt, a1, a2, a3) +char *fmt, *a1, *a3; +long a2; +{ + return format_gen(fmt, a2, 0L, (double)a2, a1, a3, NULL); +} + + + + +/* String conversions */ + +int my_toupper(c) +int c; +{ + if (islower(c)) + return _toupper(c); + else + return c; +} + + +int my_tolower(c) +int c; +{ + if (isupper(c)) + return _tolower(c); + else + return c; +} + + +void upc(s) +register char *s; +{ + for (; *s; s++) + *s = toupper(*s); +} + + +void lwc(s) +register char *s; +{ + for (; *s; s++) + *s = tolower(*s); +} + + +char *strupper(s) +register char *s; +{ + char *dest = getformat(); + register char *s2 = dest; + while (*s) + *s2++ = toupper(*s++); + *s2 = 0; + return dest; +} + + +char *strlower(s) +register char *s; +{ + char *dest = getformat(); + register char *s2 = dest; + while (*s) + *s2++ = tolower(*s++); + *s2 = 0; + return dest; +} + + + +char *my_strchr(cp, c) +register char *cp; +int c; +{ + while (*cp && *cp != c) + cp++; + if (*cp) + return cp; + else + return NULL; +} + + +char *my_strrchr(cp, c) +register char *cp; +int c; +{ + register char *cp2 = NULL; + while (*cp) { + if (*cp == c) + cp2 = cp; + cp++; + } + return cp2; +} + + +char *my_strtok(cp, delim) +char *cp, *delim; +{ + static char *ptr; + + if (cp) + ptr = cp; + while (*ptr && my_strchr(delim, *ptr)) + ptr++; + if (!*ptr) + return NULL; + cp = ptr; + while (*ptr && !my_strchr(delim, *ptr)) + ptr++; + *ptr++ = 0; + return cp; +} + + + +long my_strtol(buf, ret, base) +char *buf, **ret; +int base; +{ + unsigned long val = 0; + int dig, sign = 1; + + while (isspace(*buf)) + buf++; + if (*buf == '+') + buf++; + else if (*buf == '-') { + sign = -1; + buf++; + } + if (*buf == '0') { + if ((buf[1] == 'x' || buf[1] == 'X') && + (base == 0 || base == 16)) { + buf++; + base = 16; + } else if (base == 0) + base = 8; + buf++; + } + for (;;) { + if (isdigit(*buf)) + dig = *buf - '0'; + else if (*buf >= 'a') + dig = *buf - 'a' + 10; + else if (*buf >= 'A') + dig = *buf - 'A' + 10; + else + break; + if (dig >= base) + break; + val = val * base + dig; + buf++; + } + if (ret) + *ret = buf; + if (sign > 0) + return val; + else + return -val; +} + + + + +void init_stuff() +{ + int i; + + for (i = 0; i < NUMBUF; i++) + formatbuf[i] = ALLOC(1000, char, misc); +} + + + + +/* End. */ + + diff --git a/MultiSource/Benchmarks/MallocBench/p2c/trans.c b/MultiSource/Benchmarks/MallocBench/p2c/trans.c new file mode 100644 index 00000000..430e7ae5 --- /dev/null +++ b/MultiSource/Benchmarks/MallocBench/p2c/trans.c @@ -0,0 +1,1512 @@ +/* "p2c", a Pascal to C translator. + Copyright (C) 1989, 1990, 1991 Free Software Foundation. + Author's address: daveg@csvax.caltech.edu; 256-80 Caltech/Pasadena CA 91125. + +This program is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation (any version). + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; see the file COPYING. If not, write to +the Free Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ + + + + +#define define_globals +#define PROTO_TRANS_C +#include "trans.h" + +#include <time.h> + + + + + + +/* Roadmap: + + trans.h Declarations for all public global variables, types, + and macros. Functions are declared in separate + files p2c.{proto,hdrs} which are created + mechanically by the makeproto program. + + trans.c Main program. Parses the p2crc file. Also reserves + storage for public globals in trans.h. + + stuff.c Miscellaneous support routines. + + out.c Routines to handle the writing of C code to the output + file. This includes line breaking and indentation + support. + + comment.c Routines for managing comments and comment lists. + + lex.c Lexical analyzer. Manages input files and streams, + splits input stream into Pascal tokens. Parses + compiler directives and special comments. Also keeps + the symbol table. + + parse.c Parsing and writing statements and blocks. + + decl.c Parsing and writing declarations. + + expr.c Manipulating expressions. + + pexpr.c Parsing and writing expressions. + + funcs.c Built-in special functions and procedures. + + dir.c Interface file to "external" functions and procedures + such as hpmods and citmods. + + hpmods.c Definitions for HP-supplied Pascal modules. + + citmods.c Definitions for some Caltech-local Pascal modules. + (Outside of Caltech this file is mostly useful + as a large body of examples of how to write your + own translator extensions.) + + + p2crc Control file (read when p2c starts up). + + p2c.h Header file used by translated programs. + + p2clib.c Run-time library used by translated programs. + +*/ + + + + +Static Strlist *tweaksymbols, *synonyms; +Strlist *addmacros; + + + +Static void initrc() +{ + int i; + + for (i = 0; i < numparams; i++) { + switch (rctable[i].kind) { + case 'S': + case 'B': + *((short *)rctable[i].ptr) = rctable[i].def; + break; + case 'I': + case 'D': + *((int *)rctable[i].ptr) = rctable[i].def; + break; + case 'L': + *((long *)rctable[i].ptr) = rctable[i].def; + break; + case 'R': + *((double *)rctable[i].ptr) = rctable[i].def/100.0; + break; + case 'U': + case 'C': + *((char *)rctable[i].ptr) = 0; + break; + case 'A': + *((Strlist **)rctable[i].ptr) = NULL; + break; + case 'X': + if (rctable[i].def == 1) + *((Strlist **)rctable[i].ptr) = NULL; + break; + } + rcprevvalues[i] = NULL; + } + tweaksymbols = NULL; + synonyms = NULL; + addmacros = NULL; + varmacros = NULL; + constmacros = NULL; + fieldmacros = NULL; + funcmacros = NULL; +} + + + +Static int readrc(rcname, need) +char *rcname; +int need; +{ + FILE *rc; + char buf[500], *cp, *cp2; + long val = 0; + int i; + Strlist *sl; + + rc = fopen(rcname, "r"); + if (!rc) { + if (need) + perror(rcname); + return 0; + } + while (fgets(buf, 500, rc)) { + cp = my_strtok(buf, " =\t\n"); + if (cp && *cp != '#') { + upc(cp); + i = numparams; + while (--i >= 0 && strcmp(rctable[i].name, cp)) ; + if (i >= 0) { + if (rctable[i].kind != 'M') { + cp = my_strtok(NULL, " =\t\n"); + if (cp && *cp == '#') + cp = NULL; + if (cp && (isdigit(*cp) || *cp == '-' || *cp == '+')) + val = atol(cp); + else + val = rctable[i].def; + } + switch (rctable[i].kind) { + + case 'S': + *((short *)rctable[i].ptr) = val; + break; + + case 'I': + *((int *)rctable[i].ptr) = val; + break; + + case 'D': + *((int *)rctable[i].ptr) = + parsedelta(cp, rctable[i].def); + break; + + case 'L': + *((long *)rctable[i].ptr) = val; + break; + + case 'R': + if (cp && (isdigit(*cp) || *cp == '-' || *cp == '.')) + *((double *)rctable[i].ptr) = atof(cp); + else + *((double *)rctable[i].ptr) = rctable[i].def/100.0; + break; + + case 'U': + if (cp) + upc(cp); + + /* fall through */ + case 'C': + val = rctable[i].def; + strncpy((char *)rctable[i].ptr, cp ? cp : "", val-1); + ((char *)rctable[i].ptr)[val-1] = 0; + break; + + case 'F': + while (cp && *cp != '#') { + sl = strlist_append(&tweaksymbols, + format_s("*%s", cp)); + sl->value = rctable[i].def; + cp = my_strtok(NULL, " \t\n"); + } + break; + + case 'G': + while (cp && *cp != '#') { + sl = strlist_append(&tweaksymbols, cp); + sl->value = rctable[i].def; + cp = my_strtok(NULL, " \t\n"); + } + break; + + case 'A': + while (cp && *cp != '#') { + strlist_insert((Strlist **)rctable[i].ptr, cp); + cp = my_strtok(NULL, " \t\n"); + } + break; + + case 'M': + cp = my_strtok(NULL, "\n"); + if (cp) { + while (isspace(*cp)) cp++; + for (cp2 = cp; *cp2 && *cp2 != '#'; cp2++) ; + *cp2 = 0; + if (*cp) { + sl = strlist_append(&addmacros, cp); + sl->value = rctable[i].def; + } + } + break; + + case 'B': + if (cp) + val = parse_breakstr(cp); + if (val != -1) + *((short *)rctable[i].ptr) = val; + break; + + case 'X': + switch (rctable[i].def) { + + case 1: /* strlist with string values */ + if (cp) { + sl = strlist_append((Strlist **)rctable[i].ptr, cp); + cp = my_strtok(NULL, " =\t\n"); + if (cp && *cp != '#') + sl->value = (long)stralloc(cp); + } + break; + + case 2: /* Include */ + if (cp) + readrc(format_s(cp, infname), 1); + break; + + case 3: /* Synonym */ + if (cp) { + sl = strlist_append(&synonyms, cp); + cp = my_strtok(NULL, " =\t\n"); + if (cp && *cp != '#') + sl->value = (long)stralloc(cp); + } + break; + + } + } + } else + fprintf(stderr, "warning: can't understand %s in %s\n", cp, rcname); + } + } + fclose(rc); + return 1; +} + + +Static void postrc() +{ + int longbits; + unsigned long val; + + which_unix = UNIX_ANY; + if (!strcmp(target, "CHIPMUNK") || + !strcmp(target, "HPUX-300") || + !strcmp(target, "SUN-68K") || + !strcmp(target, "BSD-VAX")) { + signedchars = 1; + sizeof_char = 8; + sizeof_short = 16; + sizeof_int = sizeof_long = sizeof_pointer = 32; + sizeof_enum = 32; + sizeof_float = 32; + sizeof_double = 64; + if (!strcmp(target, "CHIPMUNK") || + !strcmp(target, "HPUX-300")) + which_unix = UNIX_SYSV; + else + which_unix = UNIX_BSD; + } else if (!strcmp(target, "LSC-MAC")) { + signedchars = 1; + if (prototypes < 0) + prototypes = 1; + if (fullprototyping < 0) + fullprototyping = 0; + if (voidstar < 0) + voidstar = 1; + sizeof_char = 8; + sizeof_short = sizeof_int = 16; + sizeof_long = sizeof_pointer = 32; + } else if (!strcmp(target, "BSD")) { + which_unix = UNIX_BSD; + } else if (!strcmp(target, "SYSV")) { + which_unix = UNIX_SYSV; + } else if (*target) { + fprintf(stderr, "p2c: warning: don't understand target name %s\n", target); + } + if (ansiC > 0) { + if (sprintf_value < 0) + sprintf_value = 0; + if (castnull < 0) + castnull = 0; + } + if (useenum < 0) + useenum = (ansiC != 0) ? 1 : 0; + if (void_args < 0) + void_args = (ansiC > 0 && prototypes != 0) ? 1 : 0; + if (prototypes < 0) + prototypes = (cplus > 0) ? 2 : (ansiC > 0) ? 1 : 0; + if (prototypes == 0) + fullprototyping = 0; + else if (fullprototyping < 0) + fullprototyping = 1; + if (useAnyptrMacros < 0) + useAnyptrMacros = (ansiC > 0 || cplus > 0) ? 2 : 1; + if (usePPMacros < 0) + usePPMacros = (ansiC > 0 || cplus > 0) ? 0 : 2; + if (voidstar < 0) + voidstar = (ansiC > 0 || cplus > 0) ? 1 : 0; + if (hassignedchar < 0) + hassignedchar = (ansiC > 0) ? 1 : 0; + if (useconsts < 0) + useconsts = (ansiC > 0 || cplus > 0) ? 1 : 0; + if (copystructs < 0) + copystructs = (ansiC != 0 || cplus > 0) ? 3 : 0; + if (copystructfuncs < 0) + copystructfuncs = (ansiC > 0 || cplus > 0) ? 0 : 1; + if (starfunctions < 0) + starfunctions = (ansiC > 0) ? 0 : 1; + if (variablearrays < 0) + variablearrays = (ansiC > 1) ? 1 : 0; + if (initpacstrings < 0) + initpacstrings = (ansiC > 0) ? 1 : 0; + if (*memcpyname) { + if (ansiC > 0 || which_unix == UNIX_SYSV) + strcpy(memcpyname, "memcpy"); + else if (which_unix == UNIX_BSD) + strcpy(memcpyname, "bcopy"); + } + sizeof_integer = (sizeof_int >= 32) ? sizeof_int : sizeof_long; + integername = (sizeof_int >= 32) ? "int" : "long"; + if (sizeof_integer && sizeof_integer < 32) + fprintf(stderr, "Warning: long integers have less than 32 bits\n"); + if (sizeof_int >= 32 && sizeof_long > sizeof_int && prototypes == 0) + fprintf(stderr, "Warning: translated code assumes int and long are the same"); + if (setbits < 0) + setbits = (sizeof_integer > 0) ? sizeof_integer : 32; + ucharname = (*name_UCHAR) ? name_UCHAR : + (signedchars == 0) ? "char" : "unsigned char"; + scharname = (*name_SCHAR) ? name_SCHAR : + (signedchars == 1) ? "char" : + (useAnyptrMacros == 1) ? "Signed char" : "signed char"; + for (longbits = 1, val = LONG_MAX; val >>= 1; longbits++) ; + if (sizeof_char) { + if (sizeof_char < 8 && ansiC > 0) + fprintf(stderr, "Warning: chars have less than 8 bits\n"); + if (sizeof_char > longbits) { + min_schar = LONG_MIN; + max_schar = LONG_MAX; + } else { + min_schar = - (1<<(sizeof_char-1)); + max_schar = (1<<(sizeof_char-1)) - 1; + } + if (sizeof_char >= longbits) + max_uchar = LONG_MAX; + else + max_uchar = (1<<sizeof_char) - 1; + } else { + min_schar = -128; /* Ansi-required minimum maxima */ + max_schar = 127; + max_uchar = 255; + } + if (sizeof_short) { + if (sizeof_short < 16 && ansiC > 0) + fprintf(stderr, "Warning: shorts have less than 16 bits\n"); + if (sizeof_short > longbits) { + min_sshort = LONG_MIN; + max_sshort = LONG_MAX; + } else { + min_sshort = - (1<<(sizeof_short-1)); + max_sshort = (1<<(sizeof_short-1)) - 1; + } + if (sizeof_short >= longbits) + max_ushort = LONG_MAX; + else + max_ushort = (1<<sizeof_short) - 1; + } else { + min_sshort = -32768; /* Ansi-required minimum maxima */ + max_sshort = 32767; + max_ushort = 65535; + } + if (symcase < 0) + symcase = 1; + if (smallsetconst == -2) + smallsetconst = (*name_SETBITS) ? -1 : 1; + hpux_lang = 0; + if (!strcmp(language, "TURBO")) { + which_lang = LANG_TURBO; + } else if (!strcmp(language, "UCSD")) { + which_lang = LANG_UCSD; + } else if (!strcmp(language, "MPW")) { + which_lang = LANG_MPW; + } else if (!strcmp(language, "HPUX") || !strcmp(language, "HP-UX")) { + which_lang = LANG_HP; + hpux_lang = 1; + } else if (!strcmp(language, "OREGON")) { + which_lang = LANG_OREGON; + } else if (!strcmp(language, "VAX") || !strcmp(language, "VMS")) { + which_lang = LANG_VAX; + } else if (!strncmp(language, "MODULA", 6)) { + which_lang = LANG_MODULA; + } else if (!strncmp(language, "BERK", 4) || + !strcmp(language, "SUN")) { + which_lang = LANG_BERK; + } else { + if (*language && strcmp(language, "HP") && strcmp(language, "MODCAL")) + fprintf(stderr, "Warning: Language %s not recognized, using HP\n", language); + which_lang = LANG_HP; + } + if (modula2 < 0) + modula2 = (which_lang == LANG_MODULA) ? 1 : 0; + if (pascalcasesens < 0) + pascalcasesens = (which_lang == LANG_MODULA) ? 2 : + (which_lang == LANG_BERK) ? 3 : 0; + if (implementationmodules < 0) + implementationmodules = (which_lang == LANG_VAX) ? 1 : 0; + if (integer16 < 0) + integer16 = (which_lang == LANG_TURBO || + which_lang == LANG_MPW) ? 1 : 0; + if (doublereals < 0) + doublereals = (hpux_lang || + which_lang == LANG_OREGON || + which_lang == LANG_VAX) ? 0 : 1; + if (pascalenumsize < 0) + pascalenumsize = (which_lang == LANG_HP) ? 16 : 8; + if (storefilenames < 0) + storefilenames = (which_lang == LANG_TURBO) ? 1 : 0; + if (charfiletext < 0) + charfiletext = (which_lang == LANG_BERK) ? 1 : 0; + if (readwriteopen < 0) + readwriteopen = (which_lang == LANG_TURBO) ? 1 : 0; + if (literalfilesflag < 0) + literalfilesflag = (which_lang == LANG_BERK) ? 2 : 0; + if (newlinespace < 0) + newlinespace = (which_lang == LANG_TURBO) ? 0 : 1; + if (nestedcomments < 0) + nestedcomments = (which_lang == LANG_TURBO || + which_lang == LANG_MPW || + which_lang == LANG_UCSD || + which_lang == LANG_BERK) ? 2 : 0; + if (importall < 0) + importall = (which_lang == LANG_HP) ? 1 : 0; + if (seek_base < 0) + seek_base = (which_lang == LANG_TURBO || + which_lang == LANG_MPW || + which_lang == LANG_UCSD) ? 0 : 1; + if (unsignedchar < 0 && signedchars == 0) + unsignedchar = 2; + if (hasstaticlinks < 0) + hasstaticlinks = (which_lang == LANG_HP) ? 1 : 0; + if (dollar_idents < 0) + dollar_idents = (which_lang == LANG_OREGON || + which_lang == LANG_VAX) ? 1 : 0; + if (ignorenonalpha < 0) + ignorenonalpha = (which_lang == LANG_UCSD) ? 1 : 0; + if (stringtrunclimit < 0) + stringtrunclimit = (which_lang == LANG_TURBO) ? 80 : 0; + if (defaultsetsize < 0) + defaultsetsize = (which_lang == LANG_VAX) ? 256 : + (which_lang == LANG_BERK) ? 128 : + (which_lang == LANG_MPW) ? 2040 : 8192; + if (enumbyte < 0) + enumbyte = (which_lang == LANG_HP) ? 0 : 1; + if (!*filenamefilter && (which_lang == LANG_OREGON || + which_lang == LANG_BERK)) + strcpy(filenamefilter, "P_trimname"); + charname = (useAnyptrMacros) ? "Char" : + (unsignedchar == 1) ? ucharname : + (unsignedchar == 0) ? scharname : "char"; + if (!*memcpyname) + strcpy(memcpyname, "memcpy"); + if (!*mallocname) + strcpy(mallocname, "malloc"); + if (!*freename) + strcpy(freename, "free"); + fix_parameters(); +} + + + + +void saveoldfile(fname) +char *fname; +{ +#if defined(unix) || defined(__unix) || defined(CAN_LINK) + (void) unlink(format_s("%s~", fname)); + if (link(fname, format_s("%s~", fname)) == 0) + (void) unlink(fname); +#endif +} + + + +#ifndef __STDC__ +# ifdef NO_GETENV +# define getenv(x) NULL +# else +extern char *getenv PP((char *)); +# endif +#endif + +Static long starting_time; + +Static void openlogfile() +{ + char *name, *uname; + + if (*codefname == '<') + name = format_ss(logfnfmt, infname, infname); + else + name = format_ss(logfnfmt, infname, codefname); + if (!name) + name = format_s("%s.log", codefname); + saveoldfile(name); + logf = fopen(name, "w"); + if (logf) { + fprintf(logf, "\nTranslation of %s to %s by p2c %s\n", + infname, codefname, P2C_VERSION); + fprintf(logf, "Translated"); + uname = getenv("USER"); + if (uname) + fprintf(logf, " by %s", uname); + time(&starting_time); + fprintf(logf, " on %s", ctime(&starting_time)); + fprintf(logf, "\n\n"); + } else { + perror(name); + verbose = 0; + } +} + + +void closelogfile() +{ + long ending_time; + + if (logf) { + fprintf(logf, "\n\n"); +#if defined(unix) || defined(__unix) + fprintf(logf, "Total memory used: %ld bytes.\n", (long)sbrk(0)); +#endif + time(&ending_time); + fprintf(logf, "Processed %d source lines in %ld:%ld seconds.\n", + inf_ltotal, + (ending_time - starting_time) / 60, + (ending_time - starting_time) % 60); + fprintf(logf, "\n\nTranslation completed on %s", ctime(&ending_time)); + fclose(logf); + } +} + + + + +void showinitfile() +{ + FILE *f; + int ch; + char *name; + + name = format_s("%H/%s", "p2crc"); + printf("# Copy of file %%H/p2crc => %s:\n\n", name); + f = fopen(name, "r"); + if (!f) { + perror(name); + exit(1); + } + while ((ch = getc(f)) != EOF) + putchar(ch); + fclose(f); + exit(0); +} + + + + +void usage() +{ + fprintf(stderr, "usage: p2c [options] file [modulename] [-h file.h] [-o file.c]\n"); + exit(EXIT_FAILURE); +} + + + +int main(argc, argv) +int argc; +char **argv; +{ + int numsearch; + char *searchlist[50]; + char infnbuf[200], codefnbuf[200], hdrfnbuf[200], *cp; + Symbol *sp; + Strlist *sl; + int i, nobuffer = 0, savequiet; + + i = 0; + while (i < argc && strcmp(argv[i], "-H")) i++; + if (i < argc-1) + p2c_home = argv[i+1]; + else { + cp = getenv("P2C_HOME"); + if (cp) + p2c_home = cp; + } + init_stuff(); + i = 0; + while (i < argc && strcmp(argv[i], "-i")) i++; + if (i < argc) + showinitfile(); + initrc(); + setup_dir(); + infname = infnbuf; + *infname = 0; + i = 0; + while (i < argc && argv[i][0] == '-') i++; + if (i >= argc) + strcpy(infname, argv[i]); + i = 0; + while (i < argc && strcmp(argv[i], "-v")) i++; + if (i >= argc) { + cp = getenv("P2CRC"); + if (cp) + readrc(cp, 1); + else + readrc(format_s("%H/%s", "p2crc"), 1); + } + i = 0; + while (i < argc && strcmp(argv[i], "-c")) i++; + if (i < argc-1) { + if (strcmp(argv[i+1], "-")) + readrc(argv[i+1], 1); + } else + if (!readrc("p2crc", 0)) + readrc(".p2crc", 0); + codefname = codefnbuf; + *codefname = 0; + hdrfname = hdrfnbuf; + *hdrfname = 0; + requested_module = NULL; + found_module = 0; + error_crash = 0; +#ifdef CONSERVE_MEMORY + conserve_mem = CONSERVE_MEMORY; +#else + conserve_mem = 1; +#endif + regression = 0; + verbose = 0; + partialdump = 1; + numsearch = 0; + argc--, argv++; + while (argc > 0) { + if (**argv == '-' && (*argv)[1]) { + if (!strcmp(*argv, "-a")) { + ansiC = 1; + } else if (argv[0][1] == 'L') { + if (strlen(*argv) == 2 && argc > 1) { + strcpy(language, ++*argv); + --argc; + } else + strcpy(language, *argv + 2); + upc(language); + } else if (!strcmp(*argv, "-q")) { + quietmode = 1; + } else if (!strcmp(*argv, "-o")) { + if (*codefname || --argc <= 0) + usage(); + strcpy(codefname, *++argv); + } else if (!strcmp(*argv, "-h")) { + if (*hdrfname || --argc <= 0) + usage(); + strcpy(hdrfname, *++argv); + } else if (!strcmp(*argv, "-s")) { + if (--argc <= 0) + usage(); + cp = *++argv; + if (!strcmp(cp, "-")) + librfiles = NULL; + else + searchlist[numsearch++] = cp; + } else if (!strcmp(*argv, "-c")) { + if (--argc <= 0) + usage(); + argv++; + /* already done above */ + } else if (!strcmp(*argv, "-v")) { + /* already done above */ + } else if (!strcmp(*argv, "-H")) { + /* already done above */ + } else if (argv[0][1] == 'I') { + if (strlen(*argv) == 2 && argc > 1) { + strlist_append(&importdirs, ++*argv); + --argc; + } else + strlist_append(&importdirs, *argv + 2); + } else if (argv[0][1] == 'p') { + if (strlen(*argv) == 2) + showprogress = 25; + else + showprogress = atoi(*argv + 2); + nobuffer = 1; + } else if (!strcmp(*argv, "-e")) { + copysource++; + } else if (!strcmp(*argv, "-t")) { + tokentrace++; + } else if (!strcmp(*argv, "-x")) { + error_crash++; + } else if (argv[0][1] == 'E') { + if (strlen(*argv) == 2) + maxerrors = 0; + else + maxerrors = atoi(*argv + 2); + } else if (!strcmp(*argv, "-F")) { + partialdump = 0; + } else if (argv[0][1] == 'd') { + nobuffer = 1; + if (strlen(*argv) == 2) + debug = 1; + else + debug = atoi(*argv + 2); + } else if (argv[0][1] == 'B') { + if (strlen(*argv) == 2) + i = 1; + else + i = atoi(*argv + 2); + if (argc == 2 && + strlen(argv[1]) > 2 && + !strcmp(argv[1] + strlen(argv[1]) - 2, ".c")) { + testlinebreaker(i, argv[1]); + exit(EXIT_SUCCESS); + } else + testlinebreaker(i, NULL); + } else if (argv[0][1] == 'C') { + if (strlen(*argv) == 2) + cmtdebug = 1; + else + cmtdebug = atoi(*argv + 2); + } else if (!strcmp(*argv, "-R")) { + regression = 1; + } else if (argv[0][1] == 'V') { + if (strlen(*argv) == 2) + verbose = 1; + else + verbose = atoi(*argv + 2); + } else if (argv[0][1] == 'M') { + if (strlen(*argv) == 2) + conserve_mem = 1; + else + conserve_mem = atoi(*argv + 2); + } else + usage(); + } else if (!*infname) { + strcpy(infname, *argv); + } else if (!requested_module) { + requested_module = stralloc(*argv); + } else + usage(); + argc--, argv++; + } + if (requested_module && !*codefname) + strcpy(codefname, format_ss(modulefnfmt, infname, requested_module)); + if (*infname && strcmp(infname, "-")) { + if (strlen(infname) > 2 && + !strcmp(infname + strlen(infname) - 2, ".c")) { + fprintf(stderr, "What is wrong with this picture?\n"); + exit(EXIT_FAILURE); + } + inf = fopen(infname, "r"); + if (!inf) { + perror(infname); + exit(EXIT_FAILURE); + } + if (!*codefname) + strcpy(codefname, format_s(codefnfmt, infname)); + } else { + strcpy(infname, "<stdin>"); + inf = stdin; + if (!*codefname) + strcpy(codefname, "-"); + } + if (strcmp(codefname, "-")) { + saveoldfile(codefname); + codef = fopen(codefname, "w"); + if (!codef) { + perror(codefname); + exit(EXIT_FAILURE); + } + fprintf(codef, "/* Output from p2c, the Pascal-to-C translator */\n"); + } else { + strcpy(codefname, "<stdout>"); + codef = stdout; + } + if (nobuffer) + setbuf(codef, NULL); /* for debugging */ + outf = codef; + outf_lnum = 1; + logf = NULL; + if (verbose) + openlogfile(); + setup_complete = 0; + init_lex(); + leadingcomments(); + postrc(); + setup_comment(); /* must call this first */ + setup_lex(); /* must call this second */ + setup_out(); + setup_decl(); /* must call *after* setup_lex() */ + setup_parse(); + setup_funcs(); + for (sl = tweaksymbols; sl; sl = sl->next) { + cp = sl->s; + if (*cp == '*') { + cp++; + if (!pascalcasesens) + upc(cp); + } + sp = findsymbol(cp); + if (sl->value & FUNCBREAK) + sp->flags &= ~FUNCBREAK; + sp->flags |= sl->value; + } + strlist_empty(&tweaksymbols); + for (sl = synonyms; sl; sl = sl->next) { + if (!pascalcasesens) + upc(sl->s); + sp = findsymbol(sl->s); + sp->flags |= SSYNONYM; + if (sl->value) { + if (!pascalcasesens) + upc((char *)sl->value); + strlist_append(&sp->symbolnames, "===")->value = + (long)findsymbol((char *)sl->value); + } else + strlist_append(&sp->symbolnames, "===")->value = 0; + } + strlist_empty(&synonyms); + for (sl = addmacros; sl; sl = sl->next) { + defmacro(sl->s, sl->value, "<macro>", 0); + } + strlist_empty(&addmacros); + handle_nameof(); + setup_complete = 1; + savequiet = quietmode; + quietmode = 1; + for (sl = librfiles; sl; sl = sl->next) + (void)p_search(format_none(sl->s), "pas", 0); + for (i = 0; i < numsearch; i++) + (void)p_search(format_none(searchlist[i]), "pas", 1); + quietmode = savequiet; + p_program(); + end_source(); + flushcomments(NULL, -1, -1); + showendnotes(); + check_unused_macros(); + printf("\n"); + if (!showprogress) + fprintf(stderr, "\n"); + output("\n"); + if (requested_module && !found_module) + error(format_s("Module \"%s\" not found in file", requested_module)); + if (codef != stdout) + output("\n\n/* End. */\n"); + if (inf != stdin) + fclose(inf); + if (codef != stdout) + fclose(codef); + closelogfile(); + mem_summary(); + if (!quietmode) + fprintf(stderr, "Translation completed.\n"); + exit(EXIT_SUCCESS); +} + + + + +int outmem() +{ + fprintf(stderr, "p2c: Out of memory!\n"); + exit(EXIT_FAILURE); +} + + + +#if !defined(NO_ISBOGUS) && (defined(mc68000) || defined(m68k) || defined(vax)) +int ISBOGUS(p) +char *p; +{ + unsigned long ip = (unsigned long)p; + + if (ip < 0) { + if (ip < (unsigned long)&ip) + return 1; /* below the start of the stack */ + } else if (ip >= 512) { + if (ip > (unsigned long)sbrk(0)) + return 1; /* past the end of memory */ + } else + return 1; + return 0; +} +#else +#define ISBOGUS(p) 0 +#endif + + + + + + +char *meaningkindname(kind) +enum meaningkind kind; +{ +#ifdef HASDUMPS + if ((unsigned int)kind < (unsigned int)MK_LAST) + return meaningkindnames[(int) kind]; + else +#endif /*HASDUMPS*/ + return format_d("<meaning %d>", (int) kind); +} + +char *typekindname(kind) +enum typekind kind; +{ +#ifdef HASDUMPS + if ((unsigned int)kind < (unsigned int)TK_LAST) + return typekindnames[(int) kind]; + else +#endif /*HASDUMPS*/ + return format_d("<type %d>", (int) kind); +} + +char *exprkindname(kind) +enum exprkind kind; +{ +#ifdef HASDUMPS + if ((unsigned int)kind < (unsigned int)EK_LAST) + return exprkindnames[(int) kind]; + else +#endif /*HASDUMPS*/ + return format_d("<expr %d>", (int) kind); +} + +char *stmtkindname(kind) +enum stmtkind kind; +{ +#ifdef HASDUMPS + if ((unsigned int)kind < (unsigned int)SK_LAST) + return stmtkindnames[(int) kind]; + else +#endif /*HASDUMPS*/ + return format_d("<stmt %d>", (int) kind); +} + + + +void dumptype(tp) +Type *tp; +{ + if (!tp) { + fprintf(outf, "<NULL>\n"); + return; + } + if (ISBOGUS(tp)) { + fprintf(outf, "0x%lX\n", tp); + return; + } + fprintf(outf, " Type %lx, kind=%s", tp, typekindname(tp->kind)); +#ifdef HASDUMPS + fprintf(outf, ", meaning=%lx, basetype=%lx, indextype=%lx\n", + tp->meaning, tp->basetype, tp->indextype); + tp->dumped = 1; + if (tp->basetype) + dumptype(tp->basetype); + if (tp->indextype) + dumptype(tp->indextype); +#else + fprintf(outf, "\n"); +#endif /*HASDUMPS*/ +} + + +void dumpmeaning(mp) +Meaning *mp; +{ + if (!mp) { + fprintf(outf, "<NULL>\n"); + return; + } + if (ISBOGUS(mp)) { + fprintf(outf, "0x%lX\n", mp); + return; + } + fprintf(outf, " Meaning %lx, name=%s, kind=%s", mp, ((mp->name) ? mp->name : "<null>"), + meaningkindname(mp->kind)); +#ifdef HASDUMPS + fprintf(outf, ", ctx=%lx, cbase=%lx, cnext=%lx, type=%lx\n", + mp->ctx, mp->cbase, mp->cnext, mp->type); + if (mp->type && !mp->type->dumped) + dumptype(mp->type); + mp->dumped = 1; +#else + fprintf(outf, "\n"); +#endif /*HASDUMPS*/ +} + + +void dumpsymtable(sym) +Symbol *sym; +{ + Meaning *mp; + + if (sym) { + dumpsymtable(sym->left); +#ifdef HASDUMPS + if ((sym->mbase && !sym->mbase->dumped) || + (sym->fbase && !sym->fbase->dumped)) +#endif + { + fprintf(outf, "Symbol %s:\n", sym->name); + for (mp = sym->mbase; mp; mp = mp->snext) + dumpmeaning(mp); + for (mp = sym->fbase; mp; mp = mp->snext) + dumpmeaning(mp); + fprintf(outf, "\n"); + } + dumpsymtable(sym->right); + } +} + + +void dumptypename(tp, waddr) +Type *tp; +int waddr; +{ +#ifdef HASDUMPS + if (!tp) { + fprintf(outf, "<NULL>"); + return; + } + if (ISBOGUS(tp)) { + fprintf(outf, "0x%lX", tp); + return; + } + if (tp == tp_int) fprintf(outf, "I"); + else if (tp == tp_sint) fprintf(outf, "SI"); + else if (tp == tp_uint) fprintf(outf, "UI"); + else if (tp == tp_integer) fprintf(outf, "L"); + else if (tp == tp_unsigned) fprintf(outf, "UL"); + else if (tp == tp_char) fprintf(outf, "C"); + else if (tp == tp_schar) fprintf(outf, "UC"); + else if (tp == tp_uchar) fprintf(outf, "SC"); + else if (tp == tp_boolean) fprintf(outf, "B"); + else if (tp == tp_longreal) fprintf(outf, "R"); + else if (tp == tp_real) fprintf(outf, "F"); + else if (tp == tp_anyptr) fprintf(outf, "A"); + else if (tp == tp_void) fprintf(outf, "V"); + else if (tp == tp_text) fprintf(outf, "T"); + else if (tp == tp_bigtext) fprintf(outf, "BT"); + else if (tp == tp_sshort) fprintf(outf, "SS"); + else if (tp == tp_ushort) fprintf(outf, "US"); + else if (tp == tp_abyte) fprintf(outf, "AB"); + else if (tp == tp_sbyte) fprintf(outf, "SB"); + else if (tp == tp_ubyte) fprintf(outf, "UB"); + else if (tp == tp_str255) fprintf(outf, "S"); + else if (tp == tp_strptr) fprintf(outf, "SP"); + else if (tp == tp_charptr) fprintf(outf, "CP"); + else if (tp == tp_smallset) fprintf(outf, "SMS"); + else if (tp == tp_proc) fprintf(outf, "PR"); + else if (tp == tp_jmp_buf) fprintf(outf, "JB"); + else { + if (tp->meaning && !ISBOGUS(tp->meaning) && + tp->meaning->name && !ISBOGUS(tp->meaning->name) && + tp->meaning->name[0]) { + fprintf(outf, "%s", tp->meaning->name); + if (tp->dumped) + return; + fprintf(outf, "="); + waddr = 1; + } + if (waddr) { + fprintf(outf, "%lX", tp); + if (tp->dumped) + return; + fprintf(outf, ":"); + tp->dumped = 1; + } + switch (tp->kind) { + + case TK_STRING: + fprintf(outf, "Str"); + if (tp->structdefd) + fprintf(outf, "Conf"); + break; + + case TK_SUBR: + dumptypename(tp->basetype, 0); + break; + + case TK_POINTER: + fprintf(outf, "^"); + dumptypename(tp->basetype, 0); + break; + + case TK_SMALLARRAY: + fprintf(outf, "Sm"); + /* fall through */ + + case TK_ARRAY: + fprintf(outf, "Ar"); + if (tp->structdefd) + fprintf(outf, "Conf"); + fprintf(outf, "{"); + dumptypename(tp->indextype, 0); + fprintf(outf, "}"); + if (tp->smin) { + fprintf(outf, "Skip("); + dumpexpr(tp->smin); + fprintf(outf, ")"); + } + if (tp->smax) { + fprintf(outf, "/"); + if (!ISBOGUS(tp->smax)) + dumptypename(tp->smax->val.type, 0); + fprintf(outf, "{%d%s}", tp->escale, + tp->issigned ? "S" : "U"); + } + fprintf(outf, ":"); + dumptypename(tp->basetype, 0); + break; + + case TK_SMALLSET: + fprintf(outf, "Sm"); + /* fall through */ + + case TK_SET: + fprintf(outf, "Set{"); + dumptypename(tp->indextype, 0); + fprintf(outf, "}"); + break; + + case TK_FILE: + fprintf(outf, "File{"); + dumptypename(tp->basetype, 0); + fprintf(outf, "}"); + break; + + case TK_BIGFILE: + fprintf(outf, "BigFile{"); + dumptypename(tp->basetype, 0); + fprintf(outf, "}"); + break; + + case TK_FUNCTION: + fprintf(outf, "Func"); + if (tp->issigned) + fprintf(outf, "Link"); + fprintf(outf, "{"); + dumptypename(tp->basetype, 0); + fprintf(outf, "}"); + break; + + case TK_CPROCPTR: + fprintf(outf, "C"); + /* fall through */ + + case TK_PROCPTR: + fprintf(outf, "Proc%d{", tp->escale); + dumptypename(tp->basetype, 0); + fprintf(outf, "}"); + break; + + default: + fprintf(outf, "%s", typekindname(tp->kind)); + break; + + } + if (tp->kind != TK_ARRAY && tp->kind != TK_SMALLARRAY && + (tp->smin || tp->smax)) { + fprintf(outf, "{"); + dumpexpr(tp->smin); + fprintf(outf, ".."); + dumpexpr(tp->smax); + fprintf(outf, "}"); + } + } +#else + fprintf(outf, "%lX", tp); +#endif +} + + +void dumptypename_file(f, tp) +FILE *f; +Type *tp; +{ + FILE *save = outf; + outf = f; + dumptypename(tp, 1); + outf = save; +} + + +void dumpexpr(ex) +Expr *ex; +{ + int i; + Type *type; + char *name; + + if (!ex) { + fprintf(outf, "<NULL>"); + return; + } + if (ISBOGUS(ex)) { + fprintf(outf, "0x%lX", ex); + return; + } + if (ex->kind == EK_CONST && ex->val.type == tp_integer && + ex->nargs == 0 && !ex->val.s) { + fprintf(outf, "%ld", ex->val.i); + return; + } + if (ex->kind == EK_LONGCONST && ex->val.type == tp_integer && + ex->nargs == 0 && !ex->val.s) { + fprintf(outf, "%ldL", ex->val.i); + return; + } + name = exprkindname(ex->kind); + if (!strncmp(name, "EK_", 3)) + name += 3; + fprintf(outf, "%s", name); +#ifdef HASDUMPS + + type = ex->val.type; + fprintf(outf, "/"); + dumptypename(type, 1); + if (ex->val.i) { + switch (ex->kind) { + + case EK_VAR: + case EK_FUNCTION: + case EK_CTX: + if (ISBOGUS(ex->val.i)) + fprintf(outf, "[0x%lX]", ex->val.i); + else + fprintf(outf, "[\"%s\"]", ((Meaning *)ex->val.i)->name); + break; + + default: + fprintf(outf, "[i=%ld]", ex->val.i); + break; + } + } + if (ISBOGUS(ex->val.s)) + fprintf(outf, "[0x%lX]", ex->val.s); + else if (ex->val.s) { + switch (ex->kind) { + + case EK_BICALL: + case EK_NAME: + case EK_DOT: + fprintf(outf, "[s=\"%s\"]", ex->val.s); + break; + + default: + switch (ex->val.type ? ex->val.type->kind : TK_VOID) { + case TK_STRING: + fprintf(outf, "[s=%s]", makeCstring(ex->val.s, ex->val.i)); + break; + case TK_REAL: + fprintf(outf, "[s=%s]", ex->val.s); + break; + default: + fprintf(outf, "[s=%lx]", ex->val.s); + } + break; + } + } + if (ex->nargs > 0) { + fprintf(outf, "("); + if (ex->nargs < 10) { + for (i = 0; i < ex->nargs; i++) { + if (i) + fprintf(outf, ", "); + dumpexpr(ex->args[i]); + } + } else + fprintf(outf, "..."); + fprintf(outf, ")"); + } +#endif +} + + +void dumpexpr_file(f, ex) +FILE *f; +Expr *ex; +{ + FILE *save = outf; + outf = f; + dumpexpr(ex); + outf = save; +} + + +void innerdumpstmt(sp, indent) +Stmt *sp; +int indent; +{ +#ifdef HASDUMPS + if (!sp) { + fprintf(outf, "<NULL>\n"); + return; + } + while (sp) { + if (ISBOGUS(sp)) { + fprintf(outf, "0x%lX\n", sp); + return; + } + fprintf(outf, "%s", stmtkindname(sp->kind)); + if (sp->exp1) { + fprintf(outf, ", exp1="); + dumpexpr(sp->exp1); + } + if (sp->exp2) { + fprintf(outf, ", exp2="); + dumpexpr(sp->exp2); + } + if (sp->exp3) { + fprintf(outf, ", exp3="); + dumpexpr(sp->exp3); + } + fprintf(outf, "\n"); + if (sp->stm1) { + fprintf(outf, "%*sstm1=", indent, ""); + innerdumpstmt(sp->stm1, indent+5); + } + if (sp->stm2) { + fprintf(outf, "%*sstm2=", indent, ""); + innerdumpstmt(sp->stm2, indent+5); + } + sp = sp->next; + if (sp) { + if (indent > 5) + fprintf(outf, "%*s", indent-5, ""); + fprintf(outf, "next="); + } + } +#endif +} + + +void dumpstmt(sp, indent) +Stmt *sp; +int indent; +{ + fprintf(outf, "%*s", indent, ""); + innerdumpstmt(sp, indent); +} + + +void dumpstmt_file(f, sp) +FILE *f; +Stmt *sp; +{ + FILE *save = outf; + Stmt *savenext = NULL; + outf = f; + if (sp) { + savenext = sp->next; + sp->next = NULL; + } + dumpstmt(sp, 5); + if (sp) + sp->next = savenext; + outf = save; +} + + + +void wrapup() +{ + int i; + + for (i = 0; i < SYMHASHSIZE; i++) + dumpsymtable(symtab[i]); +} + + + + +void mem_summary() +{ +#ifdef TEST_MALLOC + printf("Summary of memory allocated but not freed:\n"); + printf("Total bytes = %d of %d\n", final_bytes, total_bytes); + printf("Expressions = %d of %d\n", final_exprs, total_exprs); + printf("Meanings = %d of %d (%d of %d)\n", + final_meanings, total_meanings, + final_meanings / sizeof(Meaning), + total_meanings / sizeof(Meaning)); + printf("Strings = %d of %d\n", final_strings, total_strings); + printf("Symbols = %d of %d\n", final_symbols, total_symbols); + printf("Types = %d of %d (%d of %d)\n", final_types, total_types, + final_types / sizeof(Type), total_types / sizeof(Type)); + printf("Statements = %d of %d (%d of %d)\n", final_stmts, total_stmts, + final_stmts / sizeof(Stmt), total_stmts / sizeof(Stmt)); + printf("Strlists = %d of %d\n", final_strlists, total_strlists); + printf("Literals = %d of %d\n", final_literals, total_literals); + printf("Ctxstacks = %d of %d\n", final_ctxstacks, total_ctxstacks); + printf("Temp vars = %d of %d\n", final_tempvars, total_tempvars); + printf("Input recs = %d of %d\n", final_inprecs, total_inprecs); + printf("Parens = %d of %d\n", final_parens, total_parens); + printf("Ptr Descs = %d of %d\n", final_ptrdescs, total_ptrdescs); + printf("Other = %d of %d\n", final_misc, total_misc); + printf("\n"); +#endif +} + + +#ifdef TEST_MALLOC + +anyptr memlist; + +anyptr test_malloc(size, total, final) +int size, *total, *final; +{ + anyptr p; + + p = malloc(size + 3*sizeof(long)); +#if 1 + ((anyptr *)p)[0] = memlist; + memlist = p; + ((long *)p)[1] = size; + ((int **)p)[2] = final; + total_bytes += size; + final_bytes += size; + *total += size; + *final += size; +#endif + return (anyptr)((long *)p + 3); +} + +void test_free(p) +anyptr p; +{ +#if 1 + final_bytes -= ((long *)p)[1-3]; + *((int **)p)[2-3] -= ((long *)p)[1-3]; + ((long *)p)[1-3] *= -1; +#endif +} + +anyptr test_realloc(p, size) +anyptr p; +int size; +{ + anyptr p2; + + p2 = test_malloc(size, &total_misc, &final_misc); + memcpy(p2, p, size); + test_free(p); + return p2; +} + +#endif /* TEST_MALLOC */ + + + + +/* End. */ + + diff --git a/MultiSource/Benchmarks/MallocBench/p2c/trans.h b/MultiSource/Benchmarks/MallocBench/p2c/trans.h new file mode 100644 index 00000000..13b8575b --- /dev/null +++ b/MultiSource/Benchmarks/MallocBench/p2c/trans.h @@ -0,0 +1,1867 @@ +/* "p2c", a Pascal to C translator, version 1.20. + Copyright (C) 1989, 1990, 1991 Free Software Foundation. + Author: Dave Gillespie. + Author's address: daveg@csvax.caltech.edu; 256-80 Caltech/Pasadena CA 91125. + +This program is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation (any version). + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; see the file COPYING. If not, write to +the Free Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ + + + + +#ifdef __STDC__ +# define PP(x) x /* use true prototypes */ +# define PV() (void) +# define Anyptr void +# define __CAT__(a,b)a##b +#else +# define PP(x) () /* use old-style declarations */ +# define PV() () +# define Anyptr char +# define __ID__(a)a +# define __CAT__(a,b)__ID__(a)b +#endif + +#define Static /* For debugging purposes */ + + + +#include <stdio.h> + + +/* If the following heuristic fails, compile -DBSD=0 for non-BSD systems, + or -DBSD=1 for BSD systems. */ + +#ifdef M_XENIX +# define BSD 0 +#endif + +#ifdef FILE /* a #define in BSD, a typedef in SYSV (hp-ux, at least) */ +# ifndef BSD +# define BSD 1 +# endif +#endif + +#ifdef BSD +# if !BSD +# undef BSD +# endif +#endif + + +#ifdef __STDC__ +/* # include <stddef.h> */ +# include <stdlib.h> +# include <limits.h> +#else +# ifndef BSD +# include <malloc.h> +# include <memory.h> +# include <values.h> +# endif +# define EXIT_SUCCESS 0 +# define EXIT_FAILURE 1 +# define CHAR_BIT 8 +# define LONG_MAX (((unsigned long)~0L) >> 1) +# define LONG_MIN (- LONG_MAX - 1) +#endif + + + +#if defined(BSD) && !defined(__STDC__) +# include <strings.h> +# define memcpy(a,b,n) bcopy(b,a,n) +# define memcmp(a,b,n) bcmp(a,b,n) +char *malloc(), *realloc(); +#else +# include <string.h> +#endif + +#include <ctype.h> + + +#ifdef __GNUC__ /* Fast, in-line version of strcmp */ +# define strcmp(a,b) ({ char *_aa = (a), *_bb = (b); int _diff; \ + for (;;) { \ + if (!*_aa && !*_bb) { _diff = 0; break; } \ + if (*_aa++ != *_bb++) \ + { _diff = _aa[-1] - _bb[-1]; break; } \ + } _diff; }) +#endif + + +#if defined(HASDUMPS) && defined(define_globals) +# define DEFDUMPS +#endif + + + +/* Constants */ + +#undef MININT /* we want the Pascal definitions, not the local C definitions */ +#undef MAXINT + +#define MININT 0x80000000 +#define MAXINT 0x7fffffff + + +#ifndef EXIT_SUCCESS +# define EXIT_SUCCESS 0 +# define EXIT_FAILURE 1 +#endif + + +#ifndef P2C_HOME +# ifdef citPWS +# define P2C_HOME "/lib/p2c" +# else +# define P2C_HOME "/usr/local/p2c" /* sounds reasonable... */ +# endif +#endif + +#ifdef define_globals +char *p2c_home = P2C_HOME; +#else +extern char *p2c_home; +#endif + +#define P2C_VERSION "1.20" + + + + +/* Types */ + +#ifdef __STDC__ +typedef void *anyptr; +#else +typedef char *anyptr; +#endif + +typedef unsigned char uchar; + + + +/* Ought to rearrange token assignments at the next full re-compile */ + +typedef enum E_token { + TOK_NONE, + + /* reserved words */ + TOK_AND, TOK_ARRAY, TOK_BEGIN, TOK_CASE, TOK_CONST, + TOK_DIV, TOK_DO, TOK_DOWNTO, TOK_ELSE, TOK_END, + TOK_FILE, TOK_FOR, TOK_FUNCTION, TOK_GOTO, TOK_IF, + TOK_IN, TOK_LABEL, TOK_MOD, TOK_NIL, TOK_NOT, + TOK_OF, TOK_OR, TOK_PACKED, TOK_PROCEDURE, TOK_PROGRAM, + TOK_RECORD, TOK_REPEAT, TOK_SET, TOK_THEN, TOK_TO, + TOK_TYPE, TOK_UNTIL, TOK_VAR, TOK_WHILE, TOK_WITH, + + /* symbols */ + TOK_DOLLAR, TOK_STRLIT, TOK_LPAR, TOK_RPAR, TOK_STAR, + TOK_PLUS, TOK_COMMA, TOK_MINUS, TOK_DOT, TOK_DOTS, + TOK_SLASH, TOK_INTLIT, TOK_REALLIT, TOK_COLON, TOK_ASSIGN, + TOK_SEMI, TOK_NE, TOK_LT, TOK_GT, TOK_LE, TOK_GE, + TOK_EQ, TOK_LBR, TOK_RBR, TOK_HAT, + TOK_INCLUDE, TOK_ENDIF, + TOK_IDENT, TOK_MININT, TOK_EOF, + + /* C symbols */ + TOK_ARROW, TOK_AMP, TOK_VBAR, TOK_BANG, + TOK_TWIDDLE, TOK_PERC, TOK_QM, + TOK_LTLT, TOK_GTGT, TOK_EQEQ, TOK_BANGEQ, + TOK_PLPL, TOK_MIMI, TOK_ANDAND, TOK_OROR, + TOK_LBRACE, TOK_RBRACE, TOK_CHARLIT, + + /* HP Pascal tokens */ + TOK_ANYVAR, TOK_EXPORT, TOK_IMPLEMENT, TOK_IMPORT, TOK_MODULE, + TOK_OTHERWISE, TOK_RECOVER, TOK_TRY, + + /* Turbo Pascal tokens */ + TOK_SHL, TOK_SHR, TOK_XOR, TOK_INLINE, TOK_ABSOLUTE, + TOK_INTERRUPT, TOK_ADDR, TOK_HEXLIT, + + /* Oregon Software Pascal tokens */ + TOK_ORIGIN, TOK_INTFONLY, + + /* VAX Pascal tokens */ + TOK_REM, TOK_VALUE, TOK_VARYING, TOK_OCTLIT, TOK_COLONCOLON, + TOK_STARSTAR, + + /* Modula-2 tokens */ + TOK_BY, TOK_DEFINITION, TOK_ELSIF, TOK_FROM, TOK_LOOP, + TOK_POINTER, TOK_QUALIFIED, TOK_RETURN, + + /* UCSD Pascal tokens */ + TOK_SEGMENT, + + TOK_LAST +} Token; + +#ifdef define_globals +char *toknames[(int)TOK_LAST] = { "", + "AND", "ARRAY", "BEGIN", "CASE", "CONST", + "DIV", "DO", "DOWNTO", "ELSE", "END", + "FILE", "FOR", "FUNCTION", "GOTO", "IF", + "IN", "LABEL", "MOD", "NIL", "NOT", + "OF", "OR", "PACKED", "PROCEDURE", "PROGRAM", + "RECORD", "REPEAT", "SET", "THEN", "TO", + "TYPE", "UNTIL", "VAR", "WHILE", "WITH", + + "a '$'", "a string literal", "a '('", "a ')'", "a '*'", + "a '+'", "a comma", "a '-'", "a '.'", "'..'", + "a '/'", "an integer", "a real number", "a colon", "a ':='", + "a semicolon", "a '<>'", "a '<'", "a '>'", "a '<='", "a '>='", + "an '='", "a '['", "a ']'", "a '^'", + "an \"include\" file", "$end$", + "an identifier", "an integer", "end of file", + + "an '->'", "an '&'", "a '|'", "a '!'", + "a '~'", "a '%'", "a '?'", + "a '<<'", "a '>>'", "a '=='", "a '!='", + "a '++'", "a '--'", "a '&&'", "a '||'", + "a '{'", "a '}'", "a character literal", + + "ANYVAR", "EXPORT", "IMPLEMENT", "IMPORT", "MODULE", + "OTHERWISE", "RECOVER", "TRY", + + "SHL", "SHR", "XOR", "INLINE", "ABSOLUTE", + "INTERRUPT", "an '@'", "a hex integer", + + "ORIGIN", "INTF-ONLY", + + "REM", "VALUE", "VARYING", "an octal integer", "a '::'", + "a '**'", + + "BY", "DEFINITION", "ELSIF", "FROM", "LOOP", + "POINTER", "QUALIFIED", "RETURN", + + "SEGMENT" +} ; +#else +extern char *toknames[]; +#endif /*define_globals*/ + +typedef struct S_strlist { + struct S_strlist *next; + long value; + char s[1]; +} Strlist; + + + +typedef struct S_value { + struct S_type *type; + long i; + char *s; +} Value; + + + +/* "Symbol" notes: + * + * The symbol table is used for several things. Mainly it records all + * identifiers in the Pascal program (normally converted to upper case). + * Also used for recording certain properties about C and Pascal names. + * + * The symbol table is a hash table of binary trees. + */ + +#define AVOIDNAME 0x1 /* Avoid this name in C code */ +#define WARNNAME 0x2 /* Warn if using this name in C code */ +#define AVOIDGLOB 0x4 /* Avoid C name except private to module */ +#define NOSIDEEFF 0x8 /* Function by this name has no side effects */ +#define STRUCTF 0x10 /* Function by this name is a StructFunction */ +#define STRLAPF 0x20 /* Function by this name is a StrlapFunction */ +#define LEAVEALONE 0x40 /* Do not use custom handler for function */ +#define DETERMF 0x80 /* Function by this name is Deterministic */ +#define FMACREC 0x100 /* Used by FieldMacro stuff */ +#define AVOIDFIELD 0x200 /* Avoid this name as a struct field name */ +#define NEEDSTATIC 0x400 /* This name must be declared static */ +#define KWPOSS 0x800 /* This word may be a keyword */ +#define FUNCBREAK 0x7000 /* Line breaking flags (see sys.p2crc) */ +# define FALLBREAK 0x1000 /* Break at all commas if at any */ +# define FSPCARG1 0x2000 /* First argument is special */ +# define FSPCARG2 0x3000 /* First two arguments are special */ +# define FSPCARG3 0x4000 /* First three arguments are special */ +#define WARNLIBR 0x8000 /* Warn for all uses of this library function */ +#define FWDPARAM 0x10000 /* Was a param name for forward-declared func */ +#define SSYNONYM 0x20000 /* Symbol is a synonym for another */ + +typedef struct S_symbol { + struct S_symbol *left; /* Left pointer in binary tree */ + struct S_symbol *right; /* Right pointer in binary tree */ + struct S_meaning *mbase; /* First normal meaning for this symbol */ + struct S_meaning *fbase; /* First record-field meaning for this symbol */ + Strlist *symbolnames; /* List of NameOf's for this name */ + long flags; /* (above) */ + Token kwtok; /* Token, if symbol is a keyword */ + char name[1]; /* Pascal name (actually variable-sized) */ +} Symbol; + + + +/* "Meaning" notes: + * + * This represents one meaning of a symbol (see below). Meanings are + * organized in a tree of contexts (i.e., scopes), and also in linked + * lists of meanings per symbol. Fields described in the following are + * undefined for kinds where they are not listed. Other fields are + * defined in all kinds of meanings. + * + * MK_MODULE: Program, module, or unit. + * mp->anyvarflag = 1 if main program, 0 if module. + * mp->cbase => First meaning in module's context. + * + * MK_CONST: Pascal CONST. + * mp->type => Type of constant, same as mp->constdefn->type & mp->val.type. + * mp->anyvarflag = 1 if FoldConstants was true when defined. + * mp->constdefn => Expression for the value of the constant. + * mp->val = Value of the const, if can be evaluated, else val.type is NULL. + * mp->xnext => Next constant in enumeration, else NULL. + * mp->isreturn = 1 if constant was declared as a macro (with #define). + * + * MK_TYPE: Pascal type name. + * mp->type => Type which name represents. + * + * MK_VAR: Normal variable. + * mp->type => Type of variable. + * mp->constdefn => Initializer for variable, else NULL. + * mp->varstructflag = 1 if variable is in parent function's varstruct. + * mp->isforward = 1 if should be declared static. + * mp->isfunction = 1 if should be declared extern. + * mp->namedfile = 1 if this file variable has a shadow file-name variable. + * mp->bufferedfile = 1 if this file variable has a shadow buffer variable. + * mp->val.s => name format string if temporary var, else NULL. + * + * MK_VARREF: Variable always referenced through a pointer. + * mp->type => Type "pointer to T" where T is type of variable. + * mp->constdefn => Initializer for the pointer, else NULL. + * (Others same as for MK_VAR.) + * + * MK_VARMAC: Variable which has a VarMacro. + * mp->type => Type of variable. + * mp->constdefn => Expression for VarMacro definition. + * (Others same as for MK_VAR.) + * + * MK_SPVAR: Special variable. + * mp->handler => C function to parse and translate the special variable. + * + * MK_FIELD: Record/struct field name. + * mp->ctx, cbase = unused (unlike other meanings). + * mp->cnext => Next field in record or variant. + * mp->type => Type of field (base type if a bit-field). + * mp->rectype => Type of containing record. + * mp->constdefn => Expression for definition if FieldMacro, else NULL. + * mp->val.i = Number of bits if bit-field, or 0 if normal field. + * mp->val.type => True type of bit-field, else same as mp->type. + * mp->isforward = 1 if tag field for following variant, else 0. + * mp->namedfile = 1 if this file field has a shadow file-name field. + * mp->bufferedfile = 1 if this file field has a shadow buffer field. + * + * MK_VARIANT: Header for variant record case. + * mp->ctx => First field in variant (unlike other meanings). + * mp->cbase = unused (unlike other meanings). + * mp->cnext => Next variant in record (or next sub-variant in variant). + * mp->rectype => Type of containing record. + * mp->val = Tag value of variant. + * + * MK_LABEL: Statement label. + * mp->val.i => Case number if used by non-local gotos, else -1. + * mp->xnext => MK_VAR representing associated jmp_buf variable. + * (All optional fields are unused.) + * + * MK_FUNCTION: Procedure or function. + * mp->type => TK_FUNCTION type. + * mp->cbase => First meaning in procedure's context (when isfunction is 1, + * this will always be the return-value meaning.) + * mp->val.i => Body of the function (cast to Stmt *). + * mp->constdefn => Expression for definition if FuncMacro, else NULL. + * mp->handler => C function to adjust parse tree if predefined, else NULL. + * mp->isfunction = 1 if function, 0 if procedure. + * mp->isforward = 1 if function has been declared forward. + * mp->varstructflag = 1 if function has a varstruct. + * mp->needvarstruct = 1 if no varstruct yet but may need one. + * mp->namedfile = 1 if function should be declared "inline". + * + * MK_SPECIAL: Special, irregular built-in function. + * mp->handler => C function to parse and translate the special function. + * mp->constdefn => Expression for definition if FuncMacro, else NULL. + * mp->isfunction = 1 if function, 0 if procedure. + * + * MK_PARAM: Procedure or function parameter, or function return value. + * mp->type => Type of parameter. + * mp->isreturn = 1 if a function return value (not on parameter list). + * mp->xnext => Next parameter of function. + * mp->fakeparam = 1 if a fake parameter (e.g., conformant array size). + * mp->othername => Name of true param if this one is a local copy. + * mp->rectype => Type of true param if this one is a local copy. + * If a normal copy param, will be "pointer to" mp->type. + * If copied for varstruct reasons, will be same as mp->type. + * mp->varstructflag = 1 if variable is in parent function's varstruct. + * + * MK_VARPARAM: VAR parameter, or StructFunction return value. + * mp->type => Type "pointer to T" where T is type of parameter. + * mp->anyvarflag = 1 if no type checking is to be applied to parameter. + * mp->isreturn = 1 if a StructFunction return value (will be first param). + * (Others same as for MK_PARAM.) + * + * MK_VARPARAM with mp->type == tp_anyptr: Turbo "typeless var" parameter. + * mp->type = tp_anyptr. + * mp->anyvarflag = 1. + * (Others same as for MK_PARAM.) + * + * MK_VARPARAM with mp->type == tp_strptr: HP Pascal "var s:string" parameter. + * mp->type = tp_strptr. + * mp->anyvarflag = 1 if a separate "strmax" parameter is passed. + * (Others same as for MK_PARAM.) + * + * MK_SYNONYM: Meaning which should be treated as identical to another. + * mp->xnext => Actual meaning to be used. + * + */ + +enum meaningkind { + MK_NONE, MK_SPECIAL, + MK_MODULE, MK_FUNCTION, MK_CONST, MK_VAR, MK_TYPE, + MK_FIELD, MK_LABEL, MK_VARIANT, + MK_PARAM, MK_VARPARAM, MK_VARREF, MK_VARMAC, + MK_SPVAR, MK_SYNONYM, + MK_LAST +} ; + +#ifdef DEFDUMPS +char *meaningkindnames[(int)MK_LAST] = { + "MK_NONE", "MK_SPECIAL", + "MK_MODULE", "MK_FUNCTION", "MK_CONST", "MK_VAR", "MK_TYPE", + "MK_FIELD", "MK_LABEL", "MK_VARIANT", + "MK_PARAM", "MK_VARPARAM", "MK_VARREF", "MK_VARMAC", + "MK_SPVAR", "MK_SYNONYM" +} ; +#endif /*DEFDUMPS*/ + +typedef struct S_meaning { + struct S_meaning *snext; /* Next meaning for this symbol */ + struct S_meaning *cnext; /* Next meaning in this meaning's context */ + struct S_meaning *cbase; /* First meaning in this context */ + struct S_meaning *ctx; /* Context of this meaning */ + struct S_meaning *xnext; /* (above) */ + struct S_meaning *dtype; /* Declared type name, if any */ + struct S_symbol *sym; /* Symbol of which this is a meaning */ + struct S_type *type; /* (above) */ + struct S_type *rectype; /* (above) */ + struct S_expr *constdefn; /* (above) */ + enum meaningkind kind; /* Kind of meaning */ + unsigned needvarstruct:1, /* (above) */ + varstructflag:1, /* (above) */ + wasdeclared:1, /* Declaration has been written for meaning */ + istemporary:1, /* Is a temporary variable */ + isforward:1, /* (above) */ + isfunction:1, /* (above) */ + anyvarflag:1, /* (above) */ + isactive:1, /* Meaning is currently in scope */ + exported:1, /* Meaning is visible outside this module */ + warnifused:1, /* WarnNames was 1 when meaning was declared */ + dumped:1, /* Has been dumped (for debugging) */ + isreturn:1, /* (above) */ + fakeparam:1, /* (above) */ + namedfile:1, /* (above) */ + bufferedfile:1, /* (above) */ + volatilequal:1, /* Object has C "volatile" qualifier */ + constqual:1, /* Object has C "const" qualifier */ + dummy17:1, dummy18:1, dummy19:1, + dummy20:1, dummy21:1, dummy22:1, dummy23:1, dummy24:1, dummy25:1, + dummy26:1, dummy27:1, dummy28:1, dummy29:1, dummy30:1, dummy31:1; + Value val; /* (above) */ + int refcount; /* Number of references to meaning in program */ + char *name; /* Print name (i.e., C name) of the meaning */ + char *othername; /* (above) */ + struct S_expr *(*handler)(); /* Custom translator for procedure */ + Strlist *comments; /* Comments associated with meaning */ +} Meaning; + + + +/* "Type" notes: + * + * This struct represents a data type. Types are stored in a strange + * cross between Pascal and C semantics. (This usually works out okay.) + * + * TK_INTEGER: Base integer type. + * The following types are TK_INTEGER: + * tp_integer, tp_unsigned, tp_int, tp_uint, tp_sint. + * All other integer types are represented by subranges. + * tp->smin => Minimum value for integer. + * tp->smax => Maximum value for integer. + * + * TK_CHAR: Base character type. + * The following types are TK_CHAR: tp_char, tp_schar, tp_uchar. + * All other character types are represented by subranges. + * tp->smin => Minimum value for character. + * tp->smax => Maximum value for character. + * + * TK_BOOLEAN: Boolean type. + * The only TK_BOOLEAN type is tp_boolean. + * tp->smin => "False" expression. + * tp->smax => "True" expression. + * + * TK_REAL: Real types. + * The only TK_REAL types are tp_real, tp_longreal, and/or the SINGLE type. + * + * TK_VOID: C "void" type. + * The only TK_VOID type is tp_void. + * + * TK_SUBR: Subrange of ordinal type. + * tp->basetype => a TK_INTEGER, TK_CHAR, TK_BOOLEAN, or TK_ENUM type. + * tp->smin => Minimum ordinal value for subrange. + * tp->smax => Maximum ordinal value for subrange. + * + * TK_ENUM: Enumerated type. + * tp->fbase => First enumeration constant. + * tp->smin => Minimum value (zero). + * tp->smax => Maximum value (number of choices minus 1). + * + * TK_POINTER: Pointer type. + * tp->basetype => Base type of pointer. + * tp->smin => EK_NAME for type if not-yet-resolved forward; else NULL. + * tp->fbase => Actual type name for tp->basetype, or NULL. + * Only one pointer type is ever generated for a given other type; + * each tp->pointertype points back to that type if it has been generated. + * + * TK_STRING: Pascal string or VARYING OF CHAR type. + * tp->basetype => tp_char. + * tp->indextype => TK_SUBR from 0 to maximum string length. + * tp->structdefd = 1 if type is for a conformant VARYING OF CHAR parameter. + * + * TK_RECORD: Pascal record/C struct type. + * tp->fbase => First field in record. + * tp->structdefd = 1 if struct type has been declared in output. + * + * TK_ARRAY with smax == NULL: Normal array type. + * tp->basetype => Element type of array. + * tp->indextype => Index type (usually a TK_SUBR). + * tp->smin => Integer constant if SkipIndices was used, else NULL. + * tp->smax = NULL. + * tp->structdefd = 1 if type is for a conformant array parameter. + * tp->fbase => Actual type name for tp->basetype, or NULL. + * + * TK_ARRAY with smax != NULL: Large packed array type. + * tp->basetype => Element type of C array (tp_ubyte/tp_sbyte/tp_sshort). + * tp->indextype => Index type (usually a TK_SUBR). + * tp->smin => Integer constant if SkipIndices was used, else NULL. + * tp->smax => EK_TYPENAME for element type of Pascal array. + * tp->escale = log-base-two of number of bits per packed element, else 0. + * tp->issigned = 1 if packed array elements are signed, 0 if unsigned. + * tp->structdefd = 1 if type is for a conformant array parameter. + * tp->fbase => Actual type name for tp->basetype, or NULL. + * + * TK_SMALLARRAY: Packed array fitting within a single integer. + * (Same as for packed TK_ARRAY.) + * + * TK_SET: Normal set type. + * tp->basetype => tp_integer. + * tp->indextype => Element type of the set. + * + * TK_SMALLSET: Set fitting within a single integer. + * (Same as for TK_SET.) + * + * TK_FILE: File type (corresponds to C "FILE" type). + * tp->basetype => Type of file elements, or tp_abyte if UCSD untyped file. + * A Pascal "file" variable is represented as a TK_POINTER to a TK_FILE. + * + * TK_BIGFILE: File type with attached buffers and name. + * tp->basetype => Type of file elements, or tp_abyte if UCSD untyped file. + * A Pascal "file" variable is represented directly as a TK_BIGFILE. + * + * TK_FUNCTION: Procedure or procedure-pointer type. + * tp->basetype => Return type of function, or tp_void if procedure. + * tp->issigned = 1 if type has a generic static link. + * tp->fbase => First argument (or StructFunction return buffer pointer). + * + * TK_PROCPTR: Procedure pointer with static link. + * tp->basetype => TK_FUNCTION type. + * tp->fbase => Internal Meaning struct associated with basetype. + * tp->escale = Value of StaticLinks when type was declared. + * + * TK_CPROCPTR: Procedure pointer without static link. + * tp->basetype => TK_FUNCTION type. + * tp->fbase => Internal Meaning struct associated with basetype. + * tp->escale = Value of StaticLinks = 0. + * + * TK_SPECIAL: Special strange data type. + * Only TK_SPECIAL type at present is tp_jmp_buf. + * + */ + +enum typekind { + TK_NONE, + TK_INTEGER, TK_CHAR, TK_BOOLEAN, TK_REAL, TK_VOID, + TK_SUBR, TK_ENUM, TK_POINTER, TK_STRING, + TK_RECORD, TK_ARRAY, TK_SET, TK_FILE, TK_FUNCTION, + TK_PROCPTR, TK_SMALLSET, TK_SMALLARRAY, TK_CPROCPTR, + TK_SPECIAL, TK_BIGFILE, + TK_LAST +} ; + +#ifdef DEFDUMPS +char *typekindnames[(int)TK_LAST] = { + "TK_NONE", + "TK_INTEGER", "TK_CHAR", "TK_BOOLEAN", "TK_REAL", "TK_VOID", + "TK_SUBR", "TK_ENUM", "TK_POINTER", "TK_STRING", + "TK_RECORD", "TK_ARRAY", "TK_SET", "TK_FILE", "TK_FUNCTION", + "TK_PROCPTR", "TK_SMALLSET", "TK_SMALLARRAY", "TK_CPROCPTR", + "TK_SPECIAL", "TK_BIGFILE" +} ; +#endif /*DEFDUMPS*/ + +typedef struct S_type { + enum typekind kind; /* Kind of type */ + struct S_type *basetype; /* (above) */ + struct S_type *indextype; /* (above) */ + struct S_type *pointertype; /* Pointer to this type */ + struct S_meaning *meaning; /* Name of this type, if any */ + struct S_meaning *fbase; /* (above) */ + struct S_expr *smin; /* (above) */ + struct S_expr *smax; /* (above) */ + unsigned issigned:1, /* (above) */ + dumped:1, /* Has been dumped (for debugging) */ + structdefd:1, /* (above) */ + preserved:1; /* Declared with preservetypes = 1 */ + short escale; /* (above) */ +} Type; + + +/* "Expr" notes: + * + * Expression trees generally reflect C notation and semantics. For example, + * EK_ASSIGN is not generated for string arguments; these would get an + * EK_BICALL to strcpy instead. + * + * The data type of each expression node is stored in its "val.type" field. + * The rest of the "val" field is used only when shown below. + * The "nargs" field always contains the number of arguments; the "args" + * array is allocated to that size and will contain non-NULL Expr pointers. + * + * EK_EQ, EK_NE, EK_LT, EK_GT, EK_LE, EK_GE: Relational operators. + * ep->nargs = 2. + * + * EK_PLUS: Addition. + * ep->nargs >= 2. + * + * EK_NEG: Negation. + * ep->nargs = 1. + * + * EK_TIMES: Multiplication. + * ep->nargs >= 2. + * + * EK_DIVIDE: Real division. + * ep->nargs = 2. + * + * EK_DIV: Integer division. + * ep->nargs = 2. + * + * EK_MOD: Integer modulo (C "%" operator). + * ep->nargs = 2. + * + * EK_OR, EK_AND: Logical operators (C "&&" and "||"). + * ep->nargs = 2. + * + * EK_NOT: Logical NOT (C "!" operator). + * ep->nargs = 1. + * + * EK_BAND, EK_BOR, EK_BXOR: Bitwise operators (C "&", "|", "^"). + * ep->nargs = 2. + * + * EK_BNOT: Bitwise NOT (C "~" operator). + * ep->nargs = 1. + * + * EK_LSH, EK_RSH: Shift operators. + * ep->nargs = 2. + * + * EK_HAT: Pointer dereference. + * ep->nargs = 1. + * + * EK_INDEX: Array indexing. + * ep->nargs = 2. + * + * EK_CAST: "Soft" type cast, change data type retaining value. + * ep->type => New data type. + * ep->nargs = 1. + * + * EK_ACTCAST: "Active" type cast, performs a computation as result of cast. + * ep->type => New data type. + * ep->nargs = 1. + * + * EK_LITCAST: Literal type cast. + * ep->nargs = 2. + * ep->args[0] => EK_TYPENAME expression for name of new data type. + * ep->args[1] => Argument of cast. + * + * EK_DOT: Struct field extraction. + * ep->nargs = 1. (Only one of the following will be nonzero:) + * ep->val.i => MK_FIELD being extracted (cast to Meaning *), else 0. + * ep->val.s => Literal name of field being extracted, else NULL. + * + * EK_COND: C conditional expression. + * ep->nargs = 3. + * ep->args[0] => Condition expression. + * ep->args[1] => "Then" expression. + * ep->args[2] => "Else" expression. + * + * EK_ADDR: Address-of operator. + * ep->nargs = 1. + * + * EK_SIZEOF: Size-of operator. + * ep->nargs = 1. + * ep->args[0] => Argument expression, may be EK_TYPENAME. + * + * EK_CONST: Literal constant. + * ep->nargs = 0 or 1. + * ep->val = Value of constant. + * ep->args[0] => EK_NAME of printf format string for constant, if any. + * + * EK_LONGCONST: Literal constant, type "long int". + * (Same as for EK_CONST.) + * + * EK_VAR: Variable name. + * ep->nargs = 0. + * ep->val.i => Variable being referenced (cast to Meaning *). + * + * EK_ASSIGN: Assignment operator. + * ep->nargs = 2. + * ep->args[0] => Destination l-value expression. + * ep->args[1] => Source expression. + * + * EK_POSTINC, EK_POSTDEC: Post-increment/post-decrement operators. + * ep->nargs = 1. + * + * EK_MACARG: Placeholder for argument in expression for FuncMacro, etc. + * ep->nargs = 0. + * ep->val.i = Code selecting which argument. + * + * EK_CHECKNIL: Null-pointer check. + * ep->nargs = 1. + * + * EK_BICALL: Call to literal function name. + * ep->val.s => Name of function. + * + * EK_STRUCTCONST: Structured constant. + * ep->nargs = Number of elements in constant. + * (Note: constdefn points to an EK_CONST whose val.i points to this.) + * + * EK_STRUCTOF: Repeated element in structured constant. + * ep->nargs = 1. + * ep->val.i = Number of repetitions. + * + * EK_COMMA: C comma operator. + * ep->nargs >= 2. + * + * EK_NAME: Literal variable name. + * ep->nargs = 0. + * ep->val.s => Name of variable. + * + * EK_CTX: Name of a context, with static links. + * ep->nargs = 0. + * ep->val.i => MK_FUNCTION or MK_MODULE to name (cast to Meaning *). + * + * EK_SPCALL: Special function call. + * ep->nargs = 1 + number of arguments to function. + * ep->args[0] => Expression which is the function to call. + * + * EK_TYPENAME: Type name. + * ep->nargs = 0. + * ep->val.type => Type whose name should be printed. + * + * EK_FUNCTION: Normal function call. + * ep->val.i => MK_FUNCTION being called (cast to Meaning *). + * + */ + +enum exprkind { + EK_EQ, EK_NE, EK_LT, EK_GT, EK_LE, EK_GE, + EK_PLUS, EK_NEG, EK_TIMES, EK_DIVIDE, + EK_DIV, EK_MOD, + EK_OR, EK_AND, EK_NOT, + EK_BAND, EK_BOR, EK_BXOR, EK_BNOT, EK_LSH, EK_RSH, + EK_HAT, EK_INDEX, EK_CAST, EK_DOT, EK_COND, + EK_ADDR, EK_SIZEOF, EK_ACTCAST, + EK_CONST, EK_VAR, EK_FUNCTION, + EK_ASSIGN, EK_POSTINC, EK_POSTDEC, EK_CHECKNIL, + EK_MACARG, EK_BICALL, EK_STRUCTCONST, EK_STRUCTOF, + EK_COMMA, EK_LONGCONST, EK_NAME, EK_CTX, EK_SPCALL, + EK_LITCAST, EK_TYPENAME, + EK_LAST +} ; + +#ifdef DEFDUMPS +char *exprkindnames[(int)EK_LAST] = { + "EK_EQ", "EK_NE", "EK_LT", "EK_GT", "EK_LE", "EK_GE", + "EK_PLUS", "EK_NEG", "EK_TIMES", "EK_DIVIDE", + "EK_DIV", "EK_MOD", + "EK_OR", "EK_AND", "EK_NOT", + "EK_BAND", "EK_BOR", "EK_BXOR", "EK_BNOT", "EK_LSH", "EK_RSH", + "EK_HAT", "EK_INDEX", "EK_CAST", "EK_DOT", "EK_COND", + "EK_ADDR", "EK_SIZEOF", "EK_ACTCAST", + "EK_CONST", "EK_VAR", "EK_FUNCTION", + "EK_ASSIGN", "EK_POSTINC", "EK_POSTDEC", "EK_CHECKNIL", + "EK_MACARG", "EK_BICALL", "EK_STRUCTCONST", "EK_STRUCTOF", + "EK_COMMA", "EK_LONGCONST", "EK_NAME", "EK_CTX", "EK_SPCALL", + "EK_LITCAST", "EK_TYPENAME" +} ; +#endif /*DEFDUMPS*/ + +typedef struct S_expr { + enum exprkind kind; + short nargs; + Value val; + struct S_expr *args[1]; /* (Actually, variable-sized) */ +} Expr; + + + +/* "Stmt" notes. + * + * Statements form linked lists along the "next" pointers. + * All other pointers are NULL and unused unless shown below. + * + * SK_ASSIGN: Assignment or function call (C expression statement). + * sp->exp1 => Expression to be evaluated. + * + * SK_RETURN: C "return" statement. + * sp->exp1 => Value to return, else NULL. + * + * SK_CASE: C "switch" statement. + * sp->exp1 => Switch selector expression. + * sp->stm1 => List of SK_CASELABEL statements, followed by list of + * statements that make up the "default:" clause. + * + * SK_CASELABEL: C "case" label. + * sp->exp1 => Case value. + * sp->stm1 => List of SK_CASELABELs labelling the same clause, followed + * by list of statements in that clause. + * + * SK_CASECHECK: Case-value-range-error, occurs in "default:" clause. + * + * SK_IF: C "if" statement. + * sp->exp1 => Conditional expression. + * sp->exp2 => Constant expression, "1" if this "if" should be else-if'd + * on to parent "if". NULL => follow ElseIf parameter. + * sp->stm1 => "Then" clause. + * sp->stm2 => "Else" clause. + * + * SK_FOR: C "for" statement. + * sp->exp1 => Initialization expression (may be NULL). + * sp->exp2 => Conditional expression (may be NULL). + * sp->exp3 => Iteration expression (may be NULL). + * sp->stm1 => Loop body. + * + * SK_REPEAT: C "do-while" statement. + * sp->exp1 => Conditional expression (True = continue loop). + * sp->stm1 => Loop body. + * + * SK_WHILE: C "while" statement. + * sp->exp1 => Conditional expression. + * sp->stm1 => Loop body. + * + * SK_BREAK: C "break" statement. + * + * SK_CONTINUE: C "continue" statement. + * + * SK_TRY: HP Pascal TRY-RECOVER statement. + * sp->exp1->val.i = Global serial number of the TRY statement. + * sp->exp2 = Non-NULL if must generate a label for RECOVER block. + * sp->stm1 => TRY block. + * sp->stm2 => RECOVER block. + * + * SK_GOTO: C "goto" statement. + * sp->exp1 => EK_NAME for the label number or name. + * + * SK_LABEL: C statement label. + * sp->exp1 => EK_NAME for the label number of name. + * + * SK_HEADER: Function/module header. + * sp->exp1 => EK_VAR pointing to MK_FUNCTION or MK_MODULE. + * (This always comes first in a context's statement list.) + * + * SK_BODY: Body of function/module. + * sp->stm1 => SK_HEADER that begins the body. + * (This exists only during fixblock.) + * + */ + +enum stmtkind { + SK_ASSIGN, SK_RETURN, + SK_CASE, SK_CASELABEL, SK_IF, + SK_FOR, SK_REPEAT, SK_WHILE, SK_BREAK, SK_CONTINUE, + SK_TRY, SK_GOTO, SK_LABEL, + SK_HEADER, SK_CASECHECK, SK_BODY, + SK_LAST +} ; + +#ifdef DEFDUMPS +char *stmtkindnames[(int)SK_LAST] = { + "SK_ASSIGN", "SK_RETURN", + "SK_CASE", "SK_CASELABEL", "SK_IF", + "SK_FOR", "SK_REPEAT", "SK_WHILE", "SK_BREAK", "SK_CONTINUE", + "SK_TRY", "SK_GOTO", "SK_LABEL", + "SK_HEADER", "SK_CASECHECK", "SK_BODY" +} ; +#endif /*DEFDUMPS*/ + +typedef struct S_stmt { + enum stmtkind kind; + struct S_stmt *next, *stm1, *stm2; + struct S_expr *exp1, *exp2, *exp3; + long serial; +} Stmt; + + + +/* Flags for out_declarator(): */ + +#define ODECL_CHARSTAR 0x1 +#define ODECL_FREEARRAY 0x2 +#define ODECL_FUNCTION 0x4 +#define ODECL_HEADER 0x8 +#define ODECL_FORWARD 0x10 +#define ODECL_DECL 0x20 +#define ODECL_NOPRES 0x40 + + +/* Flags for fixexpr(): */ + +#define ENV_EXPR 0 /* return value needed */ +#define ENV_STMT 1 /* return value ignored */ +#define ENV_BOOL 2 /* boolean return value needed */ + + +/* Flags for defmacro(): */ +#define MAC_VAR 0 /* VarMacro */ +#define MAC_CONST 1 /* ConstMacro */ +#define MAC_FIELD 2 /* FieldMacro */ +#define MAC_FUNC 3 /* FuncMacro */ + +#define FMACRECname "<rec>" + + +/* Kinds of comment lines: */ +#define CMT_SHIFT 24 +#define CMT_MASK ((1L<<CMT_SHIFT)-1) +#define CMT_KMASK ((1<<(32-CMT_SHIFT))-1) +#define CMT_DONE 0 /* comment that has already been printed */ +#define CMT_PRE 1 /* comment line preceding subject */ +#define CMT_POST 2 /* comment line following subject */ +#define CMT_TRAIL 4 /* comment at end of line of code */ +#define CMT_ONBEGIN 6 /* comment on "begin" of procedure */ +#define CMT_ONEND 7 /* comment on "end" of procedure */ +#define CMT_ONELSE 8 /* comment on "else" keyword */ +#define CMT_NOT 256 /* negation of above, for searches */ + +#ifdef define_globals +char *CMT_NAMES[] = { "DONE", "PRE", "POST", "3", "TRAIL", "5", + "BEGIN", "END", "ELSE" }; +#else +extern char *CMT_NAMES[]; +#endif + +#define getcommentkind(cmt) (((cmt)->value >> CMT_SHIFT) & CMT_KMASK) + + +/* Kinds of operator line-breaking: */ +#define BRK_LEFT 0x1 +#define BRK_RIGHT 0x2 +#define BRK_LPREF 0x4 +#define BRK_RPREF 0x8 +#define BRK_ALLNONE 0x10 +#define BRK_HANG 0x20 + + + + +/* Translation parameters: */ + +#ifdef define_parameters +# define extern +#endif /* define_parameters */ + +extern enum { + UNIX_ANY, UNIX_BSD, UNIX_SYSV +} which_unix; + +extern enum { + LANG_HP, LANG_UCSD, LANG_TURBO, LANG_OREGON, LANG_VAX, + LANG_MODULA, LANG_MPW, LANG_BERK +} which_lang; + +extern short debug, tokentrace, quietmode, cmtdebug, copysource; +extern int nobanner, showprogress, maxerrors; +extern short hpux_lang, integer16, doublereals, pascalenumsize; +extern short needsignedbyte, unsignedchar, importall; +extern short nestedcomments, pascalsignif, pascalcasesens; +extern short dollar_idents, ignorenonalpha, modula2; +extern short ansiC, cplus, signedchars, signedfield, signedshift; +extern short hassignedchar, voidstar, symcase, ucconsts, csignif; +extern short copystructs, usevextern, implementationmodules; +extern short useAnyptrMacros, usePPMacros; +extern short sprintf_value; +extern char codefnfmt[40], modulefnfmt[40], logfnfmt[40]; +extern char headerfnfmt[40], headerfnfmt2[40], includefnfmt[40]; +extern char selfincludefmt[40]; +extern char constformat[40], moduleformat[40], functionformat[40]; +extern char varformat[40], fieldformat[40], typeformat[40]; +extern char enumformat[40], symbolformat[40]; +extern char p2c_h_name[40], exportsymbol[40], export_symbol[40]; +extern char externalias[40]; +extern char memcpyname[40], sprintfname[40]; +extern char roundname[40], divname[40], modname[40], remname[40]; +extern char strposname[40], strcicmpname[40]; +extern char strsubname[40], strdeletename[40], strinsertname[40]; +extern char strmovename[40], strpadname[40]; +extern char strltrimname[40], strrtrimname[40], strrptname[40]; +extern char absname[40], oddname[40], evenname[40], swapname[40]; +extern char mallocname[40], freename[40], freervaluename[40]; +extern char randrealname[40], randintname[40], randomizename[40]; +extern char skipspacename[40], readlnname[40], freopenname[40]; +extern char eofname[40], eolnname[40], fileposname[40], maxposname[40]; +extern char setunionname[40], setintname[40], setdiffname[40]; +extern char setinname[40], setaddname[40], setaddrangename[40]; +extern char setremname[40]; +extern char setequalname[40], subsetname[40], setxorname[40]; +extern char setcopyname[40], setexpandname[40], setpackname[40]; +extern char getbitsname[40], clrbitsname[40], putbitsname[40]; +extern char declbufname[40], declbufncname[40]; +extern char resetbufname[40], setupbufname[40]; +extern char getfbufname[40], chargetfbufname[40], arraygetfbufname[40]; +extern char putfbufname[40], charputfbufname[40], arrayputfbufname[40]; +extern char getname[40], chargetname[40], arraygetname[40]; +extern char putname[40], charputname[40], arrayputname[40]; +extern char eofbufname[40], fileposbufname[40]; +extern char storebitsname[40], signextname[40]; +extern char filenotfoundname[40], filenotopenname[40]; +extern char filewriteerrorname[40], badinputformatname[40], endoffilename[40]; +extern short strcpyleft; +extern char language[40], target[40]; +extern int sizeof_char, sizeof_short, sizeof_integer, sizeof_pointer, + sizeof_double, sizeof_float, sizeof_enum, sizeof_int, sizeof_long; +extern short size_t_long; +extern int setbits, defaultsetsize, seek_base, integerwidth, realwidth; +extern short quoteincludes, expandincludes, collectnest; +extern int phystabsize, intabsize, linewidth, maxlinewidth; +extern int majorspace, minorspace, functionspace, minfuncspace; +extern int casespacing, caselimit; +extern int returnlimit, breaklimit, continuelimit; +extern short nullstmtline, shortcircuit, shortopt, usecommas, elseif; +extern short usereturns, usebreaks, infloopstyle, reusefieldnames; +extern short bracesalways, braceline, bracecombine, braceelse, braceelseline; +extern short newlinefunctions; +extern short eatcomments, spitcomments, spitorphancomments; +extern short commentafter, blankafter; +extern int tabsize, blockindent, bodyindent, argindent; +extern int switchindent, caseindent, labelindent; +extern int openbraceindent, closebraceindent; +extern int funcopenindent, funccloseindent; +extern int structindent, structinitindent, extrainitindent; +extern int constindent, commentindent, bracecommentindent, commentoverindent; +extern int declcommentindent; +extern int minspacing, minspacingthresh; +extern int extraindent, bumpindent; +extern double overwidepenalty, overwideextrapenalty; +extern double commabreakpenalty, commabreakextrapenalty; +extern double assignbreakpenalty, assignbreakextrapenalty; +extern double specialargbreakpenalty; +extern double opbreakpenalty, opbreakextrapenalty, exhyphenpenalty; +extern double logbreakpenalty, logbreakextrapenalty; +extern double relbreakpenalty, relbreakextrapenalty; +extern double morebreakpenalty, morebreakextrapenalty; +extern double parenbreakpenalty, parenbreakextrapenalty; +extern double qmarkbreakpenalty, qmarkbreakextrapenalty; +extern double wrongsidepenalty, earlybreakpenalty, extraindentpenalty; +extern double bumpindentpenalty, nobumpindentpenalty; +extern double indentamountpenalty, sameindentpenalty; +extern double showbadlimit; +extern long maxalts; +extern short breakbeforearith, breakbeforerel, breakbeforelog; +extern short breakbeforedot, breakbeforeassign; +extern short for_allornone; +extern short extraparens, breakparens, returnparens; +extern short variablearrays, initpacstrings, stararrays; +extern short spaceexprs, spacefuncs, spacecommas, implicitzero, starindex; +extern int casetabs; +extern short starfunctions, mixfields, alloczeronil, postincrement; +extern short mixvars, mixtypes, mixinits, nullcharconst, castnull, addindex; +extern short highcharints, highcharbits, hasstaticlinks; +extern short mainlocals, storefilenames, addrstdfiles, readwriteopen; +extern short charfiletext, messagestderr, literalfilesflag, structfilesflag; +extern short printfonly, mixwritelns, usegets, newlinespace, binarymode; +extern char openmode[40], filenamefilter[40]; +extern short atan2flag, div_po2, mod_po2, assumebits, assumesigns; +extern short fullstrwrite, fullstrread, whilefgets, buildreads, buildwrites; +extern short foldconsts, foldstrconsts, charconsts, useconsts, useundef; +extern short elimdeadcode, offsetforloops, forevalorder; +extern short smallsetconst, bigsetconst, lelerange, unsignedtrick; +extern short useisalpha, useisspace, usestrncmp; +extern short casecheck, arraycheck, rangecheck, nilcheck, malloccheck; +extern short checkfileopen, checkfileisopen, checkfilewrite; +extern short checkreadformat, checkfileeof, checkstdineof, checkfileseek; +extern short squeezesubr, useenum, enumbyte, packing, packsigned, keepnulls; +extern short compenums, formatstrings, alwayscopyvalues; +extern short use_static, var_static, void_args, prototypes, fullprototyping; +extern short procptrprototypes, promote_enums; +extern short preservetypes, preservepointers, preservestrings; +extern short castargs, castlongargs, promoteargs, fixpromotedargs; +extern short varstrings, varfiles, copystructfuncs; +extern long skipindices; +extern short stringleaders; +extern int stringceiling, stringdefault, stringtrunclimit, longstringsize; +extern short warnnames, warnmacros; +extern Strlist *importfrom, *importdirs, *includedirs, *includefrom; +extern Strlist *librfiles, *bufferedfiles, *unbufferedfiles; +extern Strlist *externwords, *cexternwords; +extern Strlist *varmacros, *constmacros, *fieldmacros; +extern Strlist *funcmacros, *funcmacroargs, *nameoflist; +extern Strlist *specialmallocs, *specialfrees, *specialsizeofs; +extern Strlist *initialcalls, *eatnotes, *literalfiles, *structfiles; + +extern char fixedcomment[40], permanentcomment[40], interfacecomment[40]; +extern char embedcomment[40], skipcomment[40], noskipcomment[40]; +extern char signedcomment[40], unsignedcomment[40]; + +extern char name_RETV[40], name_STRMAX[40], name_LINK[40]; +extern char name_COPYPAR[40], name_TEMP[40], name_DUMMY[40]; +extern char name_LOC[40], name_VARS[40], name_STRUCT[40]; +extern char name_FAKESTRUCT[40], name_AHIGH[40], name_ALOW[40]; +extern char name_UNION[40], name_VARIANT[40], name_LABEL[40], name_LABVAR[40]; +extern char name_WITH[40], name_FOR[40], name_ENUM[40]; +extern char name_PTR[40], name_STRING[40], name_SET[40]; +extern char name_PROCEDURE[40], name_MAIN[40], name_UNITINIT[40]; +extern char name_HSYMBOL[40], name_GSYMBOL[40]; +extern char name_SETBITS[40], name_UCHAR[40], name_SCHAR[40]; +extern char name_BOOLEAN[40], name_TRUE[40], name_FALSE[40], name_NULL[40]; +extern char name_ESCAPECODE[40], name_IORESULT[40]; +extern char name_ARGC[40], name_ARGV[40]; +extern char name_ESCAPE[40], name_ESCIO[40], name_CHKIO[40], name_SETIO[40]; +extern char name_OUTMEM[40], name_CASECHECK[40], name_NILCHECK[40]; +extern char name_FNSIZE[40], name_FNVAR[40]; +extern char alternatename1[40], alternatename2[40], alternatename[40]; + + +#ifndef define_parameters +extern +#endif +struct rcstruct { + char kind; + char chgmode; + char *name; + anyptr ptr; + long def; +} rctable[] +#ifdef define_parameters + = { + 'S', 'R', "DEBUG", (anyptr) &debug, 0, + 'I', 'R', "SHOWPROGRESS", (anyptr) &showprogress, 0, + 'S', 'V', "TOKENTRACE", (anyptr) &tokentrace, 0, + 'S', 'V', "QUIET", (anyptr) &quietmode, 0, + 'S', 'V', "COPYSOURCE", (anyptr) ©source, 0, + 'I', 'R', "MAXERRORS", (anyptr) &maxerrors, 0, + 'X', ' ', "INCLUDE", (anyptr) NULL, 2, + +/* INPUT LANGUAGE */ + 'U', 'T', "LANGUAGE", (anyptr) language, 40, + 'S', 'V', "MODULA2", (anyptr) &modula2, -1, + 'S', 'T', "INTEGER16", (anyptr) &integer16, -1, + 'S', 'T', "DOUBLEREALS", (anyptr) &doublereals, -1, + 'S', 'V', "UNSIGNEDCHAR", (anyptr) &unsignedchar, -1, + 'S', 'V', "NEEDSIGNEDBYTE", (anyptr) &needsignedbyte, 0, + 'S', 'V', "PASCALENUMSIZE", (anyptr) &pascalenumsize, -1, + 'S', 'V', "NESTEDCOMMENTS", (anyptr) &nestedcomments, -1, + 'S', 'V', "IMPORTALL", (anyptr) &importall, -1, + 'S', 'V', "IMPLMODULES", (anyptr) &implementationmodules, -1, + 'A', 'V', "EXTERNWORDS", (anyptr) &externwords, 0, + 'A', 'V', "CEXTERNWORDS", (anyptr) &cexternwords, 0, + 'S', 'V', "PASCALSIGNIF", (anyptr) &pascalsignif, -1, + 'S', 'V', "PASCALCASESENS", (anyptr) &pascalcasesens, -1, + 'S', 'V', "DOLLARIDENTS", (anyptr) &dollar_idents, -1, + 'S', 'V', "IGNORENONALPHA", (anyptr) &ignorenonalpha, -1, + 'I', 'V', "SEEKBASE", (anyptr) &seek_base, -1, + 'I', 'R', "INPUTTABSIZE", (anyptr) &intabsize, 8, + +/* TARGET LANGUAGE */ + 'S', 'T', "ANSIC", (anyptr) &ansiC, -1, + 'S', 'T', "C++", (anyptr) &cplus, -1, + 'S', 'T', "VOID*", (anyptr) &voidstar, -1, + 'S', 'T', "HASSIGNEDCHAR", (anyptr) &hassignedchar, -1, + 'S', 'V', "CASTNULL", (anyptr) &castnull, -1, + 'S', 'V', "COPYSTRUCTS", (anyptr) ©structs, -1, + 'S', 'V', "VARIABLEARRAYS", (anyptr) &variablearrays, -1, + 'S', 'V', "INITPACSTRINGS", (anyptr) &initpacstrings, -1, + 'S', 'V', "REUSEFIELDNAMES", (anyptr) &reusefieldnames, 1, + 'S', 'V', "USEVEXTERN", (anyptr) &usevextern, 1, + 'S', 'V', "CSIGNIF", (anyptr) &csignif, -1, + 'S', 'V', "USEANYPTRMACROS", (anyptr) &useAnyptrMacros, -1, + 'S', 'V', "USEPPMACROS", (anyptr) &usePPMacros, -1, + +/* TARGET MACHINE */ + 'U', 'T', "TARGET", (anyptr) target, 40, + 'S', 'T', "SIGNEDCHAR", (anyptr) &signedchars, -1, + 'S', 'T', "SIGNEDFIELD", (anyptr) &signedfield, -1, + 'S', 'T', "SIGNEDSHIFT", (anyptr) &signedshift, -1, + 'I', 'T', "CHARSIZE", (anyptr) &sizeof_char, 0, + 'I', 'T', "SHORTSIZE", (anyptr) &sizeof_short, 0, + 'I', 'T', "INTSIZE", (anyptr) &sizeof_int, 0, + 'I', 'T', "LONGSIZE", (anyptr) &sizeof_long, 0, + 'I', 'T', "PTRSIZE", (anyptr) &sizeof_pointer, 0, + 'I', 'T', "DOUBLESIZE", (anyptr) &sizeof_double, 0, + 'I', 'T', "FLOATSIZE", (anyptr) &sizeof_float, 0, + 'I', 'T', "ENUMSIZE", (anyptr) &sizeof_enum, 0, + 'S', 'T', "SIZE_T_LONG", (anyptr) &size_t_long, -1, + +/* BRACES */ + 'S', 'V', "NULLSTMTLINE", (anyptr) &nullstmtline, 0, + 'S', 'V', "BRACESALWAYS", (anyptr) &bracesalways, -1, + 'S', 'V', "BRACELINE", (anyptr) &braceline, -1, + 'S', 'V', "BRACECOMBINE", (anyptr) &bracecombine, 0, + 'S', 'V', "BRACEELSE", (anyptr) &braceelse, 0, + 'S', 'V', "BRACEELSELINE", (anyptr) &braceelseline, 0, + 'S', 'V', "ELSEIF", (anyptr) &elseif, -1, + 'S', 'V', "NEWLINEFUNCS", (anyptr) &newlinefunctions, 0, + +/* INDENTATION */ + 'I', 'R', "PHYSTABSIZE", (anyptr) &phystabsize, 8, + 'D', 'R', "INDENT", (anyptr) &tabsize, 2, + 'D', 'R', "BLOCKINDENT", (anyptr) &blockindent, 0, + 'D', 'R', "BODYINDENT", (anyptr) &bodyindent, 0, + 'D', 'R', "FUNCARGINDENT", (anyptr) &argindent, 1000, + 'D', 'R', "OPENBRACEINDENT", (anyptr) &openbraceindent, 0, + 'D', 'R', "CLOSEBRACEINDENT",(anyptr) &closebraceindent, 0, + 'D', 'R', "FUNCOPENINDENT", (anyptr) &funcopenindent, 0, + 'D', 'R', "FUNCCLOSEINDENT", (anyptr) &funccloseindent, 0, + 'D', 'R', "SWITCHINDENT", (anyptr) &switchindent, 0, + 'D', 'R', "CASEINDENT", (anyptr) &caseindent, -2, + 'D', 'R', "LABELINDENT", (anyptr) &labelindent, 1000, + 'D', 'R', "STRUCTINDENT", (anyptr) &structindent, 0, + 'D', 'R', "STRUCTINITINDENT",(anyptr) &structinitindent, 0, + 'D', 'R', "EXTRAINITINDENT", (anyptr) &extrainitindent, 2, + 'I', 'R', "EXTRAINDENT", (anyptr) &extraindent, 2, + 'I', 'R', "BUMPINDENT", (anyptr) &bumpindent, 1, + 'D', 'R', "CONSTINDENT", (anyptr) &constindent, 1024, + 'D', 'R', "COMMENTINDENT", (anyptr) &commentindent, 3, + 'D', 'R', "BRACECOMMENTINDENT",(anyptr)&bracecommentindent, 2, + 'D', 'R', "DECLCOMMENTINDENT",(anyptr)&declcommentindent, -999, + 'D', 'R', "COMMENTOVERINDENT",(anyptr)&commentoverindent, 4, /*1000*/ + 'I', 'R', "MINSPACING", (anyptr) &minspacing, 2, + 'I', 'R', "MINSPACINGTHRESH",(anyptr) &minspacingthresh, -1, + +/* LINE BREAKING */ + 'I', 'R', "LINEWIDTH", (anyptr) &linewidth, 78, + 'I', 'R', "MAXLINEWIDTH", (anyptr) &maxlinewidth, 90, + 'R', 'V', "OVERWIDEPENALTY", (anyptr) &overwidepenalty, 2500, + 'R', 'V', "OVERWIDEEXTRAPENALTY", (anyptr) &overwideextrapenalty, 100, + 'R', 'V', "COMMABREAKPENALTY", (anyptr) &commabreakpenalty, 1000, + 'R', 'V', "COMMABREAKEXTRAPENALTY",(anyptr) &commabreakextrapenalty, 500, + 'R', 'V', "ASSIGNBREAKPENALTY", (anyptr) &assignbreakpenalty, 5000, + 'R', 'V', "ASSIGNBREAKEXTRAPENALTY",(anyptr)&assignbreakextrapenalty, 3000, + 'R', 'V', "SPECIALARGBREAKPENALTY",(anyptr) &specialargbreakpenalty, 500, + 'R', 'V', "OPBREAKPENALTY", (anyptr) &opbreakpenalty, 2500, + 'R', 'V', "OPBREAKEXTRAPENALTY", (anyptr) &opbreakextrapenalty, 2000, + 'R', 'V', "LOGBREAKPENALTY", (anyptr) &logbreakpenalty, 500, + 'R', 'V', "LOGBREAKEXTRAPENALTY", (anyptr) &logbreakextrapenalty, 100, + 'R', 'V', "RELBREAKPENALTY", (anyptr) &relbreakpenalty, 2000, + 'R', 'V', "RELBREAKEXTRAPENALTY", (anyptr) &relbreakextrapenalty, 1000, + 'R', 'V', "EXHYPHENPENALTY", (anyptr) &exhyphenpenalty, 1000, + 'R', 'V', "MOREBREAKPENALTY", (anyptr) &morebreakpenalty, -500, + 'R', 'V', "MOREBREAKEXTRAPENALTY", (anyptr) &morebreakextrapenalty, -300, + 'R', 'V', "QMARKBREAKPENALTY", (anyptr) &qmarkbreakpenalty, 5000, + 'R', 'V', "QMARKBREAKEXTRAPENALTY",(anyptr) &qmarkbreakextrapenalty, 3000, + 'R', 'V', "PARENBREAKPENALTY", (anyptr) &parenbreakpenalty, 2500, + 'R', 'V', "PARENBREAKEXTRAPENALTY",(anyptr) &parenbreakextrapenalty, 1000, + 'R', 'V', "WRONGSIDEPENALTY", (anyptr) &wrongsidepenalty, 1000, + 'R', 'V', "EARLYBREAKPENALTY", (anyptr) &earlybreakpenalty, 100, + 'R', 'V', "EXTRAINDENTPENALTY", (anyptr) &extraindentpenalty, 3000, + 'R', 'V', "BUMPINDENTPENALTY", (anyptr) &bumpindentpenalty, 1000, + 'R', 'V', "NOBUMPINDENTPENALTY", (anyptr) &nobumpindentpenalty, 2500, + 'R', 'V', "INDENTAMOUNTPENALTY", (anyptr) &indentamountpenalty, 50, + 'R', 'V', "SAMEINDENTPENALTY", (anyptr) &sameindentpenalty, 500, + 'R', 'V', "SHOWBADLIMIT", (anyptr) &showbadlimit, -120, + 'L', 'R', "MAXLINEBREAKTRIES", (anyptr) &maxalts, 5000, + 'G', 'V', "ALLORNONEBREAK", (anyptr) NULL, FALLBREAK, + 'G', 'V', "ONESPECIALARG", (anyptr) NULL, FSPCARG1, + 'G', 'V', "TWOSPECIALARGS", (anyptr) NULL, FSPCARG2, + 'G', 'V', "THREESPECIALARGS",(anyptr) NULL, FSPCARG3, + 'B', 'V', "BREAKARITH", (anyptr) &breakbeforearith, BRK_RIGHT, + 'B', 'V', "BREAKREL", (anyptr) &breakbeforerel, BRK_RIGHT, + 'B', 'V', "BREAKLOG", (anyptr) &breakbeforelog, BRK_RIGHT, + 'B', 'V', "BREAKDOT", (anyptr) &breakbeforedot, BRK_RIGHT, + 'B', 'V', "BREAKASSIGN", (anyptr) &breakbeforeassign, BRK_RIGHT, + 'S', 'V', "FOR_ALLORNONE", (anyptr) &for_allornone, 1, + +/* COMMENTS AND BLANK LINES */ + 'S', 'V', "NOBANNER", (anyptr) &nobanner, 0, + 'S', 'V', "EATCOMMENTS", (anyptr) &eatcomments, 0, + 'S', 'V', "SPITCOMMENTS", (anyptr) &spitcomments, 0, + 'S', 'V', "SPITORPHANCOMMENTS",(anyptr)&spitorphancomments, 0, + 'S', 'V', "COMMENTAFTER", (anyptr) &commentafter, -1, + 'S', 'V', "BLANKAFTER", (anyptr) &blankafter, 1, + 'A', 'V', "EATNOTES", (anyptr) &eatnotes, 0, + +/* SPECIAL COMMENTS */ + 'C', 'V', "FIXEDCOMMENT", (anyptr) fixedcomment, 40, + 'C', 'V', "PERMANENTCOMMENT",(anyptr) permanentcomment, 40, + 'C', 'V', "INTERFACECOMMENT",(anyptr) interfacecomment, 40, + 'C', 'V', "EMBEDCOMMENT", (anyptr) embedcomment, 40, + 'C', 'V', "SKIPCOMMENT", (anyptr) skipcomment, 40, + 'C', 'V', "NOSKIPCOMMENT", (anyptr) noskipcomment, 40, + 'C', 'V', "SIGNEDCOMMENT", (anyptr) signedcomment, 40, + 'C', 'V', "UNSIGNEDCOMMENT", (anyptr) unsignedcomment, 40, + +/* STYLISTIC OPTIONS */ + 'I', 'V', "MAJORSPACING", (anyptr) &majorspace, 2, + 'I', 'V', "MINORSPACING", (anyptr) &minorspace, 1, + 'I', 'V', "FUNCSPACING", (anyptr) &functionspace, 2, + 'I', 'V', "MINFUNCSPACING", (anyptr) &minfuncspace, 1, + 'S', 'V', "EXTRAPARENS", (anyptr) &extraparens, -1, + 'S', 'V', "BREAKADDPARENS", (anyptr) &breakparens, -1, + 'S', 'V', "RETURNPARENS", (anyptr) &returnparens, -1, + 'S', 'V', "SPACEEXPRS", (anyptr) &spaceexprs, -1, + 'S', 'V', "SPACEFUNCS", (anyptr) &spacefuncs, 0, + 'S', 'V', "SPACECOMMAS", (anyptr) &spacecommas, 1, + 'S', 'V', "IMPLICITZERO", (anyptr) &implicitzero, -1, + 'S', 'V', "STARINDEX", (anyptr) &starindex, -1, + 'S', 'V', "ADDINDEX", (anyptr) &addindex, -1, + 'S', 'V', "STARARRAYS", (anyptr) &stararrays, 1, + 'S', 'V', "STARFUNCTIONS", (anyptr) &starfunctions, -1, + 'S', 'V', "POSTINCREMENT", (anyptr) &postincrement, 1, + 'S', 'V', "MIXVARS", (anyptr) &mixvars, -1, + 'S', 'V', "MIXTYPES", (anyptr) &mixtypes, -1, + 'S', 'V', "MIXFIELDS", (anyptr) &mixfields, -1, + 'S', 'V', "MIXINITS", (anyptr) &mixinits, -1, + 'S', 'V', "MAINLOCALS", (anyptr) &mainlocals, 1, + 'S', 'V', "NULLCHAR", (anyptr) &nullcharconst, 1, + 'S', 'V', "HIGHCHARINT", (anyptr) &highcharints, 1, + 'I', 'V', "CASESPACING", (anyptr) &casespacing, 1, + 'D', 'V', "CASETABS", (anyptr) &casetabs, 1000, + 'I', 'V', "CASELIMIT", (anyptr) &caselimit, 9, + 'S', 'V', "USECOMMAS", (anyptr) &usecommas, -1, + 'S', 'V', "USERETURNS", (anyptr) &usereturns, 1, + 'I', 'V', "RETURNLIMIT", (anyptr) &returnlimit, 3, + 'S', 'V', "USEBREAKS", (anyptr) &usebreaks, 1, + 'I', 'V', "BREAKLIMIT", (anyptr) &breaklimit, 2, + 'I', 'V', "CONTINUELIMIT", (anyptr) &continuelimit, 5, + 'S', 'V', "INFLOOPSTYLE", (anyptr) &infloopstyle, 0, + +/* NAMING CONVENTIONS */ + 'C', 'V', "CODEFILENAME", (anyptr) codefnfmt, 40, + 'C', 'V', "MODULEFILENAME", (anyptr) modulefnfmt, 40, + 'C', 'V', "HEADERFILENAME", (anyptr) headerfnfmt, 40, + 'C', 'V', "HEADERFILENAME2", (anyptr) headerfnfmt2, 40, + 'C', 'V', "SELFINCLUDENAME", (anyptr) selfincludefmt, 40, + 'C', 'V', "LOGFILENAME", (anyptr) logfnfmt, 40, + 'C', 'V', "INCLUDEFILENAME", (anyptr) includefnfmt, 40, + 'S', 'V', "SYMCASE", (anyptr) &symcase, -1, + 'C', 'V', "SYMBOLFORMAT", (anyptr) symbolformat, 40, + 'C', 'V', "CONSTFORMAT", (anyptr) constformat, 40, + 'C', 'V', "MODULEFORMAT", (anyptr) moduleformat, 40, + 'C', 'V', "FUNCTIONFORMAT", (anyptr) functionformat, 40, + 'C', 'V', "VARFORMAT", (anyptr) varformat, 40, + 'C', 'V', "FIELDFORMAT", (anyptr) fieldformat, 40, + 'C', 'V', "TYPEFORMAT", (anyptr) typeformat, 40, + 'C', 'V', "ENUMFORMAT", (anyptr) enumformat, 40, + 'C', 'V', "RETURNVALUENAME", (anyptr) name_RETV, 40, + 'C', 'V', "UNITINITNAME", (anyptr) name_UNITINIT, 40, + 'C', 'V', "HSYMBOLNAME", (anyptr) name_HSYMBOL, 40, + 'C', 'V', "GSYMBOLNAME", (anyptr) name_GSYMBOL, 40, + 'C', 'V', "STRINGMAXNAME", (anyptr) name_STRMAX, 40, + 'C', 'V', "ARRAYMINNAME", (anyptr) name_ALOW, 40, + 'C', 'V', "ARRAYMAXNAME", (anyptr) name_AHIGH, 40, + 'C', 'V', "COPYPARNAME", (anyptr) name_COPYPAR, 40, + 'C', 'V', "STATICLINKNAME", (anyptr) name_LINK, 40, + 'C', 'V', "LOCALVARSSTRUCT", (anyptr) name_LOC, 40, + 'C', 'V', "LOCALVARSNAME", (anyptr) name_VARS, 40, + 'C', 'V', "FWDSTRUCTNAME", (anyptr) name_STRUCT, 40, + 'C', 'V', "ENUMLISTNAME", (anyptr) name_ENUM, 40, + 'C', 'V', "UNIONNAME", (anyptr) name_UNION, 40, + 'C', 'V', "UNIONPARTNAME", (anyptr) name_VARIANT, 40, + 'C', 'V', "FAKESTRUCTNAME", (anyptr) name_FAKESTRUCT, 40, + 'C', 'V', "LABELNAME", (anyptr) name_LABEL, 40, + 'C', 'V', "LABELVARNAME", (anyptr) name_LABVAR, 40, + 'C', 'V', "TEMPNAME", (anyptr) name_TEMP, 40, + 'C', 'V', "DUMMYNAME", (anyptr) name_DUMMY, 40, + 'C', 'V', "FORNAME", (anyptr) name_FOR, 40, + 'C', 'V', "WITHNAME", (anyptr) name_WITH, 40, + 'C', 'V', "PTRNAME", (anyptr) name_PTR, 40, + 'C', 'V', "STRINGNAME", (anyptr) name_STRING, 40, + 'C', 'V', "SETNAME", (anyptr) name_SET, 40, + 'C', 'V', "FNVARNAME", (anyptr) name_FNVAR, 40, + 'C', 'V', "FNSIZENAME", (anyptr) name_FNSIZE, 40, + 'C', 'V', "ALTERNATENAME1", (anyptr) alternatename1, 40, + 'C', 'V', "ALTERNATENAME2", (anyptr) alternatename2, 40, + 'C', 'V', "ALTERNATENAME", (anyptr) alternatename, 40, + 'C', 'V', "EXPORTSYMBOL", (anyptr) exportsymbol, 40, + 'C', 'V', "EXPORT_SYMBOL", (anyptr) export_symbol, 40, + 'C', 'V', "ALIAS", (anyptr) externalias, 40, + 'X', 'V', "SYNONYM", (anyptr) NULL, 3, + 'X', 'V', "NAMEOF", (anyptr) &nameoflist, 1, + 'G', 'V', "AVOIDNAME", (anyptr) NULL, AVOIDNAME, + 'G', 'V', "AVOIDGLOBALNAME", (anyptr) NULL, AVOIDGLOB, + 'G', 'V', "WARNNAME", (anyptr) NULL, WARNNAME, + 'G', 'V', "NOSIDEEFFECTS", (anyptr) NULL, NOSIDEEFF, + 'G', 'V', "STRUCTFUNCTION", (anyptr) NULL, STRUCTF, + 'G', 'V', "STRLAPFUNCTION", (anyptr) NULL, STRLAPF, + 'F', 'V', "LEAVEALONE", (anyptr) NULL, LEAVEALONE, + 'G', 'V', "DETERMINISTIC", (anyptr) NULL, DETERMF, + 'G', 'V', "NEEDSTATIC", (anyptr) NULL, NEEDSTATIC, + 'S', 'V', "WARNNAMES", (anyptr) &warnnames, 0, + 'M', 'V', "VARMACRO", (anyptr) NULL, MAC_VAR, + 'M', 'V', "CONSTMACRO", (anyptr) NULL, MAC_CONST, + 'M', 'V', "FIELDMACRO", (anyptr) NULL, MAC_FIELD, + 'M', 'V', "FUNCMACRO", (anyptr) NULL, MAC_FUNC, + 'S', 'V', "WARNMACROS", (anyptr) &warnmacros, 0, + +/* CODING OPTIONS */ + 'A', 'V', "INITIALCALLS", (anyptr) &initialcalls, 0, + 'S', 'V', "EXPANDINCLUDES", (anyptr) &expandincludes, -1, + 'S', 'V', "COLLECTNEST", (anyptr) &collectnest, 1, + 'S', 'V', "SHORTCIRCUIT", (anyptr) &shortcircuit, -1, + 'S', 'V', "SHORTOPT", (anyptr) &shortopt, 1, + 'S', 'V', "ELIMDEADCODE", (anyptr) &elimdeadcode, 1, + 'S', 'V', "FOLDCONSTANTS", (anyptr) &foldconsts, -1, + 'S', 'V', "FOLDSTRCONSTANTS",(anyptr) &foldstrconsts, -1, + 'S', 'V', "CHARCONSTS", (anyptr) &charconsts, 1, + 'S', 'V', "USECONSTS", (anyptr) &useconsts, -1, + 'S', 'V', "USEUNDEF", (anyptr) &useundef, 1, + 'L', 'V', "SKIPINDICES", (anyptr) &skipindices, 0, + 'S', 'V', "OFFSETFORLOOPS", (anyptr) &offsetforloops, 1, + 'S', 'V', "FOREVALORDER", (anyptr) &forevalorder, 0, + 'S', 'V', "STRINGLEADERS", (anyptr) &stringleaders, 2, + 'S', 'V', "STOREFILENAMES", (anyptr) &storefilenames, -1, + 'S', 'V', "CHARFILETEXT", (anyptr) &charfiletext, -1, + 'S', 'V', "SQUEEZESUBR", (anyptr) &squeezesubr, 1, + 'S', 'T', "USEENUM", (anyptr) &useenum, -1, + 'S', 'V', "SQUEEZEENUM", (anyptr) &enumbyte, -1, + 'S', 'V', "COMPENUMS", (anyptr) &compenums, -1, + 'S', 'V', "PRESERVETYPES", (anyptr) &preservetypes, 1, + 'S', 'V', "PRESERVEPOINTERS",(anyptr) &preservepointers, 0, + 'S', 'V', "PRESERVESTRINGS", (anyptr) &preservestrings, -1, + 'S', 'V', "PACKING", (anyptr) &packing, 1, + 'S', 'V', "PACKSIGNED", (anyptr) &packsigned, 1, + 'I', 'V', "STRINGCEILING", (anyptr) &stringceiling, 255, + 'I', 'V', "STRINGDEFAULT", (anyptr) &stringdefault, 255, + 'I', 'V', "STRINGTRUNCLIMIT",(anyptr) &stringtrunclimit, -1, + 'I', 'V', "LONGSTRINGSIZE", (anyptr) &longstringsize, -1, + 'S', 'V', "KEEPNULLS", (anyptr) &keepnulls, 0, + 'S', 'V', "HIGHCHARBITS", (anyptr) &highcharbits, -1, + 'S', 'V', "ALWAYSCOPYVALUES",(anyptr) &alwayscopyvalues, 0, + 'S', 'V', "STATICFUNCTIONS", (anyptr) &use_static, 1, + 'S', 'V', "STATICVARIABLES", (anyptr) &var_static, 1, + 'S', 'V', "VOIDARGS", (anyptr) &void_args, -1, + 'S', 'V', "PROTOTYPES", (anyptr) &prototypes, -1, + 'S', 'V', "FULLPROTOTYPING", (anyptr) &fullprototyping, -1, + 'S', 'V', "PROCPTRPROTOTYPES",(anyptr)&procptrprototypes, 1, + 'S', 'V', "CASTARGS", (anyptr) &castargs, -1, + 'S', 'V', "CASTLONGARGS", (anyptr) &castlongargs, -1, + 'S', 'V', "PROMOTEARGS", (anyptr) &promoteargs, -1, + 'S', 'V', "FIXPROMOTEDARGS", (anyptr) &fixpromotedargs, 1, + 'S', 'V', "PROMOTEENUMS", (anyptr) &promote_enums, -1, + 'S', 'V', "STATICLINKS", (anyptr) &hasstaticlinks, -1, + 'S', 'V', "VARSTRINGS", (anyptr) &varstrings, 0, + 'S', 'V', "VARFILES", (anyptr) &varfiles, 1, + 'S', 'V', "ADDRSTDFILES", (anyptr) &addrstdfiles, 0, + 'S', 'V', "COPYSTRUCTFUNCS", (anyptr) ©structfuncs, -1, + 'S', 'V', "ATAN2", (anyptr) &atan2flag, 0, + 'S', 'V', "BITWISEMOD", (anyptr) &mod_po2, -1, + 'S', 'V', "BITWISEDIV", (anyptr) &div_po2, -1, + 'S', 'V', "ASSUMEBITS", (anyptr) &assumebits, 0, + 'S', 'V', "ASSUMESIGNS", (anyptr) &assumesigns, 1, + 'S', 'V', "ALLOCZERONIL", (anyptr) &alloczeronil, 0, + 'S', 'V', "PRINTFONLY", (anyptr) &printfonly, -1, + 'S', 'V', "MIXWRITELNS", (anyptr) &mixwritelns, 1, + 'S', 'V', "MESSAGESTDERR", (anyptr) &messagestderr, 1, + 'I', 'V', "INTEGERWIDTH", (anyptr) &integerwidth, -1, + 'I', 'V', "REALWIDTH", (anyptr) &realwidth, 12, + 'S', 'V', "FORMATSTRINGS", (anyptr) &formatstrings, 0, + 'S', 'V', "WHILEFGETS", (anyptr) &whilefgets, 1, + 'S', 'V', "USEGETS", (anyptr) &usegets, 1, + 'S', 'V', "NEWLINESPACE", (anyptr) &newlinespace, -1, + 'S', 'V', "BUILDREADS", (anyptr) &buildreads, 1, + 'S', 'V', "BUILDWRITES", (anyptr) &buildwrites, 1, + 'S', 'V', "BINARYMODE", (anyptr) &binarymode, 1, + 'S', 'V', "READWRITEOPEN", (anyptr) &readwriteopen, -1, + 'C', 'V', "OPENMODE", (anyptr) openmode, 40, + 'S', 'V', "LITERALFILES", (anyptr) &literalfilesflag, -1, + 'A', 'V', "LITERALFILE", (anyptr) &literalfiles, 0, + 'S', 'V', "STRUCTFILES", (anyptr) &structfilesflag, 0, + 'A', 'V', "STRUCTFILE", (anyptr) &structfiles, 0, + 'C', 'V', "FILENAMEFILTER", (anyptr) filenamefilter, 40, + 'S', 'V', "FULLSTRWRITE", (anyptr) &fullstrwrite, -1, + 'S', 'V', "FULLSTRREAD", (anyptr) &fullstrread, 1, + 'I', 'R', "SETBITS", (anyptr) &setbits, -1, + 'I', 'V', "DEFAULTSETSIZE", (anyptr) &defaultsetsize, -1, + 'S', 'V', "SMALLSETCONST", (anyptr) &smallsetconst, -2, + 'S', 'V', "BIGSETCONST", (anyptr) &bigsetconst, 1, + 'S', 'V', "LELERANGE", (anyptr) &lelerange, 0, + 'S', 'V', "UNSIGNEDTRICK", (anyptr) &unsignedtrick, 1, + 'S', 'V', "USEISALPHA", (anyptr) &useisalpha, 1, + 'S', 'V', "USEISSPACE", (anyptr) &useisspace, 0, + 'S', 'V', "USESTRNCMP", (anyptr) &usestrncmp, 1, + +/* TARGET LIBRARY */ + 'G', 'V', "WARNLIBRARY", (anyptr) NULL, WARNLIBR, + 'S', 'V', "QUOTEINCLUDES", (anyptr) "eincludes, 1, + 'X', 'V', "IMPORTFROM", (anyptr) &importfrom, 1, + 'A', 'V', "IMPORTDIR", (anyptr) &importdirs, 0, + 'A', 'V', "INCLUDEDIR", (anyptr) &includedirs, 0, + 'X', 'V', "INCLUDEFROM", (anyptr) &includefrom, 1, + 'A', 'V', "LIBRARYFILE", (anyptr) &librfiles, 0, + 'C', 'V', "HEADERNAME", (anyptr) p2c_h_name, 40, + 'C', 'V', "PROCTYPENAME", (anyptr) name_PROCEDURE, 40, + 'C', 'V', "UCHARNAME", (anyptr) name_UCHAR, 40, + 'C', 'V', "SCHARNAME", (anyptr) name_SCHAR, 40, + 'C', 'V', "BOOLEANNAME", (anyptr) name_BOOLEAN, 40, + 'C', 'V', "TRUENAME", (anyptr) name_TRUE, 40, + 'C', 'V', "FALSENAME", (anyptr) name_FALSE, 40, + 'C', 'V', "NULLNAME", (anyptr) name_NULL, 40, + 'C', 'V', "ESCAPECODENAME", (anyptr) name_ESCAPECODE, 40, + 'C', 'V', "IORESULTNAME", (anyptr) name_IORESULT, 40, + 'C', 'V', "ARGCNAME", (anyptr) name_ARGC, 40, + 'C', 'V', "ARGVNAME", (anyptr) name_ARGV, 40, + 'C', 'V', "MAINNAME", (anyptr) name_MAIN, 40, + 'C', 'V', "ESCAPENAME", (anyptr) name_ESCAPE, 40, + 'C', 'V', "ESCIONAME", (anyptr) name_ESCIO, 40, + 'C', 'V', "CHECKIONAME", (anyptr) name_CHKIO, 40, + 'C', 'V', "SETIONAME", (anyptr) name_SETIO, 40, + 'C', 'V', "FILENOTFOUNDNAME",(anyptr) filenotfoundname, 40, + 'C', 'V', "FILENOTOPENNAME", (anyptr) filenotopenname, 40, + 'C', 'V', "FILEWRITEERRORNAME",(anyptr)filewriteerrorname,40, + 'C', 'V', "BADINPUTFORMATNAME",(anyptr)badinputformatname,40, + 'C', 'V', "ENDOFFILENAME", (anyptr) endoffilename, 40, + 'C', 'V', "OUTMEMNAME", (anyptr) name_OUTMEM, 40, + 'C', 'V', "CASECHECKNAME", (anyptr) name_CASECHECK, 40, + 'C', 'V', "NILCHECKNAME", (anyptr) name_NILCHECK, 40, + 'C', 'V', "SETBITSNAME", (anyptr) name_SETBITS, 40, + 'S', 'V', "SPRINTFVALUE", (anyptr) &sprintf_value, -1, + 'C', 'V', "SPRINTFNAME", (anyptr) sprintfname, 40, + 'C', 'V', "MEMCPYNAME", (anyptr) memcpyname, 40, + 'C', 'V', "ROUNDNAME", (anyptr) roundname, 40, + 'C', 'V', "DIVNAME", (anyptr) divname, 40, + 'C', 'V', "MODNAME", (anyptr) modname, 40, + 'C', 'V', "REMNAME", (anyptr) remname, 40, + 'C', 'V', "STRCICMPNAME", (anyptr) strcicmpname, 40, + 'C', 'V', "STRSUBNAME", (anyptr) strsubname, 40, + 'C', 'V', "STRPOSNAME", (anyptr) strposname, 40, + 'S', 'V', "STRCPYLEFT", (anyptr) &strcpyleft, 1, + 'C', 'V', "STRDELETENAME", (anyptr) strdeletename, 40, + 'C', 'V', "STRINSERTNAME", (anyptr) strinsertname, 40, + 'C', 'V', "STRMOVENAME", (anyptr) strmovename, 40, + 'C', 'V', "STRLTRIMNAME", (anyptr) strltrimname, 40, + 'C', 'V', "STRRTRIMNAME", (anyptr) strrtrimname, 40, + 'C', 'V', "STRRPTNAME", (anyptr) strrptname, 40, + 'C', 'V', "STRPADNAME", (anyptr) strpadname, 40, + 'C', 'V', "ABSNAME", (anyptr) absname, 40, + 'C', 'V', "ODDNAME", (anyptr) oddname, 40, + 'C', 'V', "EVENNAME", (anyptr) evenname, 40, + 'C', 'V', "SWAPNAME", (anyptr) swapname, 40, + 'C', 'V', "MALLOCNAME", (anyptr) mallocname, 40, + 'C', 'V', "FREENAME", (anyptr) freename, 40, + 'C', 'V', "FREERVALUENAME", (anyptr) freervaluename, 40, + 'X', 'V', "SPECIALMALLOC", (anyptr) &specialmallocs, 1, + 'X', 'V', "SPECIALFREE", (anyptr) &specialfrees, 1, + 'X', 'V', "SPECIALSIZEOF", (anyptr) &specialsizeofs, 1, + 'C', 'V', "RANDREALNAME", (anyptr) randrealname, 40, + 'C', 'V', "RANDINTNAME", (anyptr) randintname, 40, + 'C', 'V', "RANDOMIZENAME", (anyptr) randomizename, 40, + 'C', 'V', "SKIPSPACENAME", (anyptr) skipspacename, 40, + 'C', 'V', "READLNNAME", (anyptr) readlnname, 40, + 'C', 'V', "FREOPENNAME", (anyptr) freopenname, 40, + 'C', 'V', "EOFNAME", (anyptr) eofname, 40, + 'C', 'V', "EOLNNAME", (anyptr) eolnname, 40, + 'C', 'V', "FILEPOSNAME", (anyptr) fileposname, 40, + 'C', 'V', "MAXPOSNAME", (anyptr) maxposname, 40, + 'C', 'V', "SETUNIONNAME", (anyptr) setunionname, 40, + 'C', 'V', "SETINTNAME", (anyptr) setintname, 40, + 'C', 'V', "SETDIFFNAME", (anyptr) setdiffname, 40, + 'C', 'V', "SETXORNAME", (anyptr) setxorname, 40, + 'C', 'V', "SETINNAME", (anyptr) setinname, 40, + 'C', 'V', "SETADDNAME", (anyptr) setaddname, 40, + 'C', 'V', "SETADDRANGENAME", (anyptr) setaddrangename, 40, + 'C', 'V', "SETREMNAME", (anyptr) setremname, 40, + 'C', 'V', "SETEQUALNAME", (anyptr) setequalname, 40, + 'C', 'V', "SUBSETNAME", (anyptr) subsetname, 40, + 'C', 'V', "SETCOPYNAME", (anyptr) setcopyname, 40, + 'C', 'V', "SETEXPANDNAME", (anyptr) setexpandname, 40, + 'C', 'V', "SETPACKNAME", (anyptr) setpackname, 40, + 'C', 'V', "SIGNEXTENDNAME", (anyptr) signextname, 40, + 'C', 'V', "GETBITSNAME", (anyptr) getbitsname, 40, + 'C', 'V', "CLRBITSNAME", (anyptr) clrbitsname, 40, + 'C', 'V', "PUTBITSNAME", (anyptr) putbitsname, 40, + 'C', 'V', "STOREBITSNAME", (anyptr) storebitsname, 40, + 'C', 'V', "DECLBUFNAME", (anyptr) declbufname, 40, + 'C', 'V', "DECLBUFNCNAME", (anyptr) declbufncname, 40, + 'A', 'V', "BUFFEREDFILE", (anyptr) &bufferedfiles, 0, + 'A', 'V', "UNBUFFEREDFILE", (anyptr) &unbufferedfiles, 0, + 'C', 'V', "RESETBUFNAME", (anyptr) resetbufname, 40, + 'C', 'V', "SETUPBUFNAME", (anyptr) setupbufname, 40, + 'C', 'V', "GETFBUFNAME", (anyptr) getfbufname, 40, + 'C', 'V', "CHARGETFBUFNAME", (anyptr) chargetfbufname, 40, + 'C', 'V', "ARRAYGETFBUFNAME",(anyptr) arraygetfbufname, 40, + 'C', 'V', "PUTFBUFNAME", (anyptr) putfbufname, 40, + 'C', 'V', "CHARPUTFBUFNAME", (anyptr) charputfbufname, 40, + 'C', 'V', "ARRAYPUTFBUFNAME",(anyptr) arrayputfbufname, 40, + 'C', 'V', "GETNAME", (anyptr) getname, 40, + 'C', 'V', "CHARGETNAME", (anyptr) chargetname, 40, + 'C', 'V', "ARRAYGETNAME", (anyptr) arraygetname, 40, + 'C', 'V', "PUTNAME", (anyptr) putname, 40, + 'C', 'V', "CHARPUTNAME", (anyptr) charputname, 40, + 'C', 'V', "ARRAYPUTNAME", (anyptr) arrayputname, 40, + 'C', 'V', "EOFBUFNAME", (anyptr) eofbufname, 40, + 'C', 'V', "FILEPOSBUFNAME", (anyptr) fileposbufname, 40, + +/* RANGE CHECKING */ + 'S', 'V', "CASECHECK", (anyptr) &casecheck, 0, + 'S', 'V', "ARRAYCHECK", (anyptr) &arraycheck, 0, + 'S', 'V', "RANGECHECK", (anyptr) &rangecheck, 0, + 'S', 'V', "NILCHECK", (anyptr) &nilcheck, 0, + 'S', 'V', "MALLOCCHECK", (anyptr) &malloccheck, 0, + 'S', 'V', "CHECKFILEOPEN", (anyptr) &checkfileopen, 1, + 'S', 'V', "CHECKFILEISOPEN", (anyptr) &checkfileisopen, 0, + 'S', 'V', "CHECKFILEWRITE", (anyptr) &checkfilewrite, 2, + 'S', 'V', "CHECKREADFORMAT", (anyptr) &checkreadformat, 2, + 'S', 'V', "CHECKFILEEOF", (anyptr) &checkfileeof, 2, + 'S', 'V', "CHECKSTDINEOF", (anyptr) &checkstdineof, 2, + 'S', 'V', "CHECKFILESEEK", (anyptr) &checkfileseek, 2, +} +#endif /* define_parameters */ + ; + + +#undef extern + + +#ifdef define_parameters + int numparams = sizeof(rctable) / sizeof(struct rcstruct); + Strlist *rcprevvalues[sizeof(rctable) / sizeof(struct rcstruct)]; +#else + extern int numparams; + extern Strlist *rcprevvalues[]; +#endif /* define_parameters */ + + + +/* Global variables: */ + +#ifdef define_globals +# define extern +#endif /* define_globals */ + + +extern char *charname, *ucharname, *scharname, *integername; +extern long min_schar, max_schar, max_uchar; +extern long min_sshort, max_sshort, max_ushort; + +extern char *alloctemp; +extern short error_crash; +extern int total_bytes, total_exprs, total_meanings, total_strings; +extern int total_symbols, total_types, total_stmts, total_strlists; +extern int total_literals, total_ctxstacks, total_tempvars, total_inprecs; +extern int total_parens, total_ptrdescs, total_misc; +extern int final_bytes, final_exprs, final_meanings, final_strings; +extern int final_symbols, final_types, final_stmts, final_strlists; +extern int final_literals, final_ctxstacks, final_tempvars, final_inprecs; +extern int final_parens, final_ptrdescs, final_misc; + +extern char *infname, *outfname, *codefname, *hdrfname; +extern char *requested_module; +extern FILE *inf, *outf, *codef, *hdrf, *logf; +extern short setup_complete, found_module; +extern short regression, verbose, conserve_mem; +extern int inf_lnum, inf_ltotal; + +extern int outindent, outputmode; +extern int outf_lnum; +extern short dontbreaklines; + +extern Token curtok; +extern char curtokbuf[256], curtokcase[256]; +extern char *inbufptr; +extern int inbufindent; +extern long curtokint; +extern Symbol *curtoksym; +extern Meaning *curtokmeaning; +extern Strlist *curcomments; +extern Strlist **keepingstrlist; +extern short ignore_directives, skipping_module; +extern short C_lex; +extern char sysprog_flag, partial_eval_flag, iocheck_flag; +extern char range_flag, ovflcheck_flag, stackcheck_flag; +extern short switch_strpos; +extern int fixedflag; +extern int numimports; +extern Strlist *tempoptionlist; +extern long curserial, serialcount; +extern int notephase; +extern Strlist *permimports; +extern int permflag; + +#define SYMHASHSIZE 293 +extern Symbol *(symtab[SYMHASHSIZE]); +extern short partialdump; + +#define MAXWITHS 100 +extern int withlevel; +extern Type *withlist[MAXWITHS]; +extern Expr *withexprs[MAXWITHS]; + +extern Token blockkind; +extern Meaning *curctx, *curctxlast, *nullctx; + +extern int fixexpr_tryblock; +extern short fixexpr_tryflag; + +extern Type *tp_integer, *tp_char, *tp_boolean, *tp_real, *tp_longreal; +extern Type *tp_anyptr, *tp_jmp_buf, *tp_schar, *tp_uchar, *tp_charptr; +extern Type *tp_int, *tp_sshort, *tp_ushort, *tp_abyte, *tp_sbyte, *tp_ubyte; +extern Type *tp_void, *tp_str255, *tp_strptr, *tp_text, *tp_bigtext; +extern Type *tp_unsigned, *tp_uint, *tp_sint, *tp_smallset, *tp_proc; +extern Meaning *mp_string, *mp_true, *mp_false; +extern Meaning *mp_input, *mp_output, *mp_stderr; +extern Meaning *mp_maxint, *mp_minint, *mp_escapecode, *mp_ioresult; +extern Meaning *mp_uchar, *mp_schar, *mp_unsigned, *mp_uint; +extern Meaning *mp_str_hp, *mp_str_turbo; +extern Meaning *mp_val_modula, *mp_val_turbo; +extern Meaning *mp_blockread_ucsd, *mp_blockread_turbo; +extern Meaning *mp_blockwrite_ucsd, *mp_blockwrite_turbo; +extern Meaning *mp_dec_dec, *mp_dec_turbo; +extern Expr *ex_input, *ex_output; +extern Strlist *attrlist; + + +#ifndef define_globals +# undef extern +#endif + + + + +/* Function declarations are created automatically by "makeproto" */ + +#include "p2c.hdrs" + +#include "p2c.proto" + + + +/* Our library omits declarations for these functions! */ + +int link PP( (char *, char *) ); +int unlink PP( (char *) ); + + + +#define minspcthresh ((minspacingthresh >= 0) ? minspacingthresh : minspacing) + +#define delfreearg(ex, n) freeexpr((*(ex))->args[n]), deletearg(ex, n) +#define delsimpfreearg(ex, n) freeexpr((*(ex))->args[n]), delsimparg(ex, n) + +#define swapexprs(a,b) do {register Expr *t=(a);(a)=(b);(b)=(t);} while (0) +#define swapstmts(a,b) do {register Stmt *t=(a);(a)=(b);(b)=(t);} while (0) + +#define CHECKORDEXPR(ex,v) ((ex)->kind==EK_CONST ? (ex)->val.i - (v) : -2) + +#define FCheck(flag) ((flag) == 1 || (!iocheck_flag && (flag))) +#define checkeof(fex) (isvar(fex, mp_input) ? FCheck(checkstdineof) \ + : FCheck(checkfileeof)) + + +#ifdef TEST_MALLOC /* Memory testing */ + +#define ALLOC(N,TYPE,NAME) \ + (TYPE *) test_malloc((unsigned)((N)*sizeof(TYPE)), \ + &__CAT__(total_,NAME), &__CAT__(final_,NAME)) + +#define ALLOCV(N,TYPE,NAME) \ + (TYPE *) test_malloc((unsigned)(N), \ + &__CAT__(total_,NAME), &__CAT__(final_,NAME)) + +#define REALLOC(P,N,TYPE) \ + (TYPE *) test_realloc((char *)(P), (unsigned)((N)*sizeof(TYPE))) + +#define FREE(P) test_free((char*)(P)) + +#else /* not TEST_MALLOC */ + +/* If p2c always halts immediately with an out-of-memory error, try + recompiling all modules with BROKEN_OR defined. */ +#ifdef BROKEN_OR + +#define ALLOC(N,TYPE,NAME) \ + ((alloctemp = malloc((unsigned)((N)*sizeof(TYPE)))), \ + (alloctemp ? (TYPE *) alloctemp : (TYPE *) outmem())) + +#define ALLOCV(N,TYPE,NAME) \ + ((alloctemp = malloc((unsigned)(N))), \ + (alloctemp ? (TYPE *) alloctemp : (TYPE *) outmem())) + +#define REALLOC(P,N,TYPE) \ + ((alloctemp = realloc((char*)(P), (unsigned)((N)*sizeof(TYPE)))), \ + (alloctemp ? (TYPE *) alloctemp : (TYPE *) outmem())) + +#define FREE(P) free((char*)(P)) + +#else /* not BROKEN_OR */ + +#define ALLOC(N,TYPE,NAME) \ + ((alloctemp = malloc((unsigned)((N)*sizeof(TYPE)))) || outmem(), \ + (TYPE *) alloctemp) + +#define ALLOCV(N,TYPE,NAME) \ + ((alloctemp = malloc((unsigned)(N))) || outmem(), \ + (TYPE *) alloctemp) + +#define REALLOC(P,N,TYPE) \ + ((alloctemp = realloc((char*)(P), (unsigned)((N)*sizeof(TYPE)))) || outmem(), \ + (TYPE *) alloctemp) + +#define FREE(P) free((char*)(P)) + +#endif /* BROKEN_OR */ +#endif /* TEST_MALLOC */ + + +#define MIN(a,b) ((a) < (b) ? (a) : (b)) +#define MAX(a,b) ((a) > (b) ? (a) : (b)) + + + +#ifdef toupper +# undef toupper +# undef tolower +# define toupper(c) my_toupper(c) +# define tolower(c) my_tolower(c) +#endif + +#ifndef _toupper +# if 'A' == 65 && 'a' == 97 +# define _toupper(c) ((c)-'a'+'A') +# define _tolower(c) ((c)-'A'+'a') +# else +# ifdef toupper +# undef toupper /* hope these are shadowing real functions, */ +# undef tolower /* because my_toupper calls _toupper! */ +# endif +# define _toupper(c) toupper(c) +# define _tolower(c) tolower(c) +# endif +#endif + + + + +/* End. */ + |