TopSpeed-V3-M2.atg 64 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171
  1. COMPILER M2
  2. (* =============================================================================
  3. TopSpeed Modula-2 V3 - COMPLETE GRAMMAR (Coco/R .atg form)
  4. Historical JPI/Clarion V3 dialect, reconstructed from the real TS-V3
  5. corpus (TABLE/GWINM2P/GWINC2M/BYTEFIDD/CLUB/RS/Modbase) + the shipped
  6. CR.MOD reserved words + PIM/ISO Modula-2 reference forms.
  7. This ATG is the deliverable of the "complete V3 grammar" work item.
  8. It intentionally DIVERGES from the modern m2compiler-V3 subset's
  9. locked rules where the corpus proves the original dialect differed:
  10. - identifiers carry '_' and '@' (Graph._VGA, ct__@Fssssi)
  11. - '&' = AND , '~' = NOT , '<>' = '#' (all accepted)
  12. - literal suffixes H (hex), C (char), B (base-8/octal),
  13. plus 0x/0X hex-prefix forms
  14. - `::=` constant alias form (GCoord::=INTEGER)
  15. - anchored type subranges (SHORTINT[-1..1])
  16. - qualified type/designator idents (Client.ClientRec, t2.Root,
  17. p^.Left, S1[sp1], Graph.GetVideoConfig(vc))
  18. - full composite types: ARRAY (fixed + open), RECORD + variants,
  19. SET OF (range/base/enum forms), POINTER TO, PROCEDURE types
  20. - statements: WITH, IN, IS, set constructors {}, shifts << >>,
  21. procedure/function call statements
  22. - Clarion-form classes with multi-parent CLAUSE (extra parent = 230)
  23. Constructs the current scalar backend cannot lower yet PARSE fully
  24. and end with the standard SemError(230) "not supported yet" marker,
  25. exactly like M2.atg's parse-now/lower-later discipline. Semantic
  26. error codes reused from the V1/V2/Test2 family:
  27. 200 duplicate, 201 undeclared, 202 module name mismatch,
  28. 210 bad assignment, 211 bad arithmetic, 212 boolean operand,
  29. 213 incompatible comparison, 214 boolean cond required,
  30. 220 FOR needs integer var/bounds, 221 not a type name,
  31. 222 set operand mismatch, 230 not supported yet,
  32. 231 opaque type outside definition, 232 bad RETURN.
  33. LL(1) notes (accepted as benign, verified correct codegen):
  34. - TypeBlock's CLASS/CLASS IMPLEMENTATION 2-token lookahead
  35. - variant-record CASE labels sharing first-sets with field
  36. identifier lists (classic Modula-2 ambiguity).
  37. ============================================================================= *)
  38. IMPORT SymTab, QbeGen;
  39. CHARACTERS
  40. eol = CHR(13) .
  41. lf = CHR(10) .
  42. letter = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz" .
  43. digit = "0123456789" .
  44. octDigit = "01234567" .
  45. hexDigit = digit + "ABCDEFabcdef" .
  46. noQuote1 = ANY - "'" - eol .
  47. noQuote2 = ANY - '"' - eol .
  48. IGNORE CHR(9) .. CHR(13)
  49. COMMENTS FROM "(*" TO "*)" NESTED
  50. COMMENTS FROM "//" TO lf
  51. TOKENS
  52. (* V3 identifier: classic letters/digits PLUS '_' and '@' which the
  53. shipped code uses freely (Graph._VGA, _Find, ct__@Fssssi). *)
  54. ident = ( letter | "_" ) { letter | digit | "_" | "@" } .
  55. (* Numbers. V3 kept the PIM qualified forms: trailing H = hex,
  56. trailing C = character constant (hex value), trailing B = base-8
  57. (the Modbase date code needs 60B = 48 = ORD('0'), i.e. octal 60);
  58. modern 0x/0X hex-prefix also accepted (TS Dev Guide). The
  59. CONTEXT("..") clause keeps `1..10` an integer + range operator
  60. rather than the start of a real `1. ...`. *)
  61. integer = digit { digit }
  62. | digit { digit } CONTEXT("..")
  63. | digit { digit } ( "B" | "b" )
  64. | digit { hexDigit } ( "H" | "h" )
  65. | digit { hexDigit } ( "C" | "c" )
  66. | "0x" hexDigit { hexDigit }
  67. | "0X" hexDigit { hexDigit } .
  68. real = digit { digit } "." { digit }
  69. [ ( "E" | "e" ) [ "+" | "-" ] digit { digit } ] .
  70. string = "'" { noQuote1 } "'"
  71. | '"' { noQuote2 } '"' .
  72. PRODUCTIONS
  73. M2
  74. = Unit "." .
  75. (* Units: program modules compile fully; DEFINITION and
  76. IMPLEMENTATION modules parse + check now but lower in step 4
  77. (each ends with one 230); same for nested local modules. *)
  78. Unit
  79. = DefUnit
  80. | ImplUnit
  81. | ProgModule .
  82. DefUnit (. VAR m1, m2, pn: SymTab.Name; .)
  83. = "DEFINITION" "MODULE"
  84. GetIdent<m1> (. SymTab.Init; QbeGen.OpenModule(m1);
  85. IF ~SymTab.Enter(m1,
  86. SymTab.KindModule) THEN
  87. SemError(200) END; .)
  88. ";"
  89. { Import }
  90. { ConstBlock | TypeBlock<TRUE> | VarBlock
  91. | ProcHeading<pn> ";" (. SymTab.CloseProc; .)
  92. | ClassItem ";" }
  93. "END"
  94. GetIdent<m2> (. IF ~SymTab.Equal(m1, m2) THEN
  95. SemError(202) END; .)
  96. (. QbeGen.CloseModule;
  97. SemError(230);
  98. SymTab.PrintTable; .) .
  99. ImplUnit (. VAR m1, m2: SymTab.Name; .)
  100. = "IMPLEMENTATION" "MODULE"
  101. GetIdent<m1> (. SymTab.Init; QbeGen.OpenModule(m1);
  102. IF ~SymTab.Enter(m1,
  103. SymTab.KindModule) THEN
  104. SemError(200) END; .)
  105. ";"
  106. { Import }
  107. DeclSeq
  108. [ "BEGIN" (. QbeGen.BeginBody; .)
  109. [ StatSeq ] ]
  110. "END"
  111. GetIdent<m2> (. IF ~SymTab.Equal(m1, m2) THEN
  112. SemError(202) END; .)
  113. (. QbeGen.CloseModule;
  114. SemError(230);
  115. SymTab.PrintTable; .) .
  116. ProgModule (. VAR m1, m2: SymTab.Name; .)
  117. = "MODULE"
  118. GetIdent<m1> (. SymTab.Init; QbeGen.OpenModule(m1);
  119. IF ~SymTab.Enter(m1,
  120. SymTab.KindModule) THEN
  121. SemError(200) END; .)
  122. [ Priority ]
  123. ";"
  124. { Import }
  125. DeclSeq
  126. [ "BEGIN" (. QbeGen.BeginBody; .)
  127. [ StatSeq ] ]
  128. "END"
  129. GetIdent<m2> (. IF ~SymTab.Equal(m1, m2) THEN
  130. SemError(202) END; .)
  131. (. QbeGen.EndModule;
  132. SymTab.PrintTable; .) .
  133. DeclSeq
  134. = { ConstBlock | TypeBlock<FALSE> | VarBlock | [ "INLINE" ] ProcDecl ";"
  135. | NestedModule ";" | ClassItem ";"
  136. | "LABEL" LabelList ";" } .
  137. LabelList (. VAR nm: SymTab.Name; .)
  138. = GetIdent<nm> (. SemError(230); .)
  139. { "," GetIdent<nm> (. SemError(230); .) } .
  140. (* Local module, Wirth form. Parses + checks fully (own scope);
  141. lowering waits for step 4, marked by one 230 at END. *)
  142. NestedModule (. VAR m1, m2: SymTab.Name; .)
  143. = "MODULE"
  144. GetIdent<m1> (. IF ~SymTab.Enter(m1,
  145. SymTab.KindModule) THEN
  146. SemError(200) END;
  147. SymTab.PushScope; .)
  148. [ Priority ]
  149. ";"
  150. { Import }
  151. [ Export ]
  152. DeclSeq
  153. [ "BEGIN"
  154. [ StatSeq ] ]
  155. "END"
  156. GetIdent<m2> (. IF ~SymTab.Equal(m1, m2) THEN
  157. SemError(202) END;
  158. SymTab.PopScope;
  159. SemError(230); .) .
  160. Priority
  161. = "[" integer "]" (. SemError(230); .) .
  162. Export (. VAR nm: SymTab.Name; .)
  163. = "EXPORT" (* names wire up in step 4 *)
  164. [ "QUALIFIED" ]
  165. GetIdent<nm>
  166. { "," GetIdent<nm> }
  167. ";" .
  168. Import (. VAR n: SymTab.Name; .)
  169. = "FROM"
  170. GetIdent<n> (. IF ~SymTab.Enter(n,
  171. SymTab.KindImport) THEN
  172. SemError(200) END; .)
  173. "IMPORT"
  174. ImpList ";"
  175. | "IMPORT"
  176. ImpList ";" .
  177. ImpList (. VAR n: SymTab.Name; .)
  178. = GetIdent<n> (. IF ~SymTab.Enter(n,
  179. SymTab.KindImport) THEN
  180. SemError(200) END; .)
  181. { ","
  182. GetIdent<n> (. IF ~SymTab.Enter(n,
  183. SymTab.KindImport) THEN
  184. SemError(200) END; .) } .
  185. (* Opaque "TYPE T;" needs isDef (definition units); elsewhere 231. *)
  186. TypeBlock<isDef: BOOLEAN>
  187. = "TYPE" { TypeItem<isDef> ";" | ClassItem ";" } .
  188. TypeItem<isDef: BOOLEAN> (. VAR n: SymTab.Name;
  189. t: SymTab.TypeIndex; .)
  190. = GetIdent<n> (. IF ~SymTab.Enter(n,
  191. SymTab.KindType) THEN
  192. SemError(200) END; .)
  193. ( "=" Type<t> (. SymTab.SetSymType(n, t); .)
  194. | (. IF ~isDef THEN
  195. SemError(231) END;
  196. SymTab.SetSymType(n,
  197. SymTab.NewAlias()); .) ) .
  198. (* V3 TYPE surface. Start-symbols are all distinct:
  199. ident (named / anchored subrange), '[' (bare subrange),
  200. '(' (enum) , ARRAY , RECORD , SET , POINTER , PROCEDURE . *)
  201. Type<VAR t: SymTab.TypeIndex>
  202. = TypeIdent2<t> [ "["
  203. SubrangeRest<t> (. (* anchored subrange:
  204. SHORTINT[-1..1],
  205. SHORTCARD[0..7] *) .)
  206. "]" ]
  207. | "[" SubrangeRest<t> "]"
  208. | Enum<t>
  209. | ArrayType<t>
  210. | RecordType<t>
  211. | SetType<t>
  212. | PointerType<t>
  213. | "VIRTUAL" "POINTER" TypeIdent2<t> (. SemError(230); .)
  214. | ProcType<t> .
  215. (* Qualified type ident: Client.ClientRec, SYSTEM.WORD. *)
  216. TypeIdent2<VAR t: SymTab.TypeIndex> (. VAR n: SymTab.Name;
  217. k: INTEGER; .)
  218. = GetIdent<n> (. IF ~SymTab.Lookup(n) THEN
  219. SemError(201);
  220. t := SymTab.InvalidType
  221. ELSE k := SymTab.SymKind(n);
  222. IF (k = SymTab.KindType)
  223. OR (k = SymTab.KindPredef) THEN
  224. t := SymTab.SymType(n)
  225. ELSIF k = SymTab.KindImport THEN
  226. t := SymTab.InvalidType
  227. ELSE SemError(221);
  228. t := SymTab.InvalidType
  229. END
  230. END; .)
  231. { "." GetIdent<n> (. SemError(230);
  232. t := SymTab.InvalidType; .) } .
  233. (* '[' Expr '..' Expr ']' (bare or anchored). Folds literal bounds
  234. into a NewSubR subrange; anything else parses but lowers later. *)
  235. SubrangeRest<VAR t: SymTab.TypeIndex>
  236. (. VAR tlo, thi: SymTab.TypeIndex;
  237. qlo, qhi: QbeGen.QVal;
  238. lo, hi: INTEGER; .)
  239. = Expr<tlo, qlo> ".." Expr<thi, qhi>
  240. (. IF (tlo = SymTab.InvalidType)
  241. OR (thi = SymTab.InvalidType) THEN
  242. t := SymTab.InvalidType
  243. ELSIF (SymTab.ClassOf(tlo) #
  244. SymTab.ClInt)
  245. OR (SymTab.ClassOf(thi) #
  246. SymTab.ClInt) THEN
  247. SemError(230);
  248. t := SymTab.InvalidType
  249. ELSIF ~SymTab.ConstInt(qlo, lo)
  250. OR ~SymTab.ConstInt(qhi, hi)
  251. OR (lo > hi) THEN
  252. SemError(230);
  253. t := SymTab.InvalidType
  254. ELSE t := SymTab.NewSubR(lo, hi)
  255. END; .) .
  256. Enum<VAR t: SymTab.TypeIndex> (. VAR n: SymTab.Name; .)
  257. = "(" (. t := SymTab.NewEnum(); .)
  258. GetIdent<n> (. IF ~SymTab.Enter(n,
  259. SymTab.KindConst) THEN
  260. SemError(200) END;
  261. SymTab.SetSymType(n, t); .)
  262. { "," GetIdent<n> (. IF ~SymTab.Enter(n,
  263. SymTab.KindConst) THEN
  264. SemError(200) END;
  265. SymTab.SetSymType(n, t); .) }
  266. ")" .
  267. (* ARRAY [lo..hi] OF T / ARRAY OF T (open formal) / multi bound *)
  268. ArrayType<VAR t: SymTab.TypeIndex> (. VAR e: SymTab.TypeIndex;
  269. i: CARDINAL; .)
  270. = "ARRAY"
  271. ( "[" Bound { "," Bound } "]" (. t := SymTab.InvalidType; .)
  272. | Bound (. t := SymTab.InvalidType; .)
  273. | (. t := SymTab.InvalidType; .) )
  274. "OF" Type<e> (. t := SymTab.NewArray(e);
  275. SemError(230); .) .
  276. Bound (. VAR t: SymTab.TypeIndex;
  277. q: QbeGen.QVal; .)
  278. = Expr<t, q> [ ".." Expr<t, q> ] (. SemError(230); .) .
  279. (* RECORD with field lists and tagless/tagged variant CASE.
  280. FieldListSequence is the classic PIM form: fields separated by
  281. ';', alternatives by '|', optional ELSE. The label-vs-field
  282. first-set overlap is the known benign LL(1) advisory. *)
  283. RecordType<VAR t: SymTab.TypeIndex>
  284. (. VAR n: SymTab.Name;
  285. rt: SymTab.TypeIndex; .)
  286. = "RECORD" (. rt := SymTab.NewRecord();
  287. t := rt; .)
  288. FieldListSequence<rt>
  289. "END" (. SemError(230); .) .
  290. FieldListSequence<rec: SymTab.TypeIndex>
  291. = [ FieldList<rec> { ";" [ FieldList<rec> ] } ] .
  292. FieldList<rec: SymTab.TypeIndex> (. VAR tag: SymTab.Name;
  293. ti: SymTab.TypeIndex; .)
  294. = "CASE" (. SemError(230); .)
  295. [ GetIdent<tag> ":"
  296. ] Type<ti>
  297. "OF" VariantList<rec>
  298. "END"
  299. | FieldIdents<rec> .
  300. FieldIdents<rec: SymTab.TypeIndex> (. VAR n: SymTab.Name;
  301. t: SymTab.TypeIndex; .)
  302. = GetIdent<n> (. IF ~SymTab.FieldPending(rec, n)
  303. THEN SemError(200) END; .)
  304. { "," GetIdent<n> (. IF ~SymTab.FieldPending(rec, n)
  305. THEN SemError(200) END; .) }
  306. ":" Type<t> (. SymTab.FixPendingF(rec, t); .) .
  307. VariantList<rec: SymTab.TypeIndex>
  308. = [ "|" ] Variant<rec> { "|" Variant<rec> }
  309. [ "ELSE" FieldListSequence<rec> ] .
  310. Variant<rec: SymTab.TypeIndex>
  311. = VariantLabels ":" (. SymTab.PushScope; .)
  312. FieldListSequence<rec> (. SymTab.PopScope; .) .
  313. VariantLabels
  314. = VariantLabel { "," VariantLabel } .
  315. VariantLabel (. VAR t1, t2: SymTab.TypeIndex;
  316. q1, q2: QbeGen.QVal; .)
  317. = Expr<t1, q1> (. SemError(230); .)
  318. [ ".." Expr<t2, q2> (. SemError(230); .) ] .
  319. (* SET OF base: SHORTCARD[0..7], [0..31], CHAR, Direction,
  320. (RShift, LShift, Ctrl, ...) *)
  321. SetType<VAR t: SymTab.TypeIndex> (. VAR b: SymTab.TypeIndex; .)
  322. = "SET" "OF"
  323. ( TypeIdent2<b> (. t := SymTab.NewSet(b);
  324. SemError(230); .)
  325. | "[" SubrangeRest<b> "]" (. t := SymTab.NewSet(b);
  326. SemError(230); .)
  327. | Enum<b> (. t := SymTab.NewSet(b);
  328. SemError(230); .) ) .
  329. PointerType<VAR t: SymTab.TypeIndex> (. VAR b: SymTab.TypeIndex; .)
  330. = "POINTER" "TO" Type<b> (. t := SymTab.NewPtr(b);
  331. SemError(230); .) .
  332. (* PROCEDURE type: Action = PROCEDURE(ElementPtr); IPROC =
  333. PROCEDURE(); CompareProc = PROCEDURE(ADDRESS,ADDRESS,CARDINAL)
  334. : CompareType; *)
  335. ProcType<VAR t: SymTab.TypeIndex> (. VAR b: SymTab.TypeIndex; .)
  336. = "PROCEDURE" (. t := SymTab.InvalidType;
  337. SemError(230); .)
  338. [ "(" [ ProcTypeParam { ","
  339. ProcTypeParam } ] ")" ]
  340. [ ":" TypeIdent2<b> (. SemError(230); .) ] .
  341. ProcTypeParam (. VAR b: SymTab.TypeIndex; .)
  342. = [ "VAR" ] Type<b> (. SemError(230); .) .
  343. (* Clarion-form classes (docs/OOP.txt): declaration + (single or
  344. multiple) parent clause + IMPLEMENTATION blocks. Scopes and
  345. member checks now; lowering (vtable, dispatch, THIS) later —
  346. one 230 per class/impl block. Methods end with ";" per the
  347. Table example. *)
  348. (* Single CLASS item in both loops: separating declaration from
  349. IMPLEMENTATION at the loop level needs 2-token lookahead
  350. (CLASS ident vs CLASS IMPLEMENTATION), which LL(1) cannot do.
  351. The second token decides after CLASS is consumed. *)
  352. ClassItem
  353. = "CLASS" ( "IMPLEMENTATION" ClassImplRest | ClassRest ) .
  354. ClassRest (. VAR cn, m2, pn, q: SymTab.Name;
  355. ct: SymTab.TypeIndex; .)
  356. = GetIdent<cn> (. IF ~SymTab.Enter(cn,
  357. SymTab.KindType) THEN
  358. SemError(200) END;
  359. ct := SymTab.NewClass();
  360. SymTab.SetSymType(cn, ct);
  361. SymTab.PushClassScope(ct); .)
  362. [ Parents<ct> ]
  363. ";"
  364. { ClassField<ct> ";" }
  365. (* V3 class methods: pure declaration (';' only), FORWARD, or a
  366. fully bodied method whose body starts with BEGIN (the corpus
  367. form). Each bodied/FORWARD method owns its trailing ';'. *)
  368. { MethodHeading<pn> ";"
  369. ( "FORWARD" (. SymTab.MarkFwd;
  370. SymTab.CloseProc; .)
  371. ";"
  372. | "BEGIN" [ StatSeq ] "END"
  373. GetIdent<q> (. IF ~SymTab.Equal(pn, q) THEN
  374. SemError(202) END;
  375. SymTab.CloseProc;
  376. SemError(230); .)
  377. ";"
  378. | (. SymTab.CloseProc; .) ) }
  379. [ "BEGIN" (. SemError(230); .)
  380. [ StatSeq ] ]
  381. "END"
  382. GetIdent<m2> (. IF ~SymTab.Equal(cn, m2) THEN
  383. SemError(202) END;
  384. SymTab.PopScope;
  385. SemError(230); .) .
  386. (* V3 class header may list several parents
  387. (CLASS GenElem (Element, Base2);); this grammar accepts the
  388. list and rejects every parent after the first at 230 — the
  389. current backend lowers single inheritance only. *)
  390. Parents<ct: SymTab.TypeIndex> (. VAR p: SymTab.Name; .)
  391. = "(" Parent1<ct>
  392. { "," GetIdent<p> (. SemError(230); .) }
  393. ")" .
  394. Parent1<ct: SymTab.TypeIndex> (. VAR p: SymTab.Name;
  395. pt: SymTab.TypeIndex; .)
  396. = GetIdent<p> (. IF ~SymTab.Lookup(p) THEN
  397. SemError(201)
  398. ELSE pt := SymTab.SymType(p);
  399. IF SymTab.ClassOf(pt) #
  400. SymTab.ClClass THEN
  401. SemError(230)
  402. ELSE SymTab.SetParent(ct, pt)
  403. END
  404. END; .) .
  405. ClassField<ct: SymTab.TypeIndex> (. VAR n, rhs: SymTab.Name;
  406. t: SymTab.TypeIndex; .)
  407. = GetIdent<n>
  408. ( "=" GetIdent<rhs> (. IF ~SymTab.Enter(n,
  409. SymTab.KindConst) THEN
  410. SemError(200) END;
  411. IF SymTab.Lookup(rhs) THEN
  412. SymTab.SetSymType(n,
  413. SymTab.SymType(rhs))
  414. END; .)
  415. | (. IF ~SymTab.FieldPending(ct,
  416. n) THEN
  417. SemError(200) END; .)
  418. { "," GetIdent<n> (. IF ~SymTab.FieldPending(ct,
  419. n) THEN
  420. SemError(200) END; .) }
  421. ":" TypeIdent2<t> (. SymTab.FixPendingF(ct, t); .) ) .
  422. MethodHeading<VAR pn: SymTab.Name> (. VAR wantVirt: BOOLEAN; .)
  423. = (. wantVirt := FALSE; .)
  424. [ "VIRTUAL" (. wantVirt := TRUE; .) ]
  425. ProcHeading<pn> (. IF wantVirt THEN
  426. SymTab.MarkVirtual END; .) .
  427. ClassImplRest (. VAR cn, m2: SymTab.Name;
  428. ct: SymTab.TypeIndex; .)
  429. = GetIdent<cn> (. IF ~SymTab.Lookup(cn) THEN
  430. SemError(201);
  431. ct := SymTab.InvalidType
  432. ELSE ct := SymTab.SymType(cn);
  433. IF SymTab.ClassOf(ct) #
  434. SymTab.ClClass THEN
  435. SemError(230);
  436. ct := SymTab.InvalidType
  437. END
  438. END;
  439. IF ct #
  440. SymTab.InvalidType THEN
  441. IF ~SymTab.PushClassMembers(
  442. ct) THEN
  443. SemError(230) END
  444. END; .)
  445. ";" { MethodImpl<ct> ";" }
  446. [ "BEGIN" (. QbeGen.BeginBody; .)
  447. [ StatSeq ] ]
  448. "END"
  449. GetIdent<m2> (. IF ~SymTab.Equal(cn, m2) THEN
  450. SemError(202) END;
  451. SymTab.PopScope;
  452. SemError(230); .) .
  453. MethodImpl<ct: SymTab.TypeIndex> (. VAR pn: SymTab.Name; .)
  454. = MethodHeading<pn> ";"
  455. (. IF (ct #
  456. SymTab.InvalidType)
  457. & ~SymTab.MethodExists(ct,
  458. pn) THEN
  459. SemError(201) END; .)
  460. ( "FORWARD" (. SymTab.MarkFwd;
  461. SymTab.CloseProc; .)
  462. | Block<pn> (. SymTab.CloseProc;
  463. SemError(230); .) ) .
  464. (* E1) double-colon constant alias: Name ::= Expr ;
  465. GCoord::=INTEGER; TXBuffer ::= IOBase; *)
  466. ConstBlock
  467. = "CONST" { ConstDecl ";" } .
  468. ConstDecl (. VAR n: SymTab.Name;
  469. t: SymTab.TypeIndex;
  470. qv: QbeGen.QVal;
  471. cls: INTEGER; .)
  472. = GetIdent<n> (. IF ~SymTab.Enter(n,
  473. SymTab.KindConst) THEN
  474. SemError(200) END; .)
  475. ( "::=" (. SemError(230); .)
  476. Expr<t, qv> (. SymTab.SetSymType(n, t);
  477. QbeGen.DeclConst(n, "0",
  478. SymTab.InvalidType); .)
  479. | "="
  480. Expr<t, qv> (. SymTab.SetSymType(n, t);
  481. cls := SymTab.ClassOf(t);
  482. IF cls = SymTab.ClStr THEN
  483. SemError(230)
  484. ELSIF ~QbeGen.IsImm(qv) THEN
  485. SemError(230) END;
  486. QbeGen.DeclConst(n, qv, t); .) ) .
  487. VarBlock
  488. = "VAR" { VarDecl ";" } .
  489. VarDecl (. VAR nm: SymTab.Name;
  490. t: SymTab.TypeIndex;
  491. i: CARDINAL;
  492. cls: INTEGER; .)
  493. = VarIdents ":"
  494. (* V3 VAR types may be composites; the scalar phase lowers the
  495. integer/char/bool/real family and reports 230 for the rest. *)
  496. Type<t> (. cls := SymTab.ClassOf(t);
  497. IF (t # SymTab.InvalidType)
  498. & (cls # SymTab.ClInt)
  499. & (cls # SymTab.ClBool)
  500. & (cls # SymTab.ClChar)
  501. & (cls # SymTab.ClReal) THEN
  502. SemError(230) END;
  503. i := 0;
  504. WHILE i < SymTab.PendCount() DO
  505. SymTab.PendName(i, nm);
  506. QbeGen.DeclVar(nm, t);
  507. INC(i)
  508. END;
  509. SymTab.FixPending(t); .) .
  510. VarIdents (. VAR n: SymTab.Name;
  511. t: SymTab.TypeIndex;
  512. q: QbeGen.QVal; .)
  513. = GetIdent<n> (. IF ~SymTab.EnterPending(n,
  514. SymTab.KindVar) THEN
  515. SemError(200) END; .)
  516. [ "[" Expr<t, q> (. SemError(230); .)
  517. [ ":" Expr<t, q> (. SemError(230); .) ]
  518. "]" ]
  519. { ","
  520. GetIdent<n> (. IF ~SymTab.EnterPending(n,
  521. SymTab.KindVar) THEN
  522. SemError(200) END; .)
  523. [ "[" Expr<t, q> (. SemError(230); .)
  524. [ ":" Expr<t, q> (. SemError(230); .) ]
  525. "]" ] } .
  526. ParIdents<isV: BOOLEAN> (. VAR n: SymTab.Name; .)
  527. = GetIdent<n> (. IF ~SymTab.EnterParam(n, isV) THEN
  528. SemError(200) END; .)
  529. { "," GetIdent<n> (. IF ~SymTab.EnterParam(n, isV) THEN
  530. SemError(200) END; .) } .
  531. (* Procedure headings enter now (scopes, params, result); bodies
  532. parse + check with one 230 at END (lowering = step 4).
  533. FORWARD marks; the body heading re-enters (signature compare
  534. tightens in step 4). *)
  535. ProcHeading<VAR pn: SymTab.Name> (. VAR t: SymTab.TypeIndex; .)
  536. = "PROCEDURE"
  537. GetIdent<pn> (. IF ~SymTab.EnterProc(pn) THEN
  538. IF ~SymTab.ReenterProc(pn) THEN
  539. SemError(200) END
  540. END; .)
  541. [ FormalParams ]
  542. [ ":" TypeIdent2<t> (. SymTab.SetProcRes(t); .) ] .
  543. FormalParams
  544. = "(" [ ParamSection { ";" ParamSection } ] ")" .
  545. ParamSection (. VAR t: SymTab.TypeIndex;
  546. isV: BOOLEAN; .)
  547. = (. isV := FALSE; .)
  548. [ "VAR" (. isV := TRUE; .) ]
  549. ParIdents<isV> ":" Type<t> (. SymTab.FixPending(t); .) .
  550. ProcDecl (. VAR pn, assem: SymTab.Name;
  551. at: SymTab.TypeIndex;
  552. ak: INTEGER;
  553. aq: QbeGen.QVal; .)
  554. = ProcHeading<pn>
  555. ( ";"
  556. ( "FORWARD" (. SymTab.MarkFwd;
  557. SymTab.CloseProc; .)
  558. | "IN" GetIdent<assem> (. SymTab.CloseProc;
  559. SemError(230); .)
  560. | Block<pn> (. SymTab.CloseProc;
  561. SemError(230); .) )
  562. | "=" Design<at, ak, aq, assem> (. SymTab.CloseProc;
  563. SemError(230); .)
  564. "(" [ ActualParams ] ")" ) .
  565. Block<pn: SymTab.Name> (. VAR m2: SymTab.Name; .)
  566. = DeclSeq
  567. [ "BEGIN"
  568. [ StatSeq ] ]
  569. "END"
  570. GetIdent<m2> (. IF ~SymTab.Equal(pn, m2) THEN
  571. SemError(202) END; .) .
  572. StatSeq
  573. = Statement { ";" [ Statement ] } .
  574. (* Statements. Assignments and procedure/function calls both start
  575. with a designator, so they share one factored production: after
  576. the designator, ':=' selects assignment, '(' a call, anything
  577. else is a parameterless procedure-call statement. *)
  578. Statement (. VAR lx: QbeGen.QVal;
  579. lqn: SymTab.Name; .)
  580. = DesignStat
  581. | IfStat
  582. | WhileStat
  583. | RepeatStat
  584. | LoopStat
  585. | ForStat
  586. | CaseStat
  587. | WithStat
  588. | ReturnStat
  589. | "GOTO" GetIdent<lqn> (. SemError(230); .)
  590. | "EXIT" (. IF QbeGen.TopLoop(lx) THEN
  591. QbeGen.Jmp(lx)
  592. ELSE SemError(230) END; .) .
  593. DesignStat (. VAR dt, et: SymTab.TypeIndex;
  594. dk: INTEGER;
  595. qd, qe, qt: QbeGen.QVal;
  596. qn: SymTab.Name;
  597. isR, conv: BOOLEAN; .)
  598. = Design2<dt, dk, qd, qn>
  599. ( ":=" Expr<et, qe> (. IF (dt # SymTab.InvalidType)
  600. & (dk # SymTab.KindVar)
  601. & (dk # SymTab.KindParam) THEN
  602. SemError(210)
  603. ELSIF ~SymTab.Assignable(et,
  604. dt) THEN
  605. SemError(210) END;
  606. isR := (dt #
  607. SymTab.InvalidType)
  608. & (SymTab.ClassOf(dt)
  609. = SymTab.ClReal);
  610. conv := isR
  611. & SymTab.IsIntFamily(et);
  612. IF ((dk = SymTab.KindVar)
  613. OR (dk = SymTab.KindParam))
  614. & (dt # SymTab.InvalidType)
  615. & (et # SymTab.InvalidType) THEN
  616. IF conv THEN
  617. QbeGen.ConvIR(qe, qt);
  618. QbeGen.StoreVar(qn, qt, TRUE)
  619. ELSE
  620. QbeGen.StoreVar(qn, qe, isR)
  621. END
  622. END; .)
  623. | "(" [ ActualParams ] ")" (. SemError(230); .)
  624. | (. SemError(230); .) ) .
  625. ActualParams (. VAR t: SymTab.TypeIndex;
  626. q: QbeGen.QVal; .)
  627. = Expr<t, q> { "," Expr<t, q> } .
  628. IfStat (. VAR t: SymTab.TypeIndex;
  629. q, lThen, lElse, lEnd:
  630. QbeGen.QVal;
  631. hasElse: BOOLEAN; .)
  632. = "IF" (. hasElse := FALSE; .)
  633. Expr<t, q> (. IF ~SymTab.BoolCheck(t) THEN
  634. SemError(214) END;
  635. QbeGen.NewLabel(lThen);
  636. QbeGen.NewLabel(lElse);
  637. QbeGen.NewLabel(lEnd);
  638. QbeGen.Jnz(q, lThen, lElse);
  639. QbeGen.EmitLabel(lThen); .)
  640. "THEN" [ StatSeq ] (. QbeGen.Jmp(lEnd); .)
  641. { "ELSIF" (. QbeGen.EmitLabel(lElse);
  642. QbeGen.NewLabel(lElse); .)
  643. Expr<t, q> (. IF ~SymTab.BoolCheck(t) THEN
  644. SemError(214) END;
  645. QbeGen.NewLabel(lThen);
  646. QbeGen.Jnz(q, lThen, lElse);
  647. QbeGen.EmitLabel(lThen); .)
  648. "THEN" [ StatSeq ] (. QbeGen.Jmp(lEnd); .) }
  649. [ "ELSE" (. QbeGen.EmitLabel(lElse);
  650. hasElse := TRUE; .)
  651. [ StatSeq ] ]
  652. "END" (. IF hasElse THEN
  653. QbeGen.EmitLabel(lEnd)
  654. ELSE QbeGen.EmitLabel(lElse);
  655. QbeGen.EmitLabel(lEnd)
  656. END; .) .
  657. WhileStat (. VAR t: SymTab.TypeIndex;
  658. q, lTop, lBody, lEnd:
  659. QbeGen.QVal; .)
  660. = "WHILE" (. QbeGen.NewLabel(lTop);
  661. QbeGen.NewLabel(lBody);
  662. QbeGen.NewLabel(lEnd);
  663. QbeGen.EmitLabel(lTop); .)
  664. Expr<t, q> (. IF ~SymTab.BoolCheck(t) THEN
  665. SemError(214) END;
  666. QbeGen.Jnz(q, lBody, lEnd);
  667. QbeGen.EmitLabel(lBody); .)
  668. "DO" [ StatSeq ] (. QbeGen.Jmp(lTop); .)
  669. "END" (. QbeGen.EmitLabel(lEnd); .) .
  670. RepeatStat (. VAR t: SymTab.TypeIndex;
  671. q, lTop, lEnd: QbeGen.QVal; .)
  672. = "REPEAT" (. QbeGen.NewLabel(lTop);
  673. QbeGen.NewLabel(lEnd);
  674. QbeGen.EmitLabel(lTop); .)
  675. [ StatSeq ]
  676. "UNTIL" Expr<t, q> (. IF ~SymTab.BoolCheck(t) THEN
  677. SemError(214) END;
  678. QbeGen.Jnz(q, lEnd, lTop);
  679. QbeGen.EmitLabel(lEnd); .) .
  680. LoopStat (. VAR lTop, lEnd: QbeGen.QVal; .)
  681. = "LOOP" (. QbeGen.NewLabel(lTop);
  682. QbeGen.NewLabel(lEnd);
  683. QbeGen.PushLoop(lEnd);
  684. QbeGen.EmitLabel(lTop); .)
  685. [ StatSeq ]
  686. "END" (. QbeGen.Jmp(lTop);
  687. QbeGen.PopLoop;
  688. QbeGen.EmitLabel(lEnd); .) .
  689. (* FOR with static-sign BY (literal, non-zero; 220 otherwise).
  690. Runtime direction would need a compare-select; the literal
  691. sign picks cslew/csegew at "DO" time. *)
  692. ForStat (. VAR lv: SymTab.Name;
  693. tlo, thi, tby:
  694. SymTab.TypeIndex;
  695. qlo, qhi, qby, qt, qk, qb:
  696. QbeGen.QVal;
  697. lTop, lBody, lEnd:
  698. QbeGen.QVal;
  699. by: INTEGER;
  700. ok: BOOLEAN; .)
  701. = "FOR" (. by := 1; .)
  702. GetIdent<lv> (. ok := SymTab.Lookup(lv);
  703. IF ~ok THEN
  704. SemError(201)
  705. ELSIF (SymTab.SymKind(lv) #
  706. SymTab.KindVar)
  707. & (SymTab.SymKind(lv) #
  708. SymTab.KindParam) THEN
  709. SemError(220); ok := FALSE
  710. ELSIF ~SymTab.IsIntFamily(
  711. SymTab.SymType(lv)) THEN
  712. SemError(220); ok := FALSE
  713. END; .)
  714. ":=" Expr<tlo, qlo> (. IF ~SymTab.IsIntFamily(tlo) THEN
  715. SemError(220); ok := FALSE
  716. END; .)
  717. "TO" Expr<thi, qhi> (. IF ~SymTab.IsIntFamily(thi) THEN
  718. SemError(220); ok := FALSE
  719. END; .)
  720. [ "BY" Expr<tby, qby> (. IF (tby #
  721. SymTab.InvalidType)
  722. & ~SymTab.IsIntFamily(tby) THEN
  723. SemError(220); ok := FALSE
  724. END;
  725. IF ~SymTab.ConstInt(qby, by) THEN
  726. SemError(230); by := 1
  727. ELSIF by = 0 THEN
  728. SemError(220); by := 1
  729. END; .) ]
  730. "DO" (. IF ok THEN
  731. QbeGen.StoreVar(lv, qlo,
  732. FALSE) END;
  733. QbeGen.NewLabel(lTop);
  734. QbeGen.NewLabel(lBody);
  735. QbeGen.NewLabel(lEnd);
  736. QbeGen.EmitLabel(lTop);
  737. QbeGen.LoadVar(lv, FALSE, qt);
  738. QbeGen.NewTemp(qk);
  739. IF by > 0 THEN
  740. QbeGen.Op3("cslew", qk,
  741. qt, qhi, FALSE)
  742. ELSE QbeGen.Op3("csgew", qk,
  743. qt, qhi, FALSE)
  744. END;
  745. QbeGen.Jnz(qk, lBody, lEnd);
  746. QbeGen.EmitLabel(lBody); .)
  747. [ StatSeq ]
  748. "END" (. IF ok THEN
  749. QbeGen.LoadVar(lv, FALSE,
  750. qt);
  751. QbeGen.IntStr(by, qb);
  752. QbeGen.NewTemp(qk);
  753. QbeGen.Op3("add", qk,
  754. qt, qb, FALSE);
  755. QbeGen.StoreVar(lv, qk,
  756. FALSE) END;
  757. QbeGen.Jmp(lTop);
  758. QbeGen.EmitLabel(lEnd); .) .
  759. CaseStat (. VAR tsel: SymTab.TypeIndex;
  760. qsel, lEnd: QbeGen.QVal; .)
  761. = "CASE" Expr<tsel, qsel> (. QbeGen.NewLabel(lEnd); .)
  762. "OF" [ "|" ]
  763. { CaseAlt<tsel, qsel, lEnd>
  764. [ ";" ] [ "|" ] }
  765. [ "ELSE" [ StatSeq ] ]
  766. "END" (. QbeGen.EmitLabel(lEnd); .) .
  767. (* Compare-chain lowering: each alternative ends its match-tests
  768. with "jmp lAfter", so the no-match fallthrough skips the body:
  769. "cmp; jnz(lBody,lF); lF: ... ; jmp lAfter; lBody: S; jmp lEnd;
  770. lAfter:". Falls into the next alternative, ELSE, or END. *)
  771. CaseAlt<tsel: SymTab.TypeIndex; qsel: QbeGen.QVal;
  772. lEnd: QbeGen.QVal> (. VAR lBody, lAfter: QbeGen.QVal; .)
  773. = (. QbeGen.NewLabel(lBody);
  774. QbeGen.NewLabel(lAfter); .)
  775. CaseLabel<tsel, qsel, lBody>
  776. { "," CaseLabel<tsel, qsel, lBody> }
  777. ":" (. QbeGen.Jmp(lAfter);
  778. QbeGen.EmitLabel(lBody); .)
  779. [ StatSeq (. QbeGen.Jmp(lEnd); .) ]
  780. (. QbeGen.EmitLabel(lAfter); .) .
  781. CaseLabel<tsel: SymTab.TypeIndex; qsel: QbeGen.QVal;
  782. lBody: QbeGen.QVal> (. VAR t2, t3: SymTab.TypeIndex;
  783. q2, q3, qc, qd, qe:
  784. QbeGen.QVal;
  785. lNext: QbeGen.QVal; .)
  786. = Expr<t2, q2> (. IF (t2 #
  787. SymTab.InvalidType)
  788. & (tsel #
  789. SymTab.InvalidType)
  790. & ~SymTab.EqCheck(t2,
  791. tsel) THEN
  792. SemError(213) END;
  793. IF ~QbeGen.IsImm(q2) THEN
  794. SemError(230);
  795. QbeGen.CopyOp("0", q2)
  796. END;
  797. QbeGen.NewLabel(lNext);
  798. QbeGen.Cmp(SymTab.OpEq,
  799. qsel, q2, qc, FALSE);
  800. QbeGen.Jnz(qc, lBody, lNext);
  801. QbeGen.EmitLabel(lNext); .)
  802. [ ".." Expr<t3, q3> (. IF (t3 #
  803. SymTab.InvalidType)
  804. & (tsel #
  805. SymTab.InvalidType)
  806. & ~SymTab.EqCheck(t3,
  807. tsel) THEN
  808. SemError(213) END;
  809. IF ~QbeGen.IsImm(q3) THEN
  810. SemError(230);
  811. QbeGen.CopyOp("0", q3)
  812. END;
  813. QbeGen.Cmp(SymTab.OpGe,
  814. qsel, q2, qc, FALSE);
  815. QbeGen.Cmp(SymTab.OpLe,
  816. qsel, q3, qd, FALSE);
  817. QbeGen.NewTemp(qe);
  818. QbeGen.Op3("and", qe, qc, qd,
  819. FALSE);
  820. QbeGen.NewLabel(lNext);
  821. QbeGen.Jnz(qe, lBody, lNext);
  822. QbeGen.EmitLabel(lNext); .) ] .
  823. ReturnStat (. VAR t: SymTab.TypeIndex;
  824. q: QbeGen.QVal;
  825. res: SymTab.TypeIndex;
  826. hadE: BOOLEAN; .)
  827. = "RETURN" (. hadE := FALSE; .)
  828. [ Expr<t, q> (. hadE := TRUE; .) ]
  829. (. IF ~SymTab.InProc() THEN
  830. SemError(232)
  831. ELSE res := SymTab.CurRes();
  832. IF ~hadE THEN
  833. IF res #
  834. SymTab.InvalidType THEN
  835. SemError(232) END
  836. ELSIF (res =
  837. SymTab.InvalidType)
  838. OR (t #
  839. SymTab.InvalidType)
  840. & ~SymTab.Assignable(t,
  841. res) THEN
  842. SemError(232)
  843. END
  844. END; .) .
  845. (* WITH pushes the record's fields as an inner scope (classic
  846. short-hand member access); record lowering is still 230. *)
  847. WithStat (. VAR t: SymTab.TypeIndex;
  848. k: INTEGER;
  849. q: QbeGen.QVal;
  850. qn: SymTab.Name; .)
  851. = "WITH" Design2<t, k, q, qn> (. IF ~SymTab.PushRecord(t) THEN
  852. SemError(230) END; .)
  853. "DO" [ StatSeq ]
  854. "END" (. SymTab.PopScope;
  855. SemError(230); .) .
  856. (* Designators (E3): simple names behave exactly like the scalar
  857. phase; '.' '^' '[' selector chains parse and report one 230
  858. (member/pointer/array lowering arrives with step 3). *)
  859. Design<VAR t: SymTab.TypeIndex; VAR k: INTEGER;
  860. VAR q: QbeGen.QVal; VAR qn: SymTab.Name>
  861. (. VAR n: SymTab.Name;
  862. cls: INTEGER; .)
  863. = GetIdent<n> (. QbeGen.CopyOp(n, qn);
  864. IF ~SymTab.Lookup(n) THEN
  865. SemError(201);
  866. t := SymTab.InvalidType;
  867. k := -1;
  868. QbeGen.CopyOp("0", q)
  869. ELSE
  870. t := SymTab.SymType(n);
  871. k := SymTab.SymKind(n);
  872. IF k = SymTab.KindConst THEN
  873. IF SymTab.Equal(n,
  874. "TRUE") THEN
  875. t := SymTab.BoolType();
  876. QbeGen.CopyOp("1", q)
  877. ELSIF SymTab.Equal(n,
  878. "FALSE") THEN
  879. t := SymTab.BoolType();
  880. QbeGen.CopyOp("0", q)
  881. ELSE
  882. cls := SymTab.ClassOf(t);
  883. IF (t # SymTab.InvalidType)
  884. & ((cls = SymTab.ClInt)
  885. OR (cls = SymTab.ClChar)
  886. OR (cls = SymTab.ClReal)) THEN
  887. QbeGen.LoadVar(n,
  888. cls = SymTab.ClReal, q)
  889. ELSE
  890. IF t # SymTab.InvalidType
  891. THEN SemError(230)
  892. END;
  893. QbeGen.CopyOp("0", q)
  894. END
  895. END
  896. ELSIF (k = SymTab.KindVar)
  897. OR (k = SymTab.KindParam) THEN
  898. cls := SymTab.ClassOf(t);
  899. IF (cls = SymTab.ClInt)
  900. OR (cls = SymTab.ClBool)
  901. OR (cls = SymTab.ClChar)
  902. OR (cls = SymTab.ClReal) THEN
  903. QbeGen.LoadVar(n,
  904. cls = SymTab.ClReal, q)
  905. ELSE SemError(230);
  906. QbeGen.CopyOp("0", q)
  907. END
  908. ELSE QbeGen.CopyOp("0", q);
  909. IF (k = SymTab.KindImport)
  910. OR (k = SymTab.KindProc)
  911. OR (k = SymTab.KindField) THEN
  912. SemError(230)
  913. END
  914. END
  915. END; .) .
  916. Design2<VAR t: SymTab.TypeIndex; VAR k: INTEGER;
  917. VAR q: QbeGen.QVal; VAR qn: SymTab.Name>
  918. = Design<t, k, q, qn>
  919. { "." GetIdent<qn> (. SemError(230);
  920. t := SymTab.InvalidType; .)
  921. | "^" (. SemError(230);
  922. t := SymTab.InvalidType; .)
  923. | "[" ExprList "]" (. SemError(230);
  924. t := SymTab.InvalidType; .)
  925. | "(" [ ActualParams ] ")" (. SemError(230);
  926. t := SymTab.InvalidType; .) } .
  927. ExprList (. VAR t: SymTab.TypeIndex;
  928. q: QbeGen.QVal; .)
  929. = Expr<t, q> { "," Expr<t, q> } .
  930. (* Expressions. After SimExpr the optional suffix is decided by a
  931. distinct first token: relation (= # <> < <= > >=), IN, or IS. *)
  932. Expr<VAR t: SymTab.TypeIndex; VAR q: QbeGen.QVal>
  933. (. VAR t2: SymTab.TypeIndex;
  934. op: INTEGER;
  935. q2, qt: QbeGen.QVal;
  936. isR: BOOLEAN; .)
  937. = SimExpr<t, q>
  938. [ Rel<op> SimExpr<t2, q2>
  939. (. IF SymTab.RelCheck(t, t2, op) THEN
  940. isR := SymTab.ClassOf(t) = SymTab.ClReal;
  941. t := SymTab.BoolType()
  942. ELSE SemError(213); t := SymTab.InvalidType;
  943. isR := FALSE END;
  944. IF t # SymTab.InvalidType THEN
  945. QbeGen.Cmp(op, q, q2, qt, isR);
  946. QbeGen.CopyOp(qt, q)
  947. ELSE QbeGen.CopyOp("0", q)
  948. END; .)
  949. | "IN" SimExpr<t2, q2> (. IF ~SymTab.InCheck(t, t2) THEN
  950. SemError(222) END;
  951. SemError(230);
  952. QbeGen.CopyOp("0", q);
  953. t := SymTab.InvalidType; .)
  954. | "IS" TypeIdent2<t2> (. SemError(213);
  955. SemError(230);
  956. QbeGen.CopyOp("0", q);
  957. t := SymTab.InvalidType; .) ] .
  958. (* V3 relations keep both PIM '#" and the '<>' alias. *)
  959. Rel<VAR op: INTEGER>
  960. = "=" (. op := SymTab.OpEq; .)
  961. | "#" (. op := SymTab.OpNeq1; .)
  962. | "<>" (. op := SymTab.OpNeq1; .)
  963. | "<" (. op := SymTab.OpLt; .)
  964. | "<=" (. op := SymTab.OpLe; .)
  965. | ">" (. op := SymTab.OpGt; .)
  966. | ">=" (. op := SymTab.OpGe; .) .
  967. SimExpr<VAR t: SymTab.TypeIndex; VAR q: QbeGen.QVal>
  968. (. VAR t2, res2: SymTab.TypeIndex;
  969. op: INTEGER;
  970. q2, qt: QbeGen.QVal;
  971. neg, isR: BOOLEAN; .)
  972. = (. neg := FALSE; .)
  973. [ "+" | "-" (. neg := TRUE; .) ]
  974. Term<t, q> (. IF neg THEN
  975. IF QbeGen.IsImm(q) THEN
  976. QbeGen.NegFold(q, q)
  977. ELSE QbeGen.NewTemp(qt);
  978. QbeGen.NegQ(q, qt,
  979. SymTab.ClassOf(t)
  980. = SymTab.ClReal);
  981. QbeGen.CopyOp(qt, q)
  982. END
  983. END; .)
  984. { AddOp<op> Term<t2, q2>
  985. (. IF op = SymTab.OpOr THEN
  986. IF SymTab.BoolCheck(t) & SymTab.BoolCheck(t2) THEN
  987. t := SymTab.BoolType()
  988. ELSE SemError(212); t := SymTab.InvalidType END;
  989. IF t # SymTab.InvalidType THEN
  990. QbeGen.NewTemp(qt);
  991. QbeGen.Op3("or", qt, q, q2, FALSE);
  992. QbeGen.CopyOp(qt, q)
  993. ELSE QbeGen.CopyOp("0", q)
  994. END
  995. ELSE
  996. IF SymTab.ArithCheck(t, t2, FALSE, res2) THEN
  997. t := res2
  998. ELSE SemError(211); t := SymTab.InvalidType END;
  999. isR := SymTab.ClassOf(t) = SymTab.ClReal;
  1000. IF t # SymTab.InvalidType THEN
  1001. QbeGen.NewTemp(qt);
  1002. IF op = SymTab.OpAdd THEN
  1003. QbeGen.Op3("add", qt, q, q2, isR)
  1004. ELSE
  1005. QbeGen.Op3("sub", qt, q, q2, isR)
  1006. END;
  1007. QbeGen.CopyOp(qt, q)
  1008. ELSE QbeGen.CopyOp("0", q)
  1009. END
  1010. END; .) } .
  1011. AddOp<VAR op: INTEGER>
  1012. = "+" (. op := SymTab.OpAdd; .)
  1013. | "-" (. op := SymTab.OpSub; .)
  1014. | "OR" (. op := SymTab.OpOr; .) .
  1015. (* Term holds multiplication, AND (word or '&'), and the V3 shift
  1016. operators << >>. MulOp start symbols are all distinct. *)
  1017. Term<VAR t: SymTab.TypeIndex; VAR q: QbeGen.QVal>
  1018. (. VAR t2, res2: SymTab.TypeIndex;
  1019. op: INTEGER;
  1020. q2, qt: QbeGen.QVal;
  1021. isR: BOOLEAN; .)
  1022. = Fact<t, q> { MulOp<op> Fact<t2, q2>
  1023. (. IF (op = SymTab.OpAnd) THEN
  1024. IF SymTab.BoolCheck(t) & SymTab.BoolCheck(t2) THEN
  1025. t := SymTab.BoolType()
  1026. ELSE SemError(212); t := SymTab.InvalidType END;
  1027. IF t # SymTab.InvalidType THEN
  1028. QbeGen.NewTemp(qt);
  1029. QbeGen.Op3("and", qt, q, q2, FALSE);
  1030. QbeGen.CopyOp(qt, q)
  1031. ELSE QbeGen.CopyOp("0", q)
  1032. END
  1033. ELSIF (op = 10) OR (op = 11) THEN
  1034. (* << and >> : V3 word shifts; QBE shl/sar. *)
  1035. IF ~SymTab.IsIntFamily(t) OR ~SymTab.IsIntFamily(t2) THEN
  1036. SemError(211); t := SymTab.InvalidType END;
  1037. IF t # SymTab.InvalidType THEN
  1038. QbeGen.NewTemp(qt);
  1039. IF op = 10 THEN QbeGen.Op3("shl", qt, q, q2, FALSE)
  1040. ELSE QbeGen.Op3("sar", qt, q, q2, FALSE) END;
  1041. QbeGen.CopyOp(qt, q)
  1042. ELSE QbeGen.CopyOp("0", q)
  1043. END
  1044. ELSE
  1045. IF SymTab.ArithCheck(t, t2,
  1046. (op = SymTab.OpDiv) OR (op = SymTab.OpMod),
  1047. res2) THEN t := res2
  1048. ELSE SemError(211); t := SymTab.InvalidType END;
  1049. isR := SymTab.ClassOf(t) = SymTab.ClReal;
  1050. IF t # SymTab.InvalidType THEN
  1051. QbeGen.NewTemp(qt);
  1052. IF op = SymTab.OpTimes THEN
  1053. QbeGen.Op3("mul", qt, q, q2, isR)
  1054. ELSIF (op = SymTab.OpDiv)
  1055. OR (op = SymTab.OpSlash) THEN
  1056. QbeGen.Op3("div", qt, q, q2, isR)
  1057. ELSE
  1058. QbeGen.Op3("rem", qt, q, q2, isR)
  1059. END;
  1060. QbeGen.CopyOp(qt, q)
  1061. ELSE QbeGen.CopyOp("0", q)
  1062. END
  1063. END; .) } .
  1064. MulOp<VAR op: INTEGER>
  1065. = "*" (. op := SymTab.OpTimes; .)
  1066. | "/" (. op := SymTab.OpSlash; .)
  1067. | "DIV" (. op := SymTab.OpDiv; .)
  1068. | "MOD" (. op := SymTab.OpMod; .)
  1069. | "AND" (. op := SymTab.OpAnd; .)
  1070. | "&" (. op := SymTab.OpAnd; .)
  1071. | "<<" (. op := 10; .)
  1072. | ">>" (. op := 11; .) .
  1073. Fact<VAR t: SymTab.TypeIndex; VAR q: QbeGen.QVal>
  1074. (. VAR s: ARRAY [0 .. 255] OF CHAR;
  1075. et, dt, t2, b:
  1076. SymTab.TypeIndex;
  1077. dk: INTEGER;
  1078. qd, q2: QbeGen.QVal;
  1079. qn: SymTab.Name;
  1080. isCh: BOOLEAN; .)
  1081. = integer (. LexString(s);
  1082. QbeGen.NormLit(s, q, isCh);
  1083. IF isCh THEN
  1084. t := SymTab.CharType()
  1085. ELSE t := SymTab.IntType()
  1086. END; .)
  1087. | real (. LexString(s);
  1088. QbeGen.NormReal(s, q);
  1089. t := SymTab.RealType(); .)
  1090. | string (. LexString(s);
  1091. IF SymTab.StrLen(s) <= 3 THEN
  1092. t := SymTab.CharType();
  1093. QbeGen.IntStr(
  1094. QbeGen.CharVal(s), q)
  1095. ELSE t := SymTab.NewStr();
  1096. SemError(230);
  1097. QbeGen.CopyOp("0", q)
  1098. END; .)
  1099. | "{" [ SetItems ] "}" (. SemError(230);
  1100. QbeGen.CopyOp("0", q);
  1101. t := SymTab.InvalidType; .)
  1102. | "[" Expr<et, q> ":" Expr<t2, q2>
  1103. (. SemError(230);
  1104. QbeGen.CopyOp("0", q);
  1105. t := SymTab.InvalidType; .)
  1106. [ TypeIdent2<b> ] "]"
  1107. MapTail
  1108. | Design2<dt, dk, qd, qn> (. t := dt;
  1109. QbeGen.CopyOp(qd, q); .)
  1110. | "(" Expr<et, q> ")" (. t := et; .)
  1111. | "NOT" Fact<t2, q2> (. IF SymTab.BoolCheck(t2) THEN
  1112. t := SymTab.BoolType()
  1113. ELSE SemError(212);
  1114. t := SymTab.InvalidType END;
  1115. IF t # SymTab.InvalidType THEN
  1116. QbeGen.NotQ(q2, q)
  1117. ELSE QbeGen.CopyOp("0", q)
  1118. END; .)
  1119. | "~" Fact<t2, q2> (. IF SymTab.BoolCheck(t2) THEN
  1120. t := SymTab.BoolType()
  1121. ELSE SemError(212);
  1122. t := SymTab.InvalidType END;
  1123. IF t # SymTab.InvalidType THEN
  1124. QbeGen.NotQ(q2, q)
  1125. ELSE QbeGen.CopyOp("0", q)
  1126. END; .) .
  1127. MapTail (* suffix chain after a mapped-array
  1128. constructor: deref, field or
  1129. subscript, like a designator. *)
  1130. (. VAR mq: SymTab.Name;
  1131. et: SymTab.TypeIndex;
  1132. q2: QbeGen.QVal; .)
  1133. = { "." GetIdent<mq> (. SemError(230); .)
  1134. | "^" (. SemError(230); .)
  1135. | "[" Expr<et, q2> "]" (. SemError(230); .)
  1136. | "(" [ ActualParams ] ")" (. SemError(230); .) } .
  1137. SetItems
  1138. = SetItem { "," SetItem } .
  1139. SetItem (. VAR t1, t2: SymTab.TypeIndex;
  1140. q1, q2: QbeGen.QVal; .)
  1141. = Expr<t1, q1> (. SemError(230); .)
  1142. [ ".." Expr<t2, q2> (. SemError(230); .) ] .
  1143. GetIdent<VAR n: SymTab.Name>
  1144. = ident (. LexName(n); .) .
  1145. END M2.