M2.lst 75 KB

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