SCANNER.MOD 20 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730
  1. (* Renamed for readability. Semantics unchanged. Original identifiers: see docs/compiler/ + src/compiler/RENAME-MAP.md. *)
  2. IMPLEMENTATION MODULE Scanner;
  3. IMPORT Compiler, Files, Texts, ComLine, Loader, Doubles, Errors, SymTab, CodeGen;
  4. FROM SYSTEM IMPORT ADR, MOVE, CODE, TSIZE, BYTE, OVERFLOW, REALOVERFLOW;
  5. FROM STORAGE IMPORT ALLOCATE,MARK,RELEASE;
  6. VAR withSave: RecordPtr;
  7. tokLen: CARDINAL;
  8. CONST FREEMARKER = 3AE3H;
  9. CONST EOT = 032C; DEL = 177C;
  10. CONST LINEFEED = 012C; TAB = 011C; CR = 015C;
  11. VAR stackLimit [0316H]: ADDRESS;
  12. VAR buffer [0080H]: ARRAY [0..127] OF CHAR;
  13. VAR bufIndex[006CH]: CARDINAL;
  14. VAR filePos [006EH]: CARDINAL;
  15. VAR column [0070H]: CARDINAL;
  16. VAR flag [0072H]: CARDINAL;
  17. CONST EXPECTED = " expected, but ";
  18. (* $[+ remove procedure names *)
  19. PROCEDURE ScanErr(c: CARDINAL);
  20. BEGIN
  21. Errors.ReportError(c);
  22. END ScanErr;
  23. PROCEDURE ChangeEx(VAR f: ARRAY OF CHAR; e: Ext; x: BOOLEAN);
  24. VAR i: CARDINAL;
  25. BEGIN
  26. i := 0;
  27. WHILE (i < HIGH(f) - 3) AND (f[i] <> 0C) AND (f[i] <> '.') DO
  28. INC(i)
  29. END;
  30. IF x OR (f[i] <> '.') THEN
  31. f[i] := '.';
  32. MOVE(ADR(e), ADR(f[i+1]), 3);
  33. END;
  34. END ChangeEx;
  35. PROCEDURE EnterMod(m: ARRAY OF CHAR; k: CARDINAL): CARDINAL;
  36. VAR i: CARDINAL;
  37. ptr : POINTER TO SymTab.Symbol;
  38. BEGIN
  39. i := 0;
  40. WHILE (i < SymTab.moduleCount) AND (SymTab.moduleTable^[i].name <> m) DO
  41. INC(i)
  42. END;
  43. ptr := ADR(SymTab.moduleTable^[i]);
  44. IF i < SymTab.moduleCount THEN
  45. IF ptr^.word <> k THEN Errors.ReportErrorWithText(12, ptr^.name) END;
  46. ELSE
  47. IF i > 15 THEN ScanErr(84) END;
  48. ptr^.name := m;
  49. ptr^.word := k;
  50. INC(SymTab.moduleCount);
  51. END;
  52. RETURN i
  53. END EnterMod;
  54. PROCEDURE Allocate(VAR a:ADDRESS; n:CARDINAL); (* was in Z80 code *)
  55. BEGIN
  56. ALLOCATE(a, n);
  57. END Allocate;
  58. PROCEDURE GetStack(VAR m: ADDRESS);
  59. BEGIN
  60. m := stackLimit - 60;
  61. END GetStack;
  62. PROCEDURE CheckStk(m: ADDRESS);
  63. BEGIN
  64. stackLimit := m + 60;
  65. m^ := FREEMARKER;
  66. END CheckStk;
  67. (* proc 22: find identifier in keyword list *)
  68. PROCEDURE FindIden(l: List; i: ADDRESS; c: BOOLEAN): RecordPtr;
  69. (* original was in Z80 code *)
  70. VAR current: T1;
  71. BEGIN
  72. current := l^.first;
  73. WHILE current <> NIL DO
  74. IF StrCmp(i, current^.link1, c) THEN
  75. RETURN ADDRESS(current)
  76. END;
  77. current := current^.link0;
  78. END;
  79. RETURN NIL;
  80. END FindIden;
  81. (* StrCmp: original proc23 is hand-tuned stack machine code (zero stores;
  82. running pointers live on the M-stack, sizes shared via dup) that no
  83. straight v1.00 Modula-2 source reproduces (proven by exhaustive probes:
  84. INC/+/deref each fail on some operand type; v1.00 always uses memory
  85. for loop state - see F1/S3 probes). The M-code algorithm, fully decoded:
  86. - c=TRUE: LOOP { ch1=*a++; ch2=*b++; folded=((ch1 XOR ch2) AND 0DFH);
  87. IF folded#{} THEN RETURN FALSE END; IF ch1=0C THEN RETURN TRUE END }
  88. (fold via BITSET `/`+`*`; the 0DFH mask also hides the high byte of
  89. the 16-bit word fetch, so the compare is correct)
  90. - c=FALSE: unbounded NUL-terminated compare via string_comp.
  91. This clean version implements exactly that (locals instead of M-stack
  92. temps). NOTE: the decompiled ancestor dropped the c=TRUE branch entirely
  93. ("removed caseInsensitive comparison"); it is restored here. *)
  94. TYPE ByteVec = POINTER TO ARRAY [0..32767] OF CHAR;
  95. PROCEDURE StrCmp(a, b: ADDRESS; c: BOOLEAN):BOOLEAN;
  96. VAR x, y: ByteVec;
  97. ch1, ch2: CHAR;
  98. BEGIN
  99. x := a; y := b;
  100. IF c THEN
  101. LOOP
  102. ch1 := x^[0]; x := ADR(x^[1]);
  103. ch2 := y^[0]; y := ADR(y^[1]);
  104. IF ((BITSET(ORD(ch1)) / BITSET(ORD(ch2))) * BITSET{0,1,2,3,4,6,7})
  105. = BITSET{} THEN
  106. IF ch1 = 0C THEN RETURN TRUE END;
  107. ELSE RETURN FALSE END;
  108. END;
  109. ELSE
  110. WHILE x^[0] = y^[0] DO
  111. IF x^[0] = 0C THEN RETURN TRUE END;
  112. x := ADR(x^[1]); y := ADR(y^[1]);
  113. END;
  114. RETURN FALSE;
  115. END;
  116. END StrCmp;
  117. (* StrLen: original proc24 is the same hand-tuned stack-code class (counter
  118. lives on the M-stack; bound shared; `load-0,dec` = CARDINAL max literal).
  119. Decoded algorithm: i:=-1; LOOP { INC(i); IF i>bound THEN EXIT END;
  120. IF s^[i]=0C THEN EXIT END }; IF i=0 THEN i:=1 END; RETURN i.
  121. Clean version below (memory counter, same semantics incl. min-1 and the
  122. inclusive bound). Signature follows the original DEF
  123. (param2: ADDRESS; param1: WORD): callers pass (ADR(s), HIGH(s)). *)
  124. PROCEDURE StrLen(s: ADDRESS; bound: CARDINAL): CARDINAL;
  125. VAR p: ByteVec;
  126. i: CARDINAL;
  127. BEGIN
  128. p := s; i := 0;
  129. WHILE (i <= bound) AND (p^[i] # 0C) DO INC(i) END;
  130. IF i = 0 THEN RETURN 1 END;
  131. RETURN i
  132. END StrLen;
  133. PROCEDURE CopyStr(VAR d: ADDRESS; VAR s: ARRAY OF CHAR);
  134. VAR length: CARDINAL;
  135. BEGIN
  136. length := StrLen(ADR(s), HIGH(s));
  137. Allocate(d, length+1);
  138. MOVE(ADR(s), d, length);
  139. END CopyStr;
  140. PROCEDURE NewNode(k:CARDINAL):ADDRESS;
  141. VAR ptr: Compiler.RecordPtr;
  142. BEGIN
  143. Allocate(ptr, 14);
  144. ptr^.word4 := k;
  145. RETURN ptr
  146. END NewNode;
  147. PROCEDURE NewSized(k:CARDINAL):ADDRESS;
  148. VAR ptr: Compiler.RecordPtr;
  149. BEGIN
  150. IF k <= 1 THEN Allocate(ptr, 14)
  151. ELSIF k <= 6 THEN Allocate(ptr, 10)
  152. ELSIF k <= 11 THEN Allocate(ptr, 12)
  153. ELSE Allocate(ptr, 16)
  154. END;
  155. ptr^.word4 := k;
  156. RETURN ptr
  157. END NewSized;
  158. PROCEDURE MakeIden(k: CARDINAL): ADDRESS;
  159. VAR ptr : Compiler.RecordPtr;
  160. BEGIN
  161. NeedID;
  162. IF ADDRESS(scopeCur) = SymTab.currentScope THEN Errors.ReportErrorWithText(1, tokBuf) END;
  163. ptr := NewNode(k);
  164. CopyStr(ptr^.word1, tokBuf);
  165. GetSym;
  166. RETURN ptr
  167. END MakeIden;
  168. PROCEDURE InsertSy(n: SymTab.T1);
  169. BEGIN
  170. IF FindIden(ADR(SymTab.currentScope^.link1), n^.link1, 9 IN scanOpt) # NIL THEN
  171. Errors.ReportErrorWithText(1, n^.link1^)
  172. END;
  173. n^.link0 := SymTab.currentScope^.link1;
  174. SymTab.currentScope^.link1 := n;
  175. END InsertSy;
  176. PROCEDURE DeclIden(k: CARDINAL): ADDRESS;
  177. VAR ptr: SymTab.T1;
  178. BEGIN
  179. ptr := MakeIden(k);
  180. ptr^.link0 := SymTab.currentScope^.link1;
  181. SymTab.currentScope^.link1 := ptr;
  182. RETURN ptr;
  183. END DeclIden;
  184. PROCEDURE OpenScop(a:ADDRESS; b: ADDRESS);
  185. BEGIN
  186. Allocate(SymTab.currentScope, 14);
  187. SymTab.currentScope^.w0 := a;
  188. SymTab.currentScope^.link1 := b;
  189. END OpenScop;
  190. PROCEDURE WritList;
  191. VAR PipeChar[034EH]: CHAR;
  192. BEGIN
  193. Texts.WriteLn(2);
  194. IF listing
  195. THEN Texts.WriteCard(2, CodeGen.nextEmitPos - codeSize, 4)
  196. ELSE Texts.SetCol(2, 4)
  197. END;
  198. Texts.WriteChar(2, PipeChar);
  199. Texts.WriteChar(2, ' ')
  200. END WritList;
  201. PROCEDURE EchoChar;
  202. BEGIN
  203. IF (ORD(curCh) + 1) MOD 256 > 32 THEN Texts.WriteChar(2, curCh); RETURN END;
  204. IF curCh = LINEFEED THEN column := 0; WritList; RETURN END;
  205. IF curCh = TAB THEN
  206. REPEAT Texts.WriteChar(2," "); INC(column) UNTIL column MOD 8 = 0;
  207. ELSIF (curCh < " ") AND (curCh # CR) THEN
  208. Texts.WriteChar(2, "^");
  209. Texts.WriteChar(2, CHR(ORD(curCh)+40H))
  210. END;
  211. END EchoChar;
  212. PROCEDURE Refill;
  213. VAR nbRead: CARDINAL;
  214. BEGIN
  215. nbRead := Files.ReadBytes(srcFile, ADR(buffer), 128);
  216. IF nbRead < 128 THEN buffer[nbRead] := EOT END;
  217. bufIndex := 0;
  218. NextCh
  219. END Refill;
  220. PROCEDURE InitScan;
  221. BEGIN
  222. curCh := ' ';
  223. column := 0;
  224. bufIndex := 128;
  225. IF 0 IN scanOpt THEN WritList END;
  226. Files.NoTrailer(srcFile)
  227. END InitScan;
  228. PROCEDURE OpenSrc;
  229. VAR nbRead: CARDINAL;
  230. BEGIN
  231. IF NOT Files.Open(srcFile, ComLine.inName) THEN HALT END;
  232. InitScan;
  233. Files.SetPos(srcFile, LONG((tokPos DIV 128) * 128));
  234. nbRead := Files.ReadBytes(srcFile, ADR(buffer), 128);
  235. bufIndex := tokPos MOD 128;
  236. filePos := tokPos;
  237. GetSym
  238. END OpenSrc;
  239. PROCEDURE NextCh; (* original was in Z80 code *)
  240. VAR ch: CHAR;
  241. BEGIN
  242. IF bufIndex = 128 THEN Refill
  243. ELSE
  244. ch := buffer[bufIndex];
  245. INC(bufIndex);
  246. IF ch = EOT THEN curCh := 377C ELSE curCh := ch END;
  247. INC(filePos);
  248. IF 0 IN scanOpt THEN
  249. IF ch >= ' ' THEN
  250. INC(column);
  251. IF flag # 0 THEN
  252. Texts.WriteChar(3, ch);
  253. RETURN;
  254. END;
  255. END;
  256. EchoChar
  257. END;
  258. END;
  259. END NextCh;
  260. PROCEDURE GetSym;
  261. (* $[- keep procedure names *)
  262. (* proc 35 *)
  263. PROCEDURE ParseNum;
  264. VAR intPart: CARDINAL;
  265. VAR expVal: CARDINAL;
  266. VAR curDig: CARDINAL;
  267. VAR prevDig: CARDINAL;
  268. VAR limit: CARDINAL;
  269. VAR expAdj: INTEGER;
  270. VAR negExp: BOOLEAN;
  271. VAR isDec : BOOLEAN;
  272. VAR isOctal: BOOLEAN;
  273. VAR decVal: LONGINT;
  274. VAR decFull: LONGINT;
  275. VAR octVal: LONGINT;
  276. VAR hexVal: LONGINT;
  277. (* $[+ remove procedure names *)
  278. (* proc 36 *)
  279. PROCEDURE Power10(exp: CARDINAL): REAL;
  280. VAR i: CARDINAL;
  281. VAR r: REAL;
  282. BEGIN
  283. i := 0;
  284. r := 1.0;
  285. REPEAT
  286. IF ODD(exp) THEN
  287. CASE i OF
  288. | 0 : r := r * 1.0E01
  289. | 1 : r := r * 1.0E02
  290. | 2 : r := r * 1.0E04
  291. | 3 : r := r * 1.0E08
  292. | 4 : r := r * 1.0E16
  293. | 5 : r := r * 1.0E32
  294. ELSE RAISE REALOVERFLOW
  295. END;
  296. END;
  297. exp := exp DIV 2;
  298. INC(i);
  299. UNTIL exp = 0;
  300. RETURN r
  301. END Power10;
  302. PROCEDURE AccumDig;
  303. VAR digit: CARDINAL;
  304. BEGIN
  305. IF tokLen < 128 THEN tokBuf[tokLen] := curCh; INC(tokLen) END;
  306. NextCh;
  307. digit := ORD(curCh) - ORD('0');
  308. IF digit > 9 THEN
  309. IF digit >= 17 THEN digit := digit - 7 ELSE digit := 16 END;
  310. END; (* 043C *)
  311. curDig := digit
  312. END AccumDig;
  313. (* $[- keep procedure names *)
  314. BEGIN (* ParseNum *)
  315. intPart := 0;
  316. decVal := LONG(0);
  317. expAdj := 0;
  318. hexVal := decVal;
  319. octVal := decVal;
  320. decFull := decVal;
  321. tokLen:= 0;
  322. curDig := ORD(curCh) - ORD('0');
  323. prevDig := curDig;
  324. isOctal := TRUE;
  325. isDec := TRUE;
  326. REPEAT
  327. IF prevDig > 7 THEN
  328. isOctal := FALSE;
  329. IF prevDig > 9 THEN isDec := FALSE END;
  330. END;
  331. IF curDig <= 9 THEN
  332. decFull := decFull * LONG(10) + LONG(curDig);
  333. IF decFull < 3355443L THEN decVal := decFull ELSE INC(expAdj) END;
  334. IF curDig <= 7 THEN octVal := octVal * LONG(8) + LONG(curDig) END;
  335. END; (* 04b1 *)
  336. IF hexVal <= LONG(65535) THEN hexVal := hexVal * LONG(16) + LONG(curDig) END;
  337. prevDig := curDig;
  338. AccumDig;
  339. UNTIL curDig > 15;
  340. litType := Compiler.CardType;
  341. IF curCh = '.' THEN
  342. AccumDig;
  343. IF curCh = '.' THEN curCh := DEL; DEC(tokLen)
  344. ELSIF curCh = ')' THEN curCh := ']'; DEC(tokLen)
  345. ELSE
  346. IF NOT isDec THEN ScanErr(30) END;
  347. litType := Compiler.RealType;
  348. WHILE curDig <= 9 DO
  349. IF decVal < 3355443L THEN
  350. decVal := decVal * LONG(10) + LONG(curDig);
  351. DEC(expAdj)
  352. END; (* 0527 *)
  353. AccumDig;
  354. END; (* 052B *)
  355. IF curDig IN {13, 14} THEN
  356. IF curDig = 13 THEN litType := Compiler.LongrealType END;
  357. expVal := 0;
  358. AccumDig;
  359. negExp := (curCh = '-');
  360. IF negExp OR (curCh = '+') THEN AccumDig END;
  361. IF curDig > 9 THEN ScanErr(30) END;
  362. REPEAT
  363. IF expVal < 255 THEN expVal := expVal * 10 + curDig END;
  364. AccumDig;
  365. UNTIL curDig > 9;
  366. IF negExp
  367. THEN DEC(expAdj, expVal)
  368. ELSE INC(expAdj, expVal)
  369. END;
  370. END; (* 0577 *)
  371. IF litType = Compiler.RealType THEN
  372. IF decVal >= 16777216L
  373. THEN realVal := FLOAT((decVal + 1L) DIV 2L) * 2.0 (* LONG(1)/LONG(2)
  374. call nodes spiked the v1.00 expression heap (OUT OF MEMORY);
  375. L-suffixed literals fold to const nodes, identical codegen *)
  376. ELSE realVal := FLOAT(decVal)
  377. END;
  378. IF expAdj < 0 THEN realVal := realVal / Power10(-expAdj)
  379. ELSIF expAdj # 0 THEN realVal := realVal * Power10(expAdj)
  380. END;
  381. ELSE
  382. tokBuf[tokLen] := 0C;
  383. IF NOT Doubles.StrToDouble(tokBuf, lrealVal) THEN ScanErr(74) END;
  384. END;
  385. END;
  386. END; (* 05D4 *)
  387. IF litType^.word4 # 8 THEN
  388. IF curCh = 'L' THEN
  389. AccumDig;
  390. realVal := REAL(decFull);
  391. litType := Compiler.LongintType;
  392. ELSE
  393. limit := 65535;
  394. IF curCh = 'H' THEN AccumDig; decVal := hexVal
  395. ELSE
  396. IF prevDig IN {11, 12} THEN
  397. IF NOT isOctal THEN ScanErr(30) END;
  398. decVal := octVal;
  399. IF prevDig = 12 THEN litType := Compiler.CharType; limit := 255 END;
  400. ELSE
  401. IF NOT isDec OR (prevDig > 9) THEN ScanErr(30) END;
  402. decVal := decFull;
  403. END;
  404. END; (* 062e *)
  405. IF decVal > LONG(limit) THEN ScanErr(73) END;
  406. cardVal := CARD(decVal);
  407. END;
  408. END; (* 063f *)
  409. IF charClas^[ORD(curCh)] = 10 THEN ScanErr(30) END;
  410. EXCEPTION
  411. | OVERFLOW: ScanErr(73)
  412. | REALOVERFLOW:
  413. IF expAdj >= 0 THEN ScanErr(74) END;
  414. realVal := REAL(0L);
  415. END ParseNum;
  416. (* $[+ remove procedure names *)
  417. PROCEDURE SkipComm;
  418. VAR optIdx: CARDINAL;
  419. BEGIN
  420. REPEAT
  421. REPEAT
  422. IF curCh = CHR(255) THEN ScanErr(29) END;
  423. NextCh;
  424. IF curCh = '(' THEN
  425. REPEAT NextCh UNTIL curCh # '(';
  426. IF curCh = '*' THEN SkipComm END; (* recursive call *)
  427. END;
  428. IF curCh = '$' THEN
  429. NextCh;
  430. optIdx := CARDINAL(BITSET(curCh) * {0,1,2,3,4,6}) - ORD('L');
  431. IF optIdx <= 15 THEN
  432. NextCh;
  433. IF curCh = '-' THEN EXCL(scanOpt, optIdx)
  434. ELSIF curCh = '+' THEN INCL(scanOpt, optIdx)
  435. END;
  436. IF optIdx = 0 THEN Texts.WriteLn(2) END;
  437. END;
  438. END; (* 06c6 *)
  439. UNTIL curCh = '*';
  440. REPEAT NextCh UNTIL curCh # '*';
  441. UNTIL curCh = ')';
  442. END SkipComm;
  443. PROCEDURE ScanNext():BOOLEAN; (* original was in Z80 code *)
  444. VAR j: CARDINAL;
  445. VAR nextClass: CARDINAL;
  446. BEGIN
  447. isLit := FALSE;
  448. identKd := 7;
  449. WHILE curCh <= ' ' DO NextCh END;
  450. tokPos := filePos - 1;
  451. tokCol := column;
  452. IF curCh < CHR(128)
  453. THEN curSym := charClas^[ORD(curCh)]
  454. ELSE curSym := 0
  455. END;
  456. IF curSym = 10 THEN
  457. j := 0;
  458. REPEAT
  459. IF j # 128 THEN tokBuf[j] := curCh; INC(j) END;
  460. NextCh;
  461. nextClass := charClas^[ORD(curCh)];
  462. UNTIL (nextClass # 10) AND (nextClass # 11);
  463. tokBuf[j] := 0C;
  464. RETURN TRUE
  465. END; (* 0730 *)
  466. RETURN FALSE;
  467. END ScanNext;
  468. VAR tokDone: BOOLEAN;
  469. strLen: CARDINAL;
  470. ignCase: BOOLEAN;
  471. quote: CHAR;
  472. BEGIN
  473. REPEAT
  474. IF ScanNext() THEN
  475. ignCase := 9 IN scanOpt;
  476. curSym := keyHash(ADR(tokBuf), CHR(ORD(ignCase))); (* CHR(ORD()) is zero-cost (V3 probe) and value-preserving; satisfies CHAR formal *)
  477. IF curSym # 0 THEN
  478. identKd := 7;
  479. IF ((curSym = 14) OR (curSym = 39)) AND NOT (12 IN scanOpt) THEN
  480. Errors.AskContinue(2)
  481. END;
  482. RETURN
  483. END; (* 0797 *)
  484. scopeCur := ADDRESS(SymTab.currentScope);
  485. REPEAT
  486. curNode := FindIden(ADR(scopeCur^.link1), ADR(tokBuf), ignCase);
  487. IF curNode # NIL THEN
  488. litType := ADDRESS(curNode^.word2);
  489. identKd := curNode^.word4;
  490. follSet := curNode^.word3;
  491. RETURN
  492. END;
  493. scopeCur := scopeCur^.link0;
  494. UNTIL scopeCur = NIL;
  495. identKd := 0;
  496. RETURN
  497. END; (* 07BA *)
  498. tokDone := TRUE;
  499. CASE curSym OF
  500. | 0 : ScanErr(31 - ORD(curCh = CHR(255)) * 2)
  501. | 2 : NextCh;
  502. IF curCh = '=' THEN curSym := 27; NextCh
  503. ELSIF curCh = ')' THEN curSym := 7; NextCh
  504. END;
  505. | 3 : NextCh;
  506. IF curCh = '.' THEN curSym := 4; NextCh
  507. ELSIF curCh = ')' THEN curSym := 6; NextCh
  508. END;
  509. |11 : isLit := TRUE;
  510. identKd := 1;
  511. curSym := 0;
  512. ParseNum;
  513. tokBuf[tokLen] := 0C
  514. |12 : strLen := 0;
  515. isLit := TRUE;
  516. identKd := 1;
  517. curSym := 0;
  518. quote := curCh;
  519. NextCh;
  520. WHILE curCh # quote DO
  521. IF curCh = LINEFEED THEN ScanErr(28) END;
  522. IF curCh = CHR(255) THEN ScanErr(29) END;
  523. IF strLen < 128 THEN
  524. tokBuf[strLen] := curCh;
  525. INC(strLen);
  526. END;
  527. NextCh;
  528. END; (* 0839 *)
  529. tokBuf[strLen] := 0C;
  530. NextCh;
  531. litType := Compiler.charArrayDesc;
  532. IF strLen = 1 THEN
  533. litType := Compiler.CharType;
  534. cardVal := ORD(tokBuf[0]);
  535. END;
  536. ELSE
  537. NextCh;
  538. CASE curSym OF
  539. | 43: IF curCh = '*' THEN SkipComm; NextCh; tokDone := FALSE
  540. ELSIF curCh = '.' THEN curSym := 44; NextCh
  541. ELSIF curCh = ':' THEN curSym := 45; NextCh
  542. END;
  543. | 54: IF curCh = '=' THEN curSym := 56; NextCh
  544. ELSIF curCh = '>' THEN curSym := 53; NextCh
  545. END;
  546. | 55: IF curCh = '=' THEN curSym := 57; NextCh END;
  547. END;
  548. END;
  549. UNTIL tokDone;
  550. END GetSym;
  551. PROCEDURE AcceptSy(s: CARDINAL): BOOLEAN;
  552. BEGIN
  553. IF curSym = s THEN GetSym; RETURN TRUE END;
  554. RETURN FALSE
  555. END AcceptSy;
  556. PROCEDURE PushWith;
  557. BEGIN
  558. IF identKd = 6 THEN
  559. withSave^.word1 := ADDRESS(curNode^.high);
  560. withSave^.word0 := ADDRESS(SymTab.currentScope);
  561. SymTab.currentScope := ADDRESS(withSave);
  562. GetSym;
  563. ExpectSy(3);
  564. NeedID;
  565. IF scopeCur # ADDRESS(withSave) THEN Errors.ReportErrorWithText(3, tokBuf) END;
  566. SymTab.currentScope := SymTab.currentScope^.w0;
  567. END;
  568. END PushWith;
  569. PROCEDURE ExpectSy(s:CARDINAL);
  570. VAR expSet: BITSET;
  571. VAR base: CARDINAL;
  572. BEGIN
  573. IF curSym = s THEN GetSym; RETURN END;
  574. base := 0;
  575. expSet := {};
  576. IF s >= 51 THEN base := 51
  577. ELSIF s >= 40 THEN base := 40
  578. ELSIF s >= 27 THEN base := 27
  579. ELSIF s >= 13 THEN base := 13
  580. END;
  581. expSet := expSet + {s - base};
  582. Errors.ReportExpectedSet(expSet, base)
  583. END ExpectSy;
  584. PROCEDURE TestSet(s: BITSET);
  585. BEGIN
  586. IF NOT (curSym IN s) THEN Errors.ReportExpectedSet(s, 0) END;
  587. END TestSet;
  588. PROCEDURE TestR40(s: BITSET);
  589. BEGIN
  590. IF NOT ((curSym-40) IN s) THEN Errors.ReportExpectedSet(s, 40) END;
  591. END TestR40;
  592. PROCEDURE TestR13(s: BITSET);
  593. BEGIN
  594. IF NOT ((curSym-13) IN s) THEN Errors.ReportExpectedSet(s, 13) END;
  595. END TestR13;
  596. PROCEDURE NeedID;
  597. BEGIN
  598. IF (identKd = 7) OR isLit THEN
  599. Errors.ShowErrorPosition('A');
  600. Texts.WriteString(3, "Identifier");
  601. Texts.WriteString(3, EXPECTED);
  602. Errors.WriteFoundToken;
  603. Errors.AskEditOrQuit;
  604. END;
  605. END NeedID;
  606. PROCEDURE ExpectSt(VAR p: ARRAY OF CHAR);
  607. BEGIN
  608. NeedID;
  609. IF StrCmp(ADR(tokBuf), ADR(p), 9 IN scanOpt) THEN GetSym; RETURN END;
  610. Errors.ReportErrorWithText(9, p);
  611. END ExpectSt;
  612. PROCEDURE ExpectKd(k: CARDINAL);
  613. BEGIN
  614. IF identKd # k THEN
  615. NeedID;
  616. IF identKd = 0 THEN Errors.ReportErrorWithText(0, tokBuf) END;
  617. Errors.ShowErrorPosition('B');
  618. Errors.WriteKindName(k);
  619. Texts.WriteString(3, EXPECTED);
  620. Errors.WriteKindName(identKd);
  621. Texts.WriteString(3, " found");
  622. Errors.AskEditOrQuit;
  623. END;
  624. END ExpectKd;
  625. PROCEDURE Compile;
  626. (* Z80 proc 40 removed in Reloaded; v1.00 rejects SYSTEM.ADR on simple
  627. unstructured variables, so this open-array shim recovers the address.
  628. Proven on hardware: open VAR ARRAY OF WORD accepts any variable, and
  629. ADR(x) inside is legal (probe ZZ.DEF/MOD). *)
  630. PROCEDURE VarAddr(VAR x: ARRAY OF WORD): ADDRESS;
  631. BEGIN
  632. RETURN ADR(x);
  633. END VarAddr;
  634. VAR addr: ADDRESS;
  635. ptr [006EH]: CARDINAL;
  636. console [0072H]: BOOLEAN;
  637. jmpOpc [0074H]: CARDINAL;
  638. jmpAddr[0075H]: CARDINAL;
  639. (* $[- keep procedure names *)
  640. BEGIN
  641. jmpOpc := 0C3H;
  642. addr := VarAddr(scanOpt)-6;
  643. addr := ADDRESS(addr^) - 4;
  644. jmpAddr:= addr + CARDINAL(addr^) + 3;
  645. MARK(addr);
  646. ptr := 0;
  647. console := (ComLine.outName = "CON:");
  648. listing := FALSE;
  649. tokPos := 0;
  650. Allocate(withSave, 14);
  651. Compiler.OpenSourceAndOutput;
  652. IF srcFile <> NIL THEN
  653. Allocate(codeBuf, 4096);
  654. Loader.Call("COMPILE");
  655. IF Compiler.nativeCodeRequested THEN
  656. CheckStk(codeBuf + CodeGen.nextEmitPos);
  657. IF CodeGen.windowBase <> 0 THEN
  658. MOVE(codeBuf, codeBuf + CodeGen.windowBase, CodeGen.nextEmitPos - CodeGen.windowBase);
  659. Files.SetPos(codeFile, LONG(0));
  660. IF Files.ReadBytes(codeFile, codeBuf, CodeGen.windowBase) <> CodeGen.windowBase THEN
  661. RAISE Files.EndError
  662. END;
  663. END;
  664. Files.SetPos(codeFile, LONG(0));
  665. Loader.Call("GENZ80");
  666. END;
  667. END;
  668. Texts.CloseText(Texts.output);
  669. RELEASE(addr);
  670. EXCEPTION Loader.LoadError:
  671. Texts.WriteLn(3); (* console *)
  672. Texts.WriteString(3,"ERROR: CANNOT LOAD OVERLAY");
  673. Texts.WriteLn(3);
  674. Files.Delete(codeFile);
  675. RELEASE(addr)
  676. END Compile;
  677. (* $[+ remove procedure names *)
  678. END Scanner.