SimpleQ.atg 46 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856
  1. COMPILER SimpleQ
  2. (* Simplified Modula-2 without PROCEDURE / FUNCTION, with a QBE backend
  3. for the scalar subset (see QbeGen for details).
  4. - program module only, no DEFINITION / IMPLEMENTATION split
  5. - no local modules, no EXPORT, no PRIORITY
  6. - no ProcedureDeclaration, FormalParameters, ProcedureType,
  7. ProcedureCall, ActualParameters, FORWARD, RETURN
  8. - statements: assignment, IF, CASE, WHILE, REPEAT, LOOP/EXIT, FOR, WITH
  9. - symbol table (SymTab) with static type checking: same error codes
  10. 200/201/202 and 210-224 as SimpleMod2 (Test1), same lenient rules
  11. (single pass, declare-before-use; INTEGER, CARDINAL and subranges
  12. form one integer family; no mixed INTEGER/REAL arithmetic; INTEGER
  13. assigns to REAL; 1-character literal is CHAR; InvalidType suppresses
  14. follow-on errors)
  15. - backend (QbeGen): emits QBE SSA to gen_qbe/<ModName>.ssa
  16. (directory gen_qbe/ must exist), assembled with "qbe" and linked
  17. with "cc" into a native binary. Only scalar data is lowered:
  18. INTEGER/CARDINAL/SHORTINT/LONGINT/BOOLEAN/CHAR/enumerations as
  19. QBE "w", REAL/LONGREAL as QBE "d". Everything else parses and
  20. type-checks but gets error 230 (qbe backend: construct not
  21. supported in scalar subset): ARRAY/RECORD/SET/POINTER variables,
  22. string variables, WITH, IN, set literals, non-literal CONST
  23. expressions and BY steps, EXIT outside LOOP, imported names used
  24. as values.
  25. - test convention (the language has no I/O): a global
  26. VAR ExitCode : INTEGER;
  27. makes the generated main return its value as the process exit
  28. code; otherwise the program returns 0. *)
  29. IMPORT SymTab, QbeGen;
  30. CHARACTERS
  31. eol = CHR(13) .
  32. letter = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz" .
  33. digit = "0123456789" .
  34. hexDigit = digit + "ABCDEF" .
  35. noQuote1 = ANY - "'" - eol .
  36. noQuote2 = ANY - '"' - eol .
  37. IGNORE CHR(9) .. CHR(13)
  38. COMMENTS
  39. FROM "(*" TO "*)" NESTED
  40. TOKENS
  41. ident = letter { letter | digit } .
  42. integer = digit { digit }
  43. | digit { digit } CONTEXT("..")
  44. | digit { hexDigit } "H" .
  45. real = digit { digit } "." { digit }
  46. [ "E" [ "+" | "-" ] digit { digit } ] .
  47. string = "'" { noQuote1 } "'"
  48. | '"' { noQuote2 } '"' .
  49. PRODUCTIONS
  50. SimpleQ (. VAR m1, m2: SymTab.Name; .)
  51. = "MODULE"
  52. GetIdent<m1> (. SymTab.Init; QbeGen.OpenModule(m1);
  53. IF ~SymTab.Enter(m1, SymTab.KindModule)
  54. THEN SemError(200) END .)
  55. ";"
  56. { Import } Block GetIdent<m2> (. IF ~SymTab.Equal(m1, m2)
  57. THEN SemError(202) END .)
  58. "." (. QbeGen.EndModule;
  59. SymTab.PrintTable; .) .
  60. Import (. VAR n: SymTab.Name; .)
  61. = "FROM"
  62. GetIdent<n> (. IF ~SymTab.Enter(n, SymTab.KindImport)
  63. THEN SemError(200) END .)
  64. "IMPORT"
  65. ImportList ";"
  66. | "IMPORT"
  67. ImportList ";" .
  68. ImportList (. VAR n: SymTab.Name; .)
  69. = GetIdent<n> (. IF ~SymTab.Enter(n, SymTab.KindImport)
  70. THEN SemError(200) END .)
  71. { ","
  72. GetIdent<n> (. IF ~SymTab.Enter(n, SymTab.KindImport)
  73. THEN SemError(200) END .) } .
  74. Block = { Declaration }
  75. [ "BEGIN" (. QbeGen.BeginBody; .)
  76. StatSeq ]
  77. "END" .
  78. Declaration = "CONST"
  79. {
  80. ConstDecl ";" }
  81. | "TYPE"
  82. {
  83. TypeDecl ";" }
  84. | "VAR"
  85. {
  86. VarDecl ";" } .
  87. ConstDecl (. VAR n: SymTab.Name;
  88. t: SymTab.TypeIndex;
  89. qv: QbeGen.QVal;
  90. cls: INTEGER; .)
  91. = GetIdent<n> (. IF ~SymTab.Enter(n, SymTab.KindConst)
  92. THEN SemError(200) END .)
  93. "="
  94. ConstExpr<t, qv> (. SymTab.SetSymType(n, t);
  95. cls := SymTab.ClassOf(t);
  96. IF cls = SymTab.ClStr THEN
  97. SemError(230)
  98. ELSIF ~QbeGen.IsImm(qv) THEN
  99. SemError(230)
  100. END;
  101. QbeGen.DeclConst(n, qv, t); .) .
  102. ConstExpr <VAR t: SymTab.TypeIndex; VAR q: QbeGen.QVal>
  103. = Expr<t, q> .
  104. TypeDecl (. VAR n: SymTab.Name;
  105. t0, t1: SymTab.TypeIndex; .)
  106. = GetIdent<n> (. IF ~SymTab.Enter(n, SymTab.KindType)
  107. THEN SemError(200) END;
  108. t0 := SymTab.NewAlias();
  109. SymTab.SetSymType(n, t0); .)
  110. "="
  111. Type<t1> (. IF t1 = t0 THEN SemError(223);
  112. SymTab.SetTarget(t0,
  113. SymTab.InvalidType)
  114. ELSE SymTab.SetTarget(t0, t1) END; .) .
  115. VarDecl (. VAR t: SymTab.TypeIndex;
  116. i: CARDINAL;
  117. nm: SymTab.Name;
  118. cls: INTEGER; .)
  119. = VarIdents ":"
  120. Type<t> (. cls := SymTab.ClassOf(t);
  121. IF (cls # SymTab.ClInt)
  122. & (cls # SymTab.ClReal)
  123. & (cls # SymTab.ClBool)
  124. & (cls # SymTab.ClChar)
  125. & (cls # SymTab.ClEnum) THEN
  126. SemError(230)
  127. END;
  128. i := 0;
  129. WHILE i < SymTab.PendCount() DO
  130. SymTab.PendName(i, nm);
  131. QbeGen.DeclVar(nm, t);
  132. INC(i)
  133. END;
  134. SymTab.FixPending(t); .) .
  135. VarIdents (. VAR n: SymTab.Name; .)
  136. = GetIdent<n> (. IF ~SymTab.EnterPending(n,
  137. SymTab.KindVar)
  138. THEN SemError(200) END .)
  139. { ","
  140. GetIdent<n> (. IF ~SymTab.EnterPending(n,
  141. SymTab.KindVar)
  142. THEN SemError(200) END .) } .
  143. QualIdent <VAR t: SymTab.TypeIndex>
  144. (. VAR n, m: SymTab.Name; .)
  145. = GetIdent<n> (. IF ~SymTab.Lookup(n) THEN
  146. SemError(201);
  147. t := SymTab.InvalidType
  148. ELSIF (SymTab.SymKind(n) #
  149. SymTab.KindType)
  150. & (SymTab.SymKind(n) #
  151. SymTab.KindPredef)
  152. & (SymTab.SymKind(n) #
  153. SymTab.KindImport) THEN
  154. SemError(221);
  155. t := SymTab.InvalidType
  156. ELSE t := SymTab.SymType(n) END; .)
  157. { "."
  158. GetIdent<m> (. t := SymTab.InvalidType; .) } .
  159. (* Types: ProcedureType removed; subrange factored for LL(1) *)
  160. Type <VAR t: SymTab.TypeIndex>
  161. = SimpleType<t> | ArrayType<t> | RecordType<t>
  162. | SetType<t> | PointerType<t> .
  163. SimpleType <VAR t: SymTab.TypeIndex>
  164. (. VAR t1, t2: SymTab.TypeIndex;
  165. q1, q2: QbeGen.QVal; .)
  166. = QualIdent<t> [ "["
  167. ConstExpr<t1, q1> (. IF (t1 # SymTab.InvalidType)
  168. & (SymTab.ClassOf(t1) #
  169. SymTab.ClInt)
  170. & (SymTab.ClassOf(t1) #
  171. SymTab.ClChar)
  172. & (SymTab.ClassOf(t1) #
  173. SymTab.ClEnum) THEN
  174. SemError(224) END; .)
  175. ".."
  176. ConstExpr<t2, q2> (. IF (t2 # SymTab.InvalidType)
  177. & (SymTab.ClassOf(t2) #
  178. SymTab.ClInt)
  179. & (SymTab.ClassOf(t2) #
  180. SymTab.ClChar)
  181. & (SymTab.ClassOf(t2) #
  182. SymTab.ClEnum) THEN
  183. SemError(224) END; .)
  184. "]"
  185. (. t := SymTab.NewSub(t1); .) ]
  186. | "["
  187. ConstExpr<t1, q1> (. IF (t1 # SymTab.InvalidType)
  188. & (SymTab.ClassOf(t1) #
  189. SymTab.ClInt)
  190. & (SymTab.ClassOf(t1) #
  191. SymTab.ClChar)
  192. & (SymTab.ClassOf(t1) #
  193. SymTab.ClEnum) THEN
  194. SemError(224) END; .)
  195. ".."
  196. ConstExpr<t2, q2> (. IF (t2 # SymTab.InvalidType)
  197. & (SymTab.ClassOf(t2) #
  198. SymTab.ClInt)
  199. & (SymTab.ClassOf(t2) #
  200. SymTab.ClChar)
  201. & (SymTab.ClassOf(t2) #
  202. SymTab.ClEnum) THEN
  203. SemError(224) END; .)
  204. "]" (. t := SymTab.NewSub(t1); .)
  205. | Enum<t> .
  206. Enum <VAR t: SymTab.TypeIndex>
  207. (. VAR n: SymTab.Name;
  208. qs: QbeGen.QVal;
  209. ord: INTEGER; .)
  210. = "(" (. t := SymTab.NewEnum();
  211. ord := 0; .)
  212. GetIdent<n> (. IF ~SymTab.Enter(n,
  213. SymTab.KindConst)
  214. THEN SemError(200) END;
  215. SymTab.SetSymType(n, t);
  216. QbeGen.IntStr(ord, qs);
  217. QbeGen.DeclConst(n, qs, t);
  218. INC(ord); .)
  219. { ","
  220. GetIdent<n> (. IF ~SymTab.Enter(n,
  221. SymTab.KindConst)
  222. THEN SemError(200) END;
  223. SymTab.SetSymType(n, t);
  224. QbeGen.IntStr(ord, qs);
  225. QbeGen.DeclConst(n, qs, t);
  226. INC(ord); .) }
  227. ")" .
  228. ArrayType <VAR t: SymTab.TypeIndex>
  229. (. VAR s, s2, e: SymTab.TypeIndex;
  230. qs: QbeGen.QVal; .)
  231. = "ARRAY"
  232. SimpleType<s> (. IF (s # SymTab.InvalidType)
  233. & (SymTab.ClassOf(s) #
  234. SymTab.ClInt)
  235. & (SymTab.ClassOf(s) #
  236. SymTab.ClChar)
  237. & (SymTab.ClassOf(s) #
  238. SymTab.ClEnum) THEN
  239. SemError(224) END; .)
  240. { ","
  241. SimpleType<s2> (. IF (s2 # SymTab.InvalidType)
  242. & (SymTab.ClassOf(s2) #
  243. SymTab.ClInt)
  244. & (SymTab.ClassOf(s2) #
  245. SymTab.ClChar)
  246. & (SymTab.ClassOf(s2) #
  247. SymTab.ClEnum) THEN
  248. SemError(224) END; .) }
  249. "OF"
  250. Type<e> (. t := SymTab.NewArray(e); .) .
  251. RecordType <VAR t: SymTab.TypeIndex>
  252. = "RECORD" (. t := SymTab.NewRecord(); .)
  253. FieldSeq<t>
  254. "END" .
  255. FieldSeq <rt: SymTab.TypeIndex>
  256. = Field<rt> { ";"
  257. Field<rt> } .
  258. Field <rt: SymTab.TypeIndex>
  259. (. VAR et: SymTab.TypeIndex; .)
  260. = [ FieldIdents<rt> ":"
  261. Type<et> (. SymTab.FixPendingF(rt, et); .) ] .
  262. FieldIdents <rt: SymTab.TypeIndex>
  263. (. VAR n: SymTab.Name; .)
  264. = GetIdent<n> (. IF ~SymTab.FieldPending(rt, n)
  265. THEN SemError(200) END .)
  266. { ","
  267. GetIdent<n> (. IF ~SymTab.FieldPending(rt, n)
  268. THEN SemError(200) END .) } .
  269. SetType <VAR t: SymTab.TypeIndex>
  270. (. VAR s: SymTab.TypeIndex; .)
  271. = "SET"
  272. "OF"
  273. SimpleType<s> (. IF (s # SymTab.InvalidType)
  274. & (SymTab.ClassOf(s) #
  275. SymTab.ClInt)
  276. & (SymTab.ClassOf(s) #
  277. SymTab.ClChar)
  278. & (SymTab.ClassOf(s) #
  279. SymTab.ClEnum) THEN
  280. SemError(224) END;
  281. t := SymTab.NewSet(s); .) .
  282. PointerType <VAR t: SymTab.TypeIndex>
  283. (. VAR b: SymTab.TypeIndex; .)
  284. = "POINTER"
  285. "TO"
  286. Type<b> (. t := SymTab.NewPtr(b); .) .
  287. (* Statements: ProcedureCall and RETURN removed *)
  288. StatSeq = Stat { ";"
  289. Stat } .
  290. Stat (. VAR lx: QbeGen.QVal; .)
  291. = [ Assign | IfStat | CaseStat | WhileStat
  292. | RepeatStat | LoopStat | ForStat | WithStat
  293. | "EXIT" (. IF QbeGen.TopLoop(lx) THEN
  294. QbeGen.Jmp(lx)
  295. ELSE SemError(230) END; .) ] .
  296. Assign (. VAR dt, et: SymTab.TypeIndex;
  297. dk: INTEGER;
  298. qd, qe, qt: QbeGen.QVal;
  299. qn: SymTab.Name;
  300. sfx: BOOLEAN;
  301. isR, conv: BOOLEAN; .)
  302. = Design<dt, dk, qd, qn, sfx> ":="
  303. Expr<et, qe> (. IF (dt # SymTab.InvalidType)
  304. & (dk # SymTab.KindVar)
  305. & (dk # SymTab.KindField)
  306. & (dk # SymTab.KindImport) THEN
  307. SemError(210)
  308. ELSIF ~SymTab.Assignable(et, dt) THEN
  309. SemError(210) END;
  310. IF dk = SymTab.KindImport THEN
  311. SemError(230)
  312. END;
  313. isR := (dt # SymTab.InvalidType)
  314. & (SymTab.ClassOf(dt)
  315. = SymTab.ClReal);
  316. conv := isR
  317. & SymTab.IsIntFamily(et);
  318. IF ~sfx
  319. & (dk = SymTab.KindVar) THEN
  320. IF conv THEN
  321. QbeGen.ConvIR(qe, qt);
  322. QbeGen.StoreVar(qn, qt, TRUE)
  323. ELSE
  324. QbeGen.StoreVar(qn, qe, isR)
  325. END
  326. END; .) .
  327. IfStat (. VAR t: SymTab.TypeIndex;
  328. q: QbeGen.QVal;
  329. lThen, lElse, lEnd: QbeGen.QVal;
  330. hasElse: BOOLEAN; .)
  331. = "IF"
  332. Expr<t, q> (. IF ~SymTab.BoolCheck(t) THEN
  333. SemError(214) END;
  334. QbeGen.NewLabel(lThen);
  335. QbeGen.NewLabel(lElse);
  336. QbeGen.NewLabel(lEnd);
  337. QbeGen.Jnz(q, lThen, lElse);
  338. QbeGen.EmitLabel(lThen);
  339. hasElse := FALSE; .)
  340. "THEN"
  341. StatSeq
  342. { "ELSIF" (. QbeGen.Jmp(lEnd);
  343. QbeGen.EmitLabel(lElse); .)
  344. Expr<t, q> (. IF ~SymTab.BoolCheck(t) THEN
  345. SemError(214) END;
  346. QbeGen.NewLabel(lThen);
  347. QbeGen.NewLabel(lElse);
  348. QbeGen.Jnz(q, lThen, lElse);
  349. QbeGen.EmitLabel(lThen); .)
  350. "THEN"
  351. StatSeq }
  352. [ "ELSE" (. QbeGen.Jmp(lEnd);
  353. QbeGen.EmitLabel(lElse);
  354. hasElse := TRUE; .)
  355. StatSeq ]
  356. "END" (. IF ~hasElse THEN
  357. QbeGen.EmitLabel(lElse)
  358. END;
  359. QbeGen.EmitLabel(lEnd); .) .
  360. CaseStat (. VAR st: SymTab.TypeIndex;
  361. sq: QbeGen.QVal;
  362. lEnd: QbeGen.QVal; .)
  363. = "CASE"
  364. Expr<st, sq>
  365. "OF" (. QbeGen.NewLabel(lEnd); .)
  366. Case<st, sq, lEnd> { "|"
  367. Case<st, sq, lEnd> }
  368. [ "ELSE"
  369. StatSeq ]
  370. "END" (. QbeGen.EmitLabel(lEnd); .) .
  371. Case <sel: SymTab.TypeIndex; sq: QbeGen.QVal; endL: QbeGen.QVal>
  372. (. VAR lB, lN: QbeGen.QVal; .)
  373. = [ LabelList<sel, sq, lB, lN> ":" (. QbeGen.EmitLabel(lB); .)
  374. StatSeq (. QbeGen.Jmp(endL);
  375. QbeGen.EmitLabel(lN); .) ] .
  376. LabelList <sel: SymTab.TypeIndex; sq: QbeGen.QVal;
  377. VAR lB: QbeGen.QVal; VAR lN: QbeGen.QVal>
  378. = (. QbeGen.NewLabel(lB);
  379. QbeGen.NewLabel(lN); .)
  380. Labels<sel, sq, lB> { ","
  381. Labels<sel, sq, lB> }
  382. (. QbeGen.Jmp(lN); .) .
  383. Labels <sel: SymTab.TypeIndex; sq: QbeGen.QVal; lB: QbeGen.QVal>
  384. (. VAR t, t2: SymTab.TypeIndex;
  385. q, q2, qk, qg, ql, qb: QbeGen.QVal;
  386. lC: QbeGen.QVal;
  387. r, hasRange: BOOLEAN; .)
  388. = ConstExpr<t, q> (. IF ~SymTab.EqCheck(t, sel) THEN
  389. SemError(213) END;
  390. r := (SymTab.ClassOf(sel)
  391. = SymTab.ClReal)
  392. & (SymTab.ClassOf(t)
  393. = SymTab.ClReal);
  394. hasRange := FALSE; .)
  395. [ ".."
  396. ConstExpr<t2, q2> (. IF ~SymTab.EqCheck(t2, sel) THEN
  397. SemError(213) END;
  398. hasRange := TRUE; .) ]
  399. (. IF hasRange THEN
  400. QbeGen.Cmp(SymTab.OpGe,
  401. sq, q, qg, r);
  402. QbeGen.Cmp(SymTab.OpLe,
  403. sq, q2, ql, r);
  404. QbeGen.NewTemp(qb);
  405. QbeGen.Op3("and", qb, qg, ql,
  406. FALSE)
  407. ELSE
  408. QbeGen.Cmp(SymTab.OpEq,
  409. sq, q, qb, r)
  410. END;
  411. QbeGen.NewLabel(lC);
  412. QbeGen.Jnz(qb, lB, lC);
  413. QbeGen.EmitLabel(lC); .) .
  414. WhileStat (. VAR t: SymTab.TypeIndex;
  415. q: QbeGen.QVal;
  416. lC, lB, lE: QbeGen.QVal; .)
  417. = "WHILE" (. QbeGen.NewLabel(lC);
  418. QbeGen.NewLabel(lB);
  419. QbeGen.NewLabel(lE);
  420. QbeGen.EmitLabel(lC); .)
  421. Expr<t, q> (. IF ~SymTab.BoolCheck(t) THEN
  422. SemError(214) END;
  423. QbeGen.Jnz(q, lB, lE);
  424. QbeGen.EmitLabel(lB); .)
  425. "DO"
  426. StatSeq
  427. "END" (. QbeGen.Jmp(lC);
  428. QbeGen.EmitLabel(lE); .) .
  429. RepeatStat (. VAR t: SymTab.TypeIndex;
  430. q: QbeGen.QVal;
  431. lTop, lE: QbeGen.QVal; .)
  432. = "REPEAT" (. QbeGen.NewLabel(lTop);
  433. QbeGen.NewLabel(lE);
  434. QbeGen.EmitLabel(lTop); .)
  435. StatSeq
  436. "UNTIL"
  437. Expr<t, q> (. IF ~SymTab.BoolCheck(t) THEN
  438. SemError(214) END;
  439. QbeGen.Jnz(q, lE, lTop);
  440. QbeGen.EmitLabel(lE); .) .
  441. LoopStat (. VAR lTop, lE: QbeGen.QVal; .)
  442. = "LOOP" (. QbeGen.NewLabel(lTop);
  443. QbeGen.NewLabel(lE);
  444. QbeGen.EmitLabel(lTop);
  445. QbeGen.PushLoop(lE); .)
  446. StatSeq
  447. "END" (. QbeGen.Jmp(lTop);
  448. QbeGen.EmitLabel(lE);
  449. QbeGen.PopLoop; .) .
  450. ForStat (. VAR n, lv: SymTab.Name;
  451. lo, hi, by: SymTab.TypeIndex;
  452. qlo, qhi, qby, hiS, byS: QbeGen.QVal;
  453. qt, qk: QbeGen.QVal;
  454. lTop, lChk, lEnd: QbeGen.QVal;
  455. neg: BOOLEAN; .)
  456. = "FOR"
  457. GetIdent<n> (. IF ~SymTab.Lookup(n) THEN
  458. SemError(201)
  459. ELSIF (SymTab.SymKind(n) #
  460. SymTab.KindVar)
  461. & (SymTab.SymKind(n) #
  462. SymTab.KindField) THEN
  463. SemError(220)
  464. ELSIF (SymTab.SymType(n) #
  465. SymTab.InvalidType)
  466. & ~SymTab.IsIntFamily(
  467. SymTab.SymType(n)) THEN
  468. SemError(220) END;
  469. QbeGen.CopyOp(n, lv); .)
  470. ":="
  471. Expr<lo, qlo> (. IF (lo # SymTab.InvalidType)
  472. & ~SymTab.IsIntFamily(lo) THEN
  473. SemError(220) END;
  474. IF (lo # SymTab.InvalidType)
  475. & SymTab.IsIntFamily(lo) THEN
  476. QbeGen.StoreVar(lv, qlo, FALSE)
  477. ELSE
  478. QbeGen.StoreVar(lv, "0", FALSE)
  479. END; .)
  480. "TO"
  481. Expr<hi, qhi> (. IF (hi # SymTab.InvalidType)
  482. & ~SymTab.IsIntFamily(hi) THEN
  483. SemError(220) END;
  484. QbeGen.CopyOp(qhi, hiS);
  485. QbeGen.CopyOp("1", byS);
  486. neg := FALSE;
  487. by := SymTab.IntType(); .)
  488. [ "BY"
  489. ConstExpr<by, qby> (. IF (by # SymTab.InvalidType)
  490. & ~SymTab.IsIntFamily(by) THEN
  491. SemError(220) END;
  492. IF QbeGen.IsImm(qby) THEN
  493. QbeGen.CopyOp(qby, byS);
  494. neg := QbeGen.IsNeg(qby)
  495. ELSE SemError(230);
  496. QbeGen.CopyOp("1", byS);
  497. neg := FALSE
  498. END; .) ]
  499. "DO" (. QbeGen.NewLabel(lTop);
  500. QbeGen.NewLabel(lChk);
  501. QbeGen.NewLabel(lEnd);
  502. QbeGen.Jmp(lChk);
  503. QbeGen.EmitLabel(lTop); .)
  504. StatSeq
  505. "END" (. QbeGen.LoadVar(lv, FALSE, qt);
  506. QbeGen.NewTemp(qk);
  507. QbeGen.Op3("add", qk, qt, byS,
  508. FALSE);
  509. QbeGen.StoreVar(lv, qk, FALSE);
  510. QbeGen.EmitLabel(lChk);
  511. QbeGen.LoadVar(lv, FALSE, qt);
  512. QbeGen.NewTemp(qk);
  513. IF neg THEN
  514. QbeGen.Op3("csgew", qk, qt, hiS,
  515. FALSE)
  516. ELSE
  517. QbeGen.Op3("cslew", qk, qt, hiS,
  518. FALSE)
  519. END;
  520. QbeGen.Jnz(qk, lTop, lEnd);
  521. QbeGen.EmitLabel(lEnd); .) .
  522. WithStat (. VAR dt: SymTab.TypeIndex;
  523. dk: INTEGER;
  524. dq: QbeGen.QVal;
  525. qn: SymTab.Name;
  526. sfx: BOOLEAN;
  527. pushed: BOOLEAN; .)
  528. = "WITH"
  529. Design<dt, dk, dq, qn, sfx> (. pushed := FALSE;
  530. IF dt # SymTab.InvalidType THEN
  531. pushed :=
  532. SymTab.PushRecord(dt);
  533. IF ~pushed THEN
  534. SemError(215)
  535. END
  536. END;
  537. IF pushed THEN
  538. QbeGen.NoQbeEnter;
  539. SemError(230)
  540. END; .)
  541. "DO"
  542. StatSeq
  543. "END" (. IF pushed THEN
  544. SymTab.PopScope;
  545. QbeGen.NoQbeExit
  546. END; .) .
  547. (* Expressions: Designator without ActualParameters.
  548. Only record fields resolve qualified access; WITH pushes an
  549. inner scope so field names also work unqualified in its body
  550. (both report 230 in the scalar subset). Each expression
  551. synthesizes its SymTab type in t and its QBE operand in q
  552. (an immediate or a fresh %temporary holding the value). *)
  553. Design <VAR t: SymTab.TypeIndex; VAR k: INTEGER;
  554. VAR q: QbeGen.QVal; VAR qn: SymTab.Name; VAR sfx: BOOLEAN>
  555. (. VAR n, m: SymTab.Name;
  556. it: SymTab.TypeIndex;
  557. qr: QbeGen.QVal;
  558. cls: INTEGER; .)
  559. = GetIdent<n> (. QbeGen.CopyOp(n, qn);
  560. sfx := FALSE;
  561. IF ~SymTab.Lookup(n) THEN
  562. SemError(201);
  563. t := SymTab.InvalidType; k := -1;
  564. QbeGen.CopyOp("0", q)
  565. ELSE
  566. t := SymTab.SymType(n);
  567. k := SymTab.SymKind(n);
  568. IF k = SymTab.KindConst THEN
  569. IF SymTab.Equal(n, "TRUE") THEN
  570. t := SymTab.BoolType();
  571. QbeGen.CopyOp("1", q)
  572. ELSIF SymTab.Equal(n,
  573. "FALSE") THEN
  574. t := SymTab.BoolType();
  575. QbeGen.CopyOp("0", q)
  576. ELSE
  577. cls :=
  578. SymTab.ClassOf(t);
  579. IF (t #
  580. SymTab.InvalidType)
  581. & (cls # SymTab.ClStr)
  582. & ((cls = SymTab.ClInt)
  583. OR (cls = SymTab.ClReal)
  584. OR (cls = SymTab.ClBool)
  585. OR (cls = SymTab.ClChar)
  586. OR (cls
  587. = SymTab.ClEnum)) THEN
  588. QbeGen.LoadVar(n,
  589. cls = SymTab.ClReal, q)
  590. ELSE
  591. QbeGen.CopyOp("0", q)
  592. END
  593. END
  594. ELSIF k = SymTab.KindVar THEN
  595. cls := SymTab.ClassOf(t);
  596. IF (cls = SymTab.ClInt)
  597. OR (cls = SymTab.ClReal)
  598. OR (cls = SymTab.ClBool)
  599. OR (cls = SymTab.ClChar)
  600. OR (cls
  601. = SymTab.ClEnum) THEN
  602. QbeGen.LoadVar(n,
  603. cls = SymTab.ClReal, q)
  604. ELSE SemError(230);
  605. QbeGen.CopyOp("0", q)
  606. END
  607. ELSE QbeGen.CopyOp("0", q);
  608. IF k = SymTab.KindField THEN
  609. IF ~QbeGen.NoQbe() THEN
  610. SemError(230)
  611. END
  612. ELSIF k
  613. = SymTab.KindImport THEN
  614. SemError(230)
  615. END
  616. END
  617. END; .)
  618. { "." (. sfx := TRUE; .)
  619. GetIdent<m> (. IF t = SymTab.InvalidType THEN
  620. ELSIF SymTab.ClassOf(t) #
  621. SymTab.ClRecord THEN
  622. SemError(215);
  623. t := SymTab.InvalidType
  624. ELSIF ~SymTab.FieldExists(t, m) THEN
  625. SemError(216);
  626. t := SymTab.InvalidType
  627. ELSE t := SymTab.FieldType(t, m);
  628. SemError(230)
  629. END;
  630. QbeGen.CopyOp("0", q); .)
  631. | "[" (. sfx := TRUE; .)
  632. Expr<it, qr> (. IF t = SymTab.InvalidType THEN
  633. ELSIF SymTab.ClassOf(t) #
  634. SymTab.ClArray THEN
  635. SemError(217);
  636. t := SymTab.InvalidType
  637. ELSIF (it #
  638. SymTab.InvalidType)
  639. & ~SymTab.IsIntFamily(it) THEN
  640. SemError(218);
  641. t := SymTab.InvalidType
  642. ELSE t :=
  643. SymTab.ArrayElem(t);
  644. SemError(230)
  645. END;
  646. QbeGen.CopyOp("0", q); .)
  647. { ","
  648. Expr<it, qr> (. IF (it # SymTab.InvalidType)
  649. & ~SymTab.IsIntFamily(it) THEN
  650. SemError(218) END; .) }
  651. "]"
  652. | "^" (. sfx := TRUE;
  653. IF t = SymTab.InvalidType THEN
  654. ELSIF SymTab.ClassOf(t) #
  655. SymTab.ClPtr THEN
  656. SemError(219);
  657. t := SymTab.InvalidType
  658. ELSE t := SymTab.PtrBase(t);
  659. SemError(230)
  660. END;
  661. QbeGen.CopyOp("0", q); .) } .
  662. Expr <VAR t: SymTab.TypeIndex; VAR q: QbeGen.QVal>
  663. (. VAR t2: SymTab.TypeIndex;
  664. tc, op: INTEGER;
  665. q2, qk: QbeGen.QVal;
  666. r: BOOLEAN; .)
  667. = SimExpr<t, q> [ Rel<op> SimExpr<t2, q2>
  668. (. IF op = SymTab.OpIn THEN
  669. IF SymTab.InCheck(t, t2) THEN
  670. t := SymTab.BoolType();
  671. SemError(230)
  672. ELSE SemError(222);
  673. t := SymTab.InvalidType
  674. END;
  675. QbeGen.CopyOp("0", q)
  676. ELSE
  677. tc := SymTab.ClassOf(t);
  678. IF SymTab.RelCheck(t, t2, op) THEN
  679. t := SymTab.BoolType()
  680. ELSE SemError(213); t := SymTab.InvalidType END;
  681. IF t # SymTab.InvalidType THEN
  682. r := tc = SymTab.ClReal;
  683. QbeGen.Cmp(op, q, q2, qk, r);
  684. QbeGen.CopyOp(qk, q)
  685. ELSE QbeGen.CopyOp("0", q)
  686. END
  687. END; .) ] .
  688. Rel <VAR op: INTEGER>
  689. = "=" (. op := SymTab.OpEq; .)
  690. | "#" (. op := SymTab.OpNeq1; .)
  691. | "<>" (. op := SymTab.OpNeq2; .)
  692. | "<" (. op := SymTab.OpLt; .)
  693. | "<=" (. op := SymTab.OpLe; .)
  694. | ">" (. op := SymTab.OpGt; .)
  695. | ">=" (. op := SymTab.OpGe; .)
  696. | "IN" (. op := SymTab.OpIn; .) .
  697. SimExpr <VAR t: SymTab.TypeIndex; VAR q: QbeGen.QVal>
  698. (. VAR t2, res2: SymTab.TypeIndex;
  699. op: INTEGER;
  700. q2, qt: QbeGen.QVal;
  701. neg, isR: BOOLEAN; .)
  702. = (. neg := FALSE; .)
  703. [ "+" | "-" (. neg := TRUE; .) ]
  704. Term<t, q> (. IF neg THEN
  705. IF QbeGen.IsImm(q) THEN
  706. QbeGen.NegFold(q, q)
  707. ELSE QbeGen.NewTemp(qt);
  708. QbeGen.NegQ(q, qt,
  709. SymTab.ClassOf(t)
  710. = SymTab.ClReal);
  711. QbeGen.CopyOp(qt, q)
  712. END
  713. END; .)
  714. { AddOp<op> Term<t2, q2>
  715. (. IF op = SymTab.OpOr THEN
  716. IF SymTab.BoolCheck(t) & SymTab.BoolCheck(t2) THEN
  717. t := SymTab.BoolType()
  718. ELSE SemError(212); t := SymTab.InvalidType END;
  719. IF t # SymTab.InvalidType THEN
  720. QbeGen.NewTemp(qt);
  721. QbeGen.Op3("or", qt, q, q2, FALSE);
  722. QbeGen.CopyOp(qt, q)
  723. ELSE QbeGen.CopyOp("0", q)
  724. END
  725. ELSE
  726. IF SymTab.ArithCheck(t, t2, FALSE, res2) THEN t := res2
  727. ELSE SemError(211); t := SymTab.InvalidType END;
  728. IF t # SymTab.InvalidType THEN
  729. isR := SymTab.ClassOf(t) = SymTab.ClReal;
  730. QbeGen.NewTemp(qt);
  731. IF op = SymTab.OpAdd THEN
  732. QbeGen.Op3("add", qt, q, q2, isR)
  733. ELSE
  734. QbeGen.Op3("sub", qt, q, q2, isR)
  735. END;
  736. QbeGen.CopyOp(qt, q)
  737. ELSE QbeGen.CopyOp("0", q)
  738. END
  739. END; .) } .
  740. AddOp <VAR op: INTEGER>
  741. = "+" (. op := SymTab.OpAdd; .)
  742. | "-" (. op := SymTab.OpSub; .)
  743. | "OR" (. op := SymTab.OpOr; .) .
  744. Term <VAR t: SymTab.TypeIndex; VAR q: QbeGen.QVal>
  745. (. VAR t2, res2: SymTab.TypeIndex;
  746. op: INTEGER;
  747. q2, qt: QbeGen.QVal;
  748. isR: BOOLEAN; .)
  749. = Fact<t, q> { MulOp<op> Fact<t2, q2>
  750. (. IF op = SymTab.OpAnd THEN
  751. IF SymTab.BoolCheck(t) & SymTab.BoolCheck(t2) THEN
  752. t := SymTab.BoolType()
  753. ELSE SemError(212); t := SymTab.InvalidType END;
  754. IF t # SymTab.InvalidType THEN
  755. QbeGen.NewTemp(qt);
  756. QbeGen.Op3("and", qt, q, q2, FALSE);
  757. QbeGen.CopyOp(qt, q)
  758. ELSE QbeGen.CopyOp("0", q)
  759. END
  760. ELSE
  761. IF SymTab.ArithCheck(t, t2,
  762. (op = SymTab.OpDiv) OR (op = SymTab.OpMod),
  763. res2) THEN t := res2
  764. ELSE SemError(211); t := SymTab.InvalidType END;
  765. IF t # SymTab.InvalidType THEN
  766. isR := SymTab.ClassOf(t) = SymTab.ClReal;
  767. QbeGen.NewTemp(qt);
  768. IF op = SymTab.OpTimes THEN
  769. QbeGen.Op3("mul", qt, q, q2, isR)
  770. ELSIF op = SymTab.OpSlash THEN
  771. QbeGen.Op3("div", qt, q, q2, isR)
  772. ELSIF op = SymTab.OpDiv THEN
  773. QbeGen.Op3("div", qt, q, q2, FALSE)
  774. ELSE
  775. QbeGen.Op3("rem", qt, q, q2, FALSE)
  776. END;
  777. QbeGen.CopyOp(qt, q)
  778. ELSE QbeGen.CopyOp("0", q)
  779. END
  780. END; .) } .
  781. MulOp <VAR op: INTEGER>
  782. = "*" (. op := SymTab.OpTimes; .)
  783. | "/" (. op := SymTab.OpSlash; .)
  784. | "DIV" (. op := SymTab.OpDiv; .)
  785. | "MOD" (. op := SymTab.OpMod; .)
  786. | "AND" (. op := SymTab.OpAnd; .)
  787. | "&" (. op := SymTab.OpAnd; .) .
  788. Fact <VAR t: SymTab.TypeIndex; VAR q: QbeGen.QVal>
  789. (. VAR s: ARRAY [0 .. 255] OF CHAR;
  790. t2, et, dt, st: SymTab.TypeIndex;
  791. dk: INTEGER;
  792. qd, q2: QbeGen.QVal;
  793. qnF: SymTab.Name;
  794. sfxF: BOOLEAN; .)
  795. = integer (. LexString(s);
  796. QbeGen.NormInt(s, q);
  797. t := SymTab.IntType(); .)
  798. | real (. LexString(s);
  799. QbeGen.NormReal(s, q);
  800. t := SymTab.RealType(); .)
  801. | string (. LexString(s);
  802. IF SymTab.StrLen(s) <= 3 THEN
  803. t := SymTab.CharType();
  804. QbeGen.IntStr(
  805. QbeGen.CharVal(s), q)
  806. ELSE t := SymTab.NewStr();
  807. SemError(230);
  808. QbeGen.CopyOp("0", q)
  809. END; .)
  810. | Design<dt, dk, qd, qnF, sfxF> (. t := dt;
  811. QbeGen.CopyOp(qd, q); .)
  812. | "("
  813. Expr<et, q> ")" (. t := et; .)
  814. | ( "NOT" | "~" )
  815. Fact<t2, q2> (. IF SymTab.BoolCheck(t2) THEN
  816. t := SymTab.BoolType()
  817. ELSE SemError(212);
  818. t := SymTab.InvalidType END;
  819. IF t # SymTab.InvalidType THEN
  820. QbeGen.NotQ(q2, q)
  821. ELSE QbeGen.CopyOp("0", q)
  822. END; .)
  823. | SetLit<st> (. t := st;
  824. SemError(230);
  825. QbeGen.CopyOp("0", q); .) .
  826. SetLit <VAR t: SymTab.TypeIndex>
  827. (. VAR first, et: SymTab.TypeIndex;
  828. qe: QbeGen.QVal; .)
  829. = "{"
  830. (. t := SymTab.SetFor(SymTab.IntType()); .)
  831. [ Elem<et, qe> (. first := et; t := SymTab.SetFor(et); .)
  832. { ","
  833. Elem<et, qe> (. IF ~SymTab.SetElemCheck(first, et) THEN
  834. SemError(222) END; .) } ]
  835. "}" .
  836. Elem <VAR t: SymTab.TypeIndex; VAR q: QbeGen.QVal>
  837. (. VAR t2: SymTab.TypeIndex;
  838. q2: QbeGen.QVal; .)
  839. = Expr<t, q> [ ".."
  840. Expr<t2, q2> (. IF ~SymTab.SetElemCheck(t, t2) THEN
  841. SemError(222) END; .) ] .
  842. GetIdent <VAR n: SymTab.Name>
  843. = ident (. LexName(n); .) .
  844. END SimpleQ.