Go to most recent revision | Details | Last modification | View Log | RSS feed
Rev | Author | Line No. | Line |
---|---|---|---|
7597 | akron1 | 1 | (* |
2 | BSD 2-Clause License |
||
3 | |||
4 | Copyright (c) 2018, 2019, Anton Krotov |
||
5 | All rights reserved. |
||
6 | *) |
||
7 | |||
8 | MODULE STATEMENTS; |
||
9 | |||
10 | IMPORT |
||
11 | |||
12 | PARS, PROG, SCAN, ARITH, STRINGS, LISTS, CODE, X86, AMD64, |
||
13 | ERRORS, MACHINE, AVL := AVLTREES, CONSOLE, C := COLLECTIONS, mConst := CONSTANTS; |
||
14 | |||
15 | |||
16 | CONST |
||
17 | |||
18 | eCONST = PARS.eCONST; eTYPE = PARS.eTYPE; eVAR = PARS.eVAR; |
||
19 | eEXPR = PARS.eEXPR; eVREC = PARS.eVREC; ePROC = PARS.ePROC; |
||
20 | eVPAR = PARS.eVPAR; ePARAM = PARS.ePARAM; eSTPROC = PARS.eSTPROC; |
||
21 | eSTFUNC = PARS.eSTFUNC; eSYSFUNC = PARS.eSYSFUNC; eSYSPROC = PARS.eSYSPROC; |
||
22 | eIMP = PARS.eIMP; |
||
23 | |||
24 | errASSERT = 1; errPTR = 2; errDIV = 3; errPROC = 4; |
||
25 | errGUARD = 5; errIDX = 6; errCASE = 7; errCOPY = 8; |
||
26 | errCHR = 9; errWCHR = 10; errBYTE = 11; |
||
27 | |||
28 | chkIDX* = 0; chkGUARD* = 1; chkPTR* = 2; chkCHR* = 3; chkWCHR* = 4; chkBYTE* = 5; |
||
29 | |||
30 | chkALL* = {chkIDX, chkGUARD, chkPTR, chkCHR, chkWCHR, chkBYTE}; |
||
31 | |||
32 | |||
33 | TYPE |
||
34 | |||
35 | isXXX = PROCEDURE (e: PARS.EXPR): BOOLEAN; |
||
36 | |||
37 | RANGE = RECORD |
||
38 | |||
39 | a, b: INTEGER |
||
40 | |||
41 | END; |
||
42 | |||
43 | CASE_LABEL = POINTER TO rCASE_LABEL; |
||
44 | |||
45 | rCASE_LABEL = RECORD (AVL.DATA) |
||
46 | |||
47 | range: RANGE; |
||
48 | |||
49 | variant, self: INTEGER; |
||
50 | |||
51 | type: PROG.TYPE_; |
||
52 | |||
53 | prev: CASE_LABEL |
||
54 | |||
55 | END; |
||
56 | |||
57 | CASE_VARIANT = POINTER TO RECORD (LISTS.ITEM) |
||
58 | |||
59 | label: INTEGER; |
||
60 | cmd: CODE.COMMAND; |
||
61 | processed: BOOLEAN |
||
62 | |||
63 | END; |
||
64 | |||
65 | |||
66 | VAR |
||
67 | |||
68 | begcall, endcall: CODE.COMMAND; |
||
69 | |||
70 | checking: SET; |
||
71 | |||
72 | CaseLabels, CaseVar: C.COLLECTION; |
||
73 | |||
74 | CaseVariants: LISTS.LIST; |
||
75 | |||
76 | |||
77 | PROCEDURE isExpr (e: PARS.EXPR): BOOLEAN; |
||
78 | RETURN e.obj IN {eCONST, eVAR, eEXPR, eVPAR, ePARAM, eVREC} |
||
79 | END isExpr; |
||
80 | |||
81 | |||
82 | PROCEDURE isVar (e: PARS.EXPR): BOOLEAN; |
||
83 | RETURN e.obj IN {eVAR, eVPAR, ePARAM, eVREC} |
||
84 | END isVar; |
||
85 | |||
86 | |||
87 | PROCEDURE isBoolean (e: PARS.EXPR): BOOLEAN; |
||
88 | RETURN isExpr(e) & (e.type.typ = PROG.tBOOLEAN) |
||
89 | END isBoolean; |
||
90 | |||
91 | |||
92 | PROCEDURE isInteger (e: PARS.EXPR): BOOLEAN; |
||
93 | RETURN isExpr(e) & (e.type.typ = PROG.tINTEGER) |
||
94 | END isInteger; |
||
95 | |||
96 | |||
97 | PROCEDURE isByte (e: PARS.EXPR): BOOLEAN; |
||
98 | RETURN isExpr(e) & (e.type.typ = PROG.tBYTE) |
||
99 | END isByte; |
||
100 | |||
101 | |||
102 | PROCEDURE isInt (e: PARS.EXPR): BOOLEAN; |
||
103 | RETURN isByte(e) OR isInteger(e) |
||
104 | END isInt; |
||
105 | |||
106 | |||
107 | PROCEDURE isReal (e: PARS.EXPR): BOOLEAN; |
||
108 | RETURN isExpr(e) & (e.type.typ = PROG.tREAL) |
||
109 | END isReal; |
||
110 | |||
111 | |||
112 | PROCEDURE isSet (e: PARS.EXPR): BOOLEAN; |
||
113 | RETURN isExpr(e) & (e.type.typ = PROG.tSET) |
||
114 | END isSet; |
||
115 | |||
116 | |||
117 | PROCEDURE isString (e: PARS.EXPR): BOOLEAN; |
||
118 | RETURN (e.obj = eCONST) & (e.type.typ IN {PROG.tSTRING, PROG.tCHAR}) |
||
119 | END isString; |
||
120 | |||
121 | |||
122 | PROCEDURE isStringW (e: PARS.EXPR): BOOLEAN; |
||
123 | RETURN (e.obj = eCONST) & (e.type.typ IN {PROG.tSTRING, PROG.tCHAR, PROG.tWCHAR}) |
||
124 | END isStringW; |
||
125 | |||
126 | |||
127 | PROCEDURE isChar (e: PARS.EXPR): BOOLEAN; |
||
128 | RETURN isExpr(e) & (e.type.typ = PROG.tCHAR) |
||
129 | END isChar; |
||
130 | |||
131 | |||
132 | PROCEDURE isCharArray (e: PARS.EXPR): BOOLEAN; |
||
133 | RETURN isExpr(e) & (e.type.typ = PROG.tARRAY) & (e.type.base.typ = PROG.tCHAR) |
||
134 | END isCharArray; |
||
135 | |||
136 | |||
137 | PROCEDURE isCharW (e: PARS.EXPR): BOOLEAN; |
||
138 | RETURN isExpr(e) & (e.type.typ = PROG.tWCHAR) |
||
139 | END isCharW; |
||
140 | |||
141 | |||
142 | PROCEDURE isCharArrayW (e: PARS.EXPR): BOOLEAN; |
||
143 | RETURN isExpr(e) & (e.type.typ = PROG.tARRAY) & (e.type.base.typ = PROG.tWCHAR) |
||
144 | END isCharArrayW; |
||
145 | |||
146 | |||
147 | PROCEDURE isCharArrayX (e: PARS.EXPR): BOOLEAN; |
||
148 | RETURN isExpr(e) & (e.type.typ = PROG.tARRAY) & (e.type.base.typ IN {PROG.tCHAR, PROG.tWCHAR}) |
||
149 | END isCharArrayX; |
||
150 | |||
151 | |||
152 | PROCEDURE isPtr (e: PARS.EXPR): BOOLEAN; |
||
153 | RETURN isExpr(e) & (e.type.typ = PROG.tPOINTER) |
||
154 | END isPtr; |
||
155 | |||
156 | |||
157 | PROCEDURE isRec (e: PARS.EXPR): BOOLEAN; |
||
158 | RETURN isExpr(e) & (e.type.typ = PROG.tRECORD) |
||
159 | END isRec; |
||
160 | |||
161 | |||
162 | PROCEDURE isArr (e: PARS.EXPR): BOOLEAN; |
||
163 | RETURN isExpr(e) & (e.type.typ = PROG.tARRAY) |
||
164 | END isArr; |
||
165 | |||
166 | |||
167 | PROCEDURE isProc (e: PARS.EXPR): BOOLEAN; |
||
168 | RETURN isExpr(e) & (e.type.typ = PROG.tPROCEDURE) OR (e.obj IN {ePROC, eIMP}) |
||
169 | END isProc; |
||
170 | |||
171 | |||
172 | PROCEDURE isNil (e: PARS.EXPR): BOOLEAN; |
||
173 | RETURN e.type.typ = PROG.tNIL |
||
174 | END isNil; |
||
175 | |||
176 | |||
177 | PROCEDURE getpos (parser: PARS.PARSER; VAR pos: SCAN.POSITION); |
||
178 | BEGIN |
||
179 | pos := parser.lex.pos |
||
180 | END getpos; |
||
181 | |||
182 | |||
183 | PROCEDURE NextPos (parser: PARS.PARSER; VAR pos: SCAN.POSITION); |
||
184 | BEGIN |
||
185 | PARS.NextPos(parser, pos) |
||
186 | END NextPos; |
||
187 | |||
188 | |||
189 | PROCEDURE strlen (e: PARS.EXPR): INTEGER; |
||
190 | VAR |
||
191 | res: INTEGER; |
||
192 | |||
193 | BEGIN |
||
194 | ASSERT(isString(e)); |
||
195 | IF e.type.typ = PROG.tCHAR THEN |
||
196 | res := 1 |
||
197 | ELSE |
||
198 | res := LENGTH(e.value.string(SCAN.IDENT).s) |
||
199 | END |
||
200 | RETURN res |
||
201 | END strlen; |
||
202 | |||
203 | |||
204 | PROCEDURE _length (s: ARRAY OF CHAR): INTEGER; |
||
205 | VAR |
||
206 | i, res: INTEGER; |
||
207 | |||
208 | BEGIN |
||
209 | i := 0; |
||
210 | res := 0; |
||
211 | WHILE (i < LEN(s)) & (s[i] # 0X) DO |
||
212 | IF (s[i] <= CHR(127)) OR (s[i] >= CHR(192)) THEN |
||
213 | INC(res) |
||
214 | END; |
||
215 | INC(i) |
||
216 | END |
||
217 | |||
218 | RETURN res |
||
219 | END _length; |
||
220 | |||
221 | |||
222 | PROCEDURE utf8strlen (e: PARS.EXPR): INTEGER; |
||
223 | VAR |
||
224 | res: INTEGER; |
||
225 | |||
226 | BEGIN |
||
227 | ASSERT(isStringW(e)); |
||
228 | IF e.type.typ IN {PROG.tCHAR, PROG.tWCHAR} THEN |
||
229 | res := 1 |
||
230 | ELSE |
||
231 | res := _length(e.value.string(SCAN.IDENT).s) |
||
232 | END |
||
233 | RETURN res |
||
234 | END utf8strlen; |
||
235 | |||
236 | |||
237 | PROCEDURE StrToWChar (s: ARRAY OF CHAR): INTEGER; |
||
238 | VAR |
||
239 | res: ARRAY 2 OF WCHAR; |
||
240 | |||
241 | BEGIN |
||
242 | ASSERT(STRINGS.Utf8To16(s, res) = 1) |
||
243 | RETURN ORD(res[0]) |
||
244 | END StrToWChar; |
||
245 | |||
246 | |||
247 | PROCEDURE isStringW1 (e: PARS.EXPR): BOOLEAN; |
||
248 | RETURN (e.obj = eCONST) & isString(e) & (utf8strlen(e) = 1) & (strlen(e) > 1) |
||
249 | END isStringW1; |
||
250 | |||
251 | |||
252 | PROCEDURE assigncomp (e: PARS.EXPR; t: PROG.TYPE_): BOOLEAN; |
||
253 | VAR |
||
254 | res: BOOLEAN; |
||
255 | |||
256 | |||
257 | PROCEDURE arrcomp (src, dst: PROG.TYPE_): BOOLEAN; |
||
258 | RETURN (dst.typ = PROG.tARRAY) & PROG.isOpenArray(src) & |
||
259 | ~PROG.isOpenArray(src.base) & ~PROG.isOpenArray(dst.base) & |
||
260 | PROG.isTypeEq(src.base, dst.base) |
||
261 | END arrcomp; |
||
262 | |||
263 | |||
264 | BEGIN |
||
265 | IF isExpr(e) OR (e.obj IN {ePROC, eIMP}) THEN |
||
266 | IF arrcomp(e.type, t) THEN |
||
267 | res := TRUE |
||
268 | ELSIF isInt(e) & (t.typ IN {PROG.tBYTE, PROG.tINTEGER}) THEN |
||
269 | IF (e.obj = eCONST) & (t.typ = PROG.tBYTE) THEN |
||
270 | res := ARITH.range(e.value, 0, 255) |
||
271 | ELSE |
||
272 | res := TRUE |
||
273 | END |
||
274 | ELSIF isSet(e) & (t.typ = PROG.tSET) THEN |
||
275 | res := TRUE |
||
276 | ELSIF isBoolean(e) & (t.typ = PROG.tBOOLEAN) THEN |
||
277 | res := TRUE |
||
278 | ELSIF isReal(e) & (t.typ = PROG.tREAL) THEN |
||
279 | res := TRUE |
||
280 | ELSIF isChar(e) & (t.typ = PROG.tCHAR) THEN |
||
281 | res := TRUE |
||
282 | ELSIF (e.obj = eCONST) & isChar(e) & (t.typ = PROG.tWCHAR) THEN |
||
283 | res := TRUE |
||
284 | ELSIF isStringW1(e) & (t.typ = PROG.tWCHAR) THEN |
||
285 | res := TRUE |
||
286 | ELSIF isCharW(e) & (t.typ = PROG.tWCHAR) THEN |
||
287 | res := TRUE |
||
288 | ELSIF PROG.isBaseOf(t, e.type) THEN |
||
289 | res := TRUE |
||
290 | ELSIF ~PROG.isOpenArray(t) & ~PROG.isOpenArray(e.type) & PROG.isTypeEq(t, e.type) THEN |
||
291 | res := TRUE |
||
292 | ELSIF isNil(e) & (t.typ IN {PROG.tPOINTER, PROG.tPROCEDURE}) THEN |
||
293 | res := TRUE |
||
294 | ELSIF isString(e) & ((t.typ = PROG.tARRAY) & (t.base.typ = PROG.tCHAR) & (t.length > strlen(e))) THEN |
||
295 | res := TRUE |
||
296 | ELSIF isStringW(e) & ((t.typ = PROG.tARRAY) & (t.base.typ = PROG.tWCHAR) & (t.length > utf8strlen(e))) THEN |
||
297 | res := TRUE |
||
298 | ELSE |
||
299 | res := FALSE |
||
300 | END |
||
301 | ELSE |
||
302 | res := FALSE |
||
303 | END |
||
304 | RETURN res |
||
305 | END assigncomp; |
||
306 | |||
307 | |||
308 | PROCEDURE String (e: PARS.EXPR): INTEGER; |
||
309 | VAR |
||
310 | offset: INTEGER; |
||
311 | string: SCAN.IDENT; |
||
312 | |||
313 | BEGIN |
||
314 | IF strlen(e) # 1 THEN |
||
315 | string := e.value.string(SCAN.IDENT); |
||
316 | IF string.offset = -1 THEN |
||
317 | string.offset := CODE.putstr(string.s); |
||
318 | END; |
||
319 | offset := string.offset |
||
320 | ELSE |
||
321 | offset := CODE.putstr1(ARITH.Int(e.value)) |
||
322 | END |
||
323 | |||
324 | RETURN offset |
||
325 | END String; |
||
326 | |||
327 | |||
328 | PROCEDURE StringW (e: PARS.EXPR): INTEGER; |
||
329 | VAR |
||
330 | offset: INTEGER; |
||
331 | string: SCAN.IDENT; |
||
332 | |||
333 | BEGIN |
||
334 | IF utf8strlen(e) # 1 THEN |
||
335 | string := e.value.string(SCAN.IDENT); |
||
336 | IF string.offsetW = -1 THEN |
||
337 | string.offsetW := CODE.putstrW(string.s); |
||
338 | END; |
||
339 | offset := string.offsetW |
||
340 | ELSE |
||
341 | IF e.type.typ IN {PROG.tWCHAR, PROG.tCHAR} THEN |
||
342 | offset := CODE.putstrW1(ARITH.Int(e.value)) |
||
343 | ELSE (* e.type.typ = PROG.tSTRING *) |
||
344 | string := e.value.string(SCAN.IDENT); |
||
345 | IF string.offsetW = -1 THEN |
||
346 | string.offsetW := CODE.putstrW(string.s); |
||
347 | END; |
||
348 | offset := string.offsetW |
||
349 | END |
||
350 | END |
||
351 | |||
352 | RETURN offset |
||
353 | END StringW; |
||
354 | |||
355 | |||
356 | PROCEDURE CheckRange (range, line, errno: INTEGER); |
||
357 | VAR |
||
358 | label: INTEGER; |
||
359 | |||
360 | BEGIN |
||
361 | label := CODE.NewLabel(); |
||
362 | CODE.AddCmd2(CODE.opCHKIDX, label, range); |
||
363 | CODE.OnError(line, errno); |
||
364 | CODE.SetLabel(label) |
||
365 | END CheckRange; |
||
366 | |||
367 | |||
368 | PROCEDURE assign (e: PARS.EXPR; VarType: PROG.TYPE_; line: INTEGER): BOOLEAN; |
||
369 | VAR |
||
370 | res: BOOLEAN; |
||
371 | label: INTEGER; |
||
372 | |||
373 | |||
374 | PROCEDURE arrcomp (src, dst: PROG.TYPE_): BOOLEAN; |
||
375 | RETURN (dst.typ = PROG.tARRAY) & PROG.isOpenArray(src) & |
||
376 | ~PROG.isOpenArray(src.base) & ~PROG.isOpenArray(dst.base) & |
||
377 | PROG.isTypeEq(src.base, dst.base) |
||
378 | END arrcomp; |
||
379 | |||
380 | |||
381 | BEGIN |
||
382 | IF isExpr(e) OR (e.obj IN {ePROC, eIMP}) THEN |
||
383 | res := TRUE; |
||
384 | IF arrcomp(e.type, VarType) THEN |
||
385 | |||
386 | IF ~PROG.isOpenArray(VarType) THEN |
||
387 | CODE.AddCmd(CODE.opCONST, VarType.length) |
||
388 | END; |
||
389 | CODE.AddCmd(CODE.opCOPYA, VarType.base.size); |
||
390 | label := CODE.NewLabel(); |
||
391 | CODE.AddJmpCmd(CODE.opJE, label); |
||
392 | CODE.OnError(line, errCOPY); |
||
393 | CODE.SetLabel(label) |
||
394 | |||
395 | ELSIF isInt(e) & (VarType.typ IN {PROG.tBYTE, PROG.tINTEGER}) THEN |
||
396 | IF VarType.typ = PROG.tINTEGER THEN |
||
397 | IF e.obj = eCONST THEN |
||
398 | CODE.AddCmd(CODE.opSAVEC, ARITH.Int(e.value)) |
||
399 | ELSE |
||
400 | CODE.AddCmd0(CODE.opSAVE) |
||
401 | END |
||
402 | ELSE |
||
403 | IF e.obj = eCONST THEN |
||
404 | res := ARITH.range(e.value, 0, 255); |
||
405 | IF res THEN |
||
406 | CODE.AddCmd(CODE.opSAVE8C, ARITH.Int(e.value)) |
||
407 | END |
||
408 | ELSE |
||
409 | IF chkBYTE IN checking THEN |
||
410 | label := CODE.NewLabel(); |
||
411 | CODE.AddCmd2(CODE.opCHKBYTE, label, 0); |
||
412 | CODE.OnError(line, errBYTE); |
||
413 | CODE.SetLabel(label) |
||
414 | END; |
||
415 | CODE.AddCmd0(CODE.opSAVE8) |
||
416 | END |
||
417 | END |
||
418 | ELSIF isSet(e) & (VarType.typ = PROG.tSET) THEN |
||
419 | IF e.obj = eCONST THEN |
||
420 | CODE.AddCmd(CODE.opSAVEC, ARITH.Int(e.value)) |
||
421 | ELSE |
||
422 | CODE.AddCmd0(CODE.opSAVE) |
||
423 | END |
||
424 | ELSIF isBoolean(e) & (VarType.typ = PROG.tBOOLEAN) THEN |
||
425 | IF e.obj = eCONST THEN |
||
426 | CODE.AddCmd(CODE.opSBOOLC, ARITH.Int(e.value)) |
||
427 | ELSE |
||
428 | CODE.AddCmd0(CODE.opSBOOL) |
||
429 | END |
||
430 | ELSIF isReal(e) & (VarType.typ = PROG.tREAL) THEN |
||
431 | IF e.obj = eCONST THEN |
||
432 | CODE.Float(ARITH.Float(e.value)) |
||
433 | END; |
||
434 | CODE.savef |
||
435 | ELSIF isChar(e) & (VarType.typ = PROG.tCHAR) THEN |
||
436 | IF e.obj = eCONST THEN |
||
437 | CODE.AddCmd(CODE.opSAVE8C, ARITH.Int(e.value)) |
||
438 | ELSE |
||
439 | CODE.AddCmd0(CODE.opSAVE8) |
||
440 | END |
||
441 | ELSIF (e.obj = eCONST) & isChar(e) & (VarType.typ = PROG.tWCHAR) THEN |
||
442 | CODE.AddCmd(CODE.opSAVE16C, ARITH.Int(e.value)) |
||
443 | ELSIF isStringW1(e) & (VarType.typ = PROG.tWCHAR) THEN |
||
444 | CODE.AddCmd(CODE.opSAVE16C, StrToWChar(e.value.string(SCAN.IDENT).s)) |
||
445 | ELSIF isCharW(e) & (VarType.typ = PROG.tWCHAR) THEN |
||
446 | IF e.obj = eCONST THEN |
||
447 | CODE.AddCmd(CODE.opSAVE16C, ARITH.Int(e.value)) |
||
448 | ELSE |
||
449 | CODE.AddCmd0(CODE.opSAVE16) |
||
450 | END |
||
451 | ELSIF PROG.isBaseOf(VarType, e.type) THEN |
||
452 | IF VarType.typ = PROG.tPOINTER THEN |
||
453 | CODE.AddCmd0(CODE.opSAVE) |
||
454 | ELSE |
||
455 | CODE.AddCmd(CODE.opCOPY, VarType.size) |
||
456 | END |
||
457 | ELSIF (e.type.typ = PROG.tCARD32) & (VarType.typ = PROG.tCARD32) THEN |
||
458 | CODE.AddCmd0(CODE.opSAVE32) |
||
459 | ELSIF (e.type.typ = PROG.tCARD16) & (VarType.typ = PROG.tCARD16) THEN |
||
460 | CODE.AddCmd0(CODE.opSAVE16) |
||
461 | ELSIF ~PROG.isOpenArray(VarType) & ~PROG.isOpenArray(e.type) & PROG.isTypeEq(VarType, e.type) THEN |
||
462 | IF e.obj = ePROC THEN |
||
463 | CODE.AssignProc(e.ident.proc.label) |
||
464 | ELSIF e.obj = eIMP THEN |
||
465 | CODE.AssignImpProc(e.ident.import) |
||
466 | ELSE |
||
467 | IF VarType.typ = PROG.tPROCEDURE THEN |
||
468 | CODE.AddCmd0(CODE.opSAVE) |
||
469 | ELSE |
||
470 | CODE.AddCmd(CODE.opCOPY, VarType.size) |
||
471 | END |
||
472 | END |
||
473 | ELSIF isNil(e) & (VarType.typ IN {PROG.tPOINTER, PROG.tPROCEDURE}) THEN |
||
474 | CODE.AddCmd(CODE.opSAVEC, 0) |
||
475 | ELSIF isString(e) & ((VarType.typ = PROG.tARRAY) & (VarType.base.typ = PROG.tCHAR) & (VarType.length > strlen(e))) THEN |
||
476 | CODE.saves(String(e), strlen(e) + 1) |
||
477 | ELSIF isStringW(e) & ((VarType.typ = PROG.tARRAY) & (VarType.base.typ = PROG.tWCHAR) & (VarType.length > utf8strlen(e))) THEN |
||
478 | CODE.saves(StringW(e), (utf8strlen(e) + 1) * 2) |
||
479 | ELSE |
||
480 | res := FALSE |
||
481 | END |
||
482 | ELSE |
||
483 | res := FALSE |
||
484 | END |
||
485 | RETURN res |
||
486 | END assign; |
||
487 | |||
488 | |||
489 | PROCEDURE LoadConst (e: PARS.EXPR); |
||
490 | BEGIN |
||
491 | CODE.AddCmd(CODE.opCONST, ARITH.Int(e.value)) |
||
492 | END LoadConst; |
||
493 | |||
494 | |||
495 | PROCEDURE paramcomp (parser: PARS.PARSER; pos: SCAN.POSITION; e: PARS.EXPR; p: PROG.PARAM); |
||
496 | |||
497 | PROCEDURE arrcomp (e: PARS.EXPR; p: PROG.PARAM): BOOLEAN; |
||
498 | VAR |
||
499 | t1, t2: PROG.TYPE_; |
||
500 | |||
501 | BEGIN |
||
502 | t1 := p.type; |
||
503 | t2 := e.type; |
||
504 | WHILE (t2.typ = PROG.tARRAY) & PROG.isOpenArray(t1) DO |
||
505 | t1 := t1.base; |
||
506 | t2 := t2.base |
||
507 | END |
||
508 | |||
509 | RETURN PROG.isTypeEq(t1, t2) |
||
510 | END arrcomp; |
||
511 | |||
512 | |||
513 | PROCEDURE ArrLen (t: PROG.TYPE_; n: INTEGER): INTEGER; |
||
514 | VAR |
||
515 | res: INTEGER; |
||
516 | BEGIN |
||
517 | REPEAT |
||
518 | res := t.length; |
||
519 | t := t.base; |
||
520 | DEC(n) |
||
521 | UNTIL (n < 0) OR (t.typ # PROG.tARRAY); |
||
522 | ASSERT(n < 0) |
||
523 | RETURN res |
||
524 | END ArrLen; |
||
525 | |||
526 | |||
527 | PROCEDURE OpenArray (t, t2: PROG.TYPE_); |
||
528 | VAR |
||
529 | n: INTEGER; |
||
530 | d1, d2: INTEGER; |
||
531 | BEGIN |
||
532 | IF t.length # 0 THEN |
||
533 | CODE.AddCmd(CODE.opPARAM, 1); |
||
534 | n := PROG.Dim(t2) - 1; |
||
535 | WHILE n >= 0 DO |
||
536 | CODE.AddCmd(CODE.opCONST, ArrLen(t, n)); |
||
537 | CODE.AddCmd(CODE.opPARAM, 1); |
||
538 | DEC(n) |
||
539 | END |
||
540 | ELSE |
||
541 | d1 := PROG.Dim(t); |
||
542 | d2 := PROG.Dim(t2); |
||
543 | IF d1 # d2 THEN |
||
544 | n := d2 - d1; |
||
545 | WHILE d2 > d1 DO |
||
546 | CODE.AddCmd(CODE.opCONST, ArrLen(t, d2 - 1)); |
||
547 | DEC(d2) |
||
548 | END; |
||
549 | d2 := PROG.Dim(t2); |
||
550 | WHILE n > 0 DO |
||
551 | CODE.AddCmd(CODE.opROT, d2); |
||
552 | DEC(n) |
||
553 | END |
||
554 | END; |
||
555 | CODE.AddCmd(CODE.opPARAM, PROG.Dim(t2) + 1) |
||
556 | END |
||
557 | END OpenArray; |
||
558 | |||
559 | |||
560 | BEGIN |
||
561 | IF p.vPar THEN |
||
562 | |||
563 | PARS.check(isVar(e), parser, pos, 93); |
||
564 | IF p.type.typ = PROG.tRECORD THEN |
||
565 | PARS.check(PROG.isBaseOf(p.type, e.type), parser, pos, 66); |
||
566 | IF e.obj = eVREC THEN |
||
567 | IF e.ident # NIL THEN |
||
568 | CODE.AddCmd(CODE.opVADR, e.ident.offset - 1) |
||
569 | ELSE |
||
570 | CODE.AddCmd0(CODE.opPUSHT) |
||
571 | END |
||
572 | ELSE |
||
573 | CODE.AddCmd(CODE.opCONST, e.type.num) |
||
574 | END; |
||
575 | CODE.AddCmd(CODE.opPARAM, 2) |
||
576 | ELSIF PROG.isOpenArray(p.type) THEN |
||
577 | PARS.check(arrcomp(e, p), parser, pos, 66); |
||
578 | OpenArray(e.type, p.type) |
||
579 | ELSE |
||
580 | PARS.check(PROG.isTypeEq(e.type, p.type), parser, pos, 66); |
||
581 | CODE.AddCmd(CODE.opPARAM, 1) |
||
582 | END; |
||
583 | PARS.check(~e.readOnly, parser, pos, 94) |
||
584 | |||
585 | ELSE |
||
586 | PARS.check(isExpr(e) OR isProc(e), parser, pos, 66); |
||
587 | IF PROG.isOpenArray(p.type) THEN |
||
588 | IF e.type.typ = PROG.tARRAY THEN |
||
589 | PARS.check(arrcomp(e, p), parser, pos, 66); |
||
590 | OpenArray(e.type, p.type) |
||
591 | ELSIF isString(e) & (p.type.typ = PROG.tARRAY) & (p.type.base.typ = PROG.tCHAR) THEN |
||
592 | CODE.AddCmd(CODE.opSADR, String(e)); |
||
593 | CODE.AddCmd(CODE.opPARAM, 1); |
||
594 | CODE.AddCmd(CODE.opCONST, strlen(e) + 1); |
||
595 | CODE.AddCmd(CODE.opPARAM, 1) |
||
596 | ELSIF isStringW(e) & (p.type.typ = PROG.tARRAY) & (p.type.base.typ = PROG.tWCHAR) THEN |
||
597 | CODE.AddCmd(CODE.opSADR, StringW(e)); |
||
598 | CODE.AddCmd(CODE.opPARAM, 1); |
||
599 | CODE.AddCmd(CODE.opCONST, utf8strlen(e) + 1); |
||
600 | CODE.AddCmd(CODE.opPARAM, 1) |
||
601 | ELSE |
||
602 | PARS.error(parser, pos, 66) |
||
603 | END |
||
604 | ELSE |
||
605 | PARS.check(~PROG.isOpenArray(e.type), parser, pos, 66); |
||
606 | PARS.check(assigncomp(e, p.type), parser, pos, 66); |
||
607 | IF e.obj = eCONST THEN |
||
608 | IF e.type.typ = PROG.tREAL THEN |
||
609 | CODE.Float(ARITH.Float(e.value)); |
||
610 | CODE.pushf |
||
611 | ELSIF e.type.typ = PROG.tNIL THEN |
||
612 | CODE.AddCmd(CODE.opCONST, 0); |
||
613 | CODE.AddCmd(CODE.opPARAM, 1) |
||
614 | ELSIF isStringW1(e) & (p.type.typ = PROG.tWCHAR) THEN |
||
615 | CODE.AddCmd(CODE.opCONST, StrToWChar(e.value.string(SCAN.IDENT).s)); |
||
616 | CODE.AddCmd(CODE.opPARAM, 1) |
||
617 | ELSIF (e.type.typ = PROG.tSTRING) OR |
||
618 | (e.type.typ IN {PROG.tCHAR, PROG.tWCHAR}) & (p.type.typ = PROG.tARRAY) & (p.type.base.typ IN {PROG.tCHAR, PROG.tWCHAR}) THEN |
||
619 | CODE.SetMinDataSize(p.type.size); |
||
620 | IF p.type.base.typ = PROG.tCHAR THEN |
||
621 | CODE.AddCmd(CODE.opSADR, String(e)) |
||
622 | ELSE (* WCHAR *) |
||
623 | CODE.AddCmd(CODE.opSADR, StringW(e)) |
||
624 | END; |
||
625 | CODE.AddCmd(CODE.opPARAM, 1) |
||
626 | ELSE |
||
627 | LoadConst(e); |
||
628 | CODE.AddCmd(CODE.opPARAM, 1) |
||
629 | END |
||
630 | ELSIF e.obj = ePROC THEN |
||
631 | PARS.check(e.ident.global, parser, pos, 85); |
||
632 | CODE.PushProc(e.ident.proc.label); |
||
633 | CODE.AddCmd(CODE.opPARAM, 1) |
||
634 | ELSIF e.obj = eIMP THEN |
||
635 | CODE.PushImpProc(e.ident.import); |
||
636 | CODE.AddCmd(CODE.opPARAM, 1) |
||
637 | ELSIF isExpr(e) & (e.type.typ = PROG.tREAL) THEN |
||
638 | CODE.pushf |
||
639 | ELSE |
||
640 | IF (p.type.typ = PROG.tBYTE) & (e.type.typ = PROG.tINTEGER) & (chkBYTE IN checking) THEN |
||
641 | CheckRange(256, pos.line, errBYTE) |
||
642 | END; |
||
643 | CODE.AddCmd(CODE.opPARAM, 1) |
||
644 | END |
||
645 | END |
||
646 | |||
647 | END |
||
648 | END paramcomp; |
||
649 | |||
650 | |||
651 | PROCEDURE stProc (parser: PARS.PARSER; VAR e: PARS.EXPR); |
||
652 | VAR |
||
653 | e2: PARS.EXPR; |
||
654 | pos: SCAN.POSITION; |
||
655 | proc: INTEGER; |
||
656 | label: INTEGER; |
||
657 | n, i: INTEGER; |
||
658 | code: ARITH.VALUE; |
||
659 | e1: PARS.EXPR; |
||
660 | wchar: BOOLEAN; |
||
661 | cmd1, |
||
662 | cmd2: CODE.COMMAND; |
||
663 | |||
664 | |||
665 | PROCEDURE varparam (parser: PARS.PARSER; pos: SCAN.POSITION; isfunc: isXXX; readOnly: BOOLEAN; VAR e: PARS.EXPR); |
||
666 | BEGIN |
||
667 | parser.designator(parser, e); |
||
668 | PARS.check(isVar(e), parser, pos, 93); |
||
669 | PARS.check(isfunc(e), parser, pos, 66); |
||
670 | IF readOnly THEN |
||
671 | PARS.check(~e.readOnly, parser, pos, 94) |
||
672 | END |
||
673 | END varparam; |
||
674 | |||
675 | |||
676 | PROCEDURE shift_minmax (proc: INTEGER): CHAR; |
||
677 | VAR |
||
678 | res: CHAR; |
||
679 | BEGIN |
||
680 | CASE proc OF |
||
681 | |PROG.stASR: res := "A" |
||
682 | |PROG.stLSL: res := "L" |
||
683 | |PROG.stROR: res := "O" |
||
684 | |PROG.stLSR: res := "R" |
||
685 | |PROG.stMIN: res := "m" |
||
686 | |PROG.stMAX: res := "x" |
||
687 | END |
||
688 | RETURN res |
||
689 | END shift_minmax; |
||
690 | |||
691 | |||
692 | BEGIN |
||
693 | ASSERT(e.obj IN {eSTPROC, eSTFUNC, eSYSPROC, eSYSFUNC}); |
||
694 | |||
695 | getpos(parser, pos); |
||
696 | proc := e.stproc; |
||
697 | |||
698 | IF e.obj IN {eSYSPROC, eSYSFUNC} THEN |
||
699 | IF parser.unit.scopeLvl > 0 THEN |
||
700 | parser.unit.scopes[parser.unit.scopeLvl].enter(CODE.COMMAND).allocReg := FALSE |
||
701 | END |
||
702 | END; |
||
703 | |||
704 | IF e.obj IN {eSTPROC, eSYSPROC} THEN |
||
705 | |||
706 | CASE proc OF |
||
707 | |PROG.stASSERT: |
||
708 | parser.expression(parser, e); |
||
709 | PARS.check(isBoolean(e), parser, pos, 66); |
||
710 | IF e.obj = eCONST THEN |
||
711 | IF ~ARITH.getBool(e.value) THEN |
||
712 | CODE.OnError(pos.line, errASSERT) |
||
713 | END |
||
714 | ELSE |
||
715 | label := CODE.NewLabel(); |
||
716 | CODE.AddJmpCmd(CODE.opJE, label); |
||
717 | CODE.OnError(pos.line, errASSERT); |
||
718 | CODE.SetLabel(label) |
||
719 | END |
||
720 | |||
721 | |PROG.stINC, PROG.stDEC: |
||
722 | CODE.pushBegEnd(begcall, endcall); |
||
723 | varparam(parser, pos, isInt, TRUE, e); |
||
724 | IF e.type.typ = PROG.tINTEGER THEN |
||
725 | IF parser.sym = SCAN.lxCOMMA THEN |
||
726 | NextPos(parser, pos); |
||
727 | CODE.setlast(begcall); |
||
728 | parser.expression(parser, e2); |
||
729 | CODE.setlast(endcall.prev(CODE.COMMAND)); |
||
730 | PARS.check(isInt(e2), parser, pos, 66); |
||
731 | IF e2.obj = eCONST THEN |
||
732 | CODE.AddCmd(CODE.opINCC + ORD(proc = PROG.stDEC), ARITH.Int(e2.value)) |
||
733 | ELSE |
||
734 | CODE.AddCmd0(CODE.opINC + ORD(proc = PROG.stDEC)) |
||
735 | END |
||
736 | ELSE |
||
737 | CODE.AddCmd0(CODE.opINC1 + ORD(proc = PROG.stDEC)) |
||
738 | END |
||
739 | ELSE (* e.type.typ = PROG.tBYTE *) |
||
740 | IF parser.sym = SCAN.lxCOMMA THEN |
||
741 | NextPos(parser, pos); |
||
742 | CODE.setlast(begcall); |
||
743 | parser.expression(parser, e2); |
||
744 | CODE.setlast(endcall.prev(CODE.COMMAND)); |
||
745 | PARS.check(isInt(e2), parser, pos, 66); |
||
746 | IF e2.obj = eCONST THEN |
||
747 | CODE.AddCmd(CODE.opINCCB + ORD(proc = PROG.stDEC), ARITH.Int(e2.value)) |
||
748 | ELSE |
||
749 | CODE.AddCmd0(CODE.opINCB + ORD(proc = PROG.stDEC)) |
||
750 | END |
||
751 | ELSE |
||
752 | CODE.AddCmd0(CODE.opINC1B + ORD(proc = PROG.stDEC)) |
||
753 | END |
||
754 | END; |
||
755 | CODE.popBegEnd(begcall, endcall) |
||
756 | |||
757 | |PROG.stINCL, PROG.stEXCL: |
||
758 | CODE.pushBegEnd(begcall, endcall); |
||
759 | varparam(parser, pos, isSet, TRUE, e); |
||
760 | PARS.checklex(parser, SCAN.lxCOMMA); |
||
761 | NextPos(parser, pos); |
||
762 | CODE.setlast(begcall); |
||
763 | parser.expression(parser, e2); |
||
764 | CODE.setlast(endcall.prev(CODE.COMMAND)); |
||
765 | PARS.check(isInt(e2), parser, pos, 66); |
||
766 | IF e2.obj = eCONST THEN |
||
767 | PARS.check(ARITH.range(e2.value, 0, MACHINE.target.maxSet), parser, pos, 56); |
||
768 | CODE.AddCmd(CODE.opINCLC + ORD(proc = PROG.stEXCL), ARITH.Int(e2.value)) |
||
769 | ELSE |
||
770 | CODE.AddCmd0(CODE.opINCL + ORD(proc = PROG.stEXCL)) |
||
771 | END; |
||
772 | CODE.popBegEnd(begcall, endcall) |
||
773 | |||
774 | |PROG.stNEW: |
||
775 | varparam(parser, pos, isPtr, TRUE, e); |
||
776 | CODE.New(e.type.base.size, e.type.base.num) |
||
777 | |||
778 | |PROG.stDISPOSE: |
||
779 | varparam(parser, pos, isPtr, TRUE, e); |
||
780 | CODE.AddCmd0(CODE.opDISP) |
||
781 | |||
782 | |PROG.stPACK: |
||
783 | varparam(parser, pos, isReal, TRUE, e); |
||
784 | PARS.checklex(parser, SCAN.lxCOMMA); |
||
785 | NextPos(parser, pos); |
||
786 | parser.expression(parser, e2); |
||
787 | PARS.check(isInt(e2), parser, pos, 66); |
||
788 | IF e2.obj = eCONST THEN |
||
789 | CODE.AddCmd(CODE.opPACKC, ARITH.Int(e2.value)) |
||
790 | ELSE |
||
791 | CODE.AddCmd0(CODE.opPACK) |
||
792 | END |
||
793 | |||
794 | |PROG.stUNPK: |
||
795 | varparam(parser, pos, isReal, TRUE, e); |
||
796 | PARS.checklex(parser, SCAN.lxCOMMA); |
||
797 | NextPos(parser, pos); |
||
798 | varparam(parser, pos, isInteger, TRUE, e2); |
||
799 | CODE.AddCmd0(CODE.opUNPK) |
||
800 | |||
801 | |PROG.stCOPY: |
||
802 | parser.expression(parser, e); |
||
803 | IF isString(e) OR isCharArray(e) THEN |
||
804 | wchar := FALSE |
||
805 | ELSIF isStringW(e) OR isCharArrayW(e) THEN |
||
806 | wchar := TRUE |
||
807 | ELSE |
||
808 | PARS.check(FALSE, parser, pos, 66) |
||
809 | END; |
||
810 | |||
811 | IF isCharArrayX(e) & ~PROG.isOpenArray(e.type) THEN |
||
812 | CODE.AddCmd(CODE.opCONST, e.type.length) |
||
813 | END; |
||
814 | |||
815 | PARS.checklex(parser, SCAN.lxCOMMA); |
||
816 | NextPos(parser, pos); |
||
817 | |||
818 | IF wchar THEN |
||
819 | varparam(parser, pos, isCharArrayW, TRUE, e1) |
||
820 | ELSE |
||
821 | IF e.obj = eCONST THEN |
||
822 | varparam(parser, pos, isCharArrayX, TRUE, e1) |
||
823 | ELSE |
||
824 | varparam(parser, pos, isCharArray, TRUE, e1) |
||
825 | END; |
||
826 | |||
827 | wchar := e1.type.base.typ = PROG.tWCHAR |
||
828 | END; |
||
829 | |||
830 | IF ~PROG.isOpenArray(e1.type) THEN |
||
831 | CODE.AddCmd(CODE.opCONST, e1.type.length) |
||
832 | END; |
||
833 | |||
834 | IF e.obj = eCONST THEN |
||
835 | IF wchar THEN |
||
836 | CODE.AddCmd(CODE.opSADR, StringW(e)); |
||
837 | CODE.AddCmd(CODE.opCONST, utf8strlen(e) + 1) |
||
838 | ELSE |
||
839 | CODE.AddCmd(CODE.opSADR, String(e)); |
||
840 | CODE.AddCmd(CODE.opCONST, strlen(e) + 1) |
||
841 | END; |
||
842 | CODE.AddCmd(CODE.opCOPYS2, e1.type.base.size) |
||
843 | ELSE |
||
844 | CODE.AddCmd(CODE.opCOPYS, e1.type.base.size) |
||
845 | END |
||
846 | |||
847 | |PROG.sysGET: |
||
848 | parser.expression(parser, e); |
||
849 | PARS.check(isInt(e), parser, pos, 66); |
||
850 | IF e.obj = eCONST THEN |
||
851 | LoadConst(e) |
||
852 | END; |
||
853 | PARS.checklex(parser, SCAN.lxCOMMA); |
||
854 | NextPos(parser, pos); |
||
855 | parser.designator(parser, e2); |
||
856 | PARS.check(isVar(e2), parser, pos, 93); |
||
857 | PARS.check((e2.type.typ IN PROG.BASICTYPES) OR (e2.type.typ = PROG.tPOINTER) OR (e2.type.typ = PROG.tPROCEDURE), parser, pos, 66); |
||
858 | CODE.SysGet(e2.type.size) |
||
859 | |||
860 | |PROG.sysPUT, PROG.sysPUT8, PROG.sysPUT16, PROG.sysPUT32: |
||
861 | CODE.pushBegEnd(begcall, endcall); |
||
862 | parser.expression(parser, e); |
||
863 | PARS.check(isInt(e), parser, pos, 66); |
||
864 | IF e.obj = eCONST THEN |
||
865 | LoadConst(e) |
||
866 | END; |
||
867 | PARS.checklex(parser, SCAN.lxCOMMA); |
||
868 | NextPos(parser, pos); |
||
869 | CODE.setlast(begcall); |
||
870 | parser.expression(parser, e2); |
||
871 | PARS.check(isExpr(e2), parser, pos, 66); |
||
872 | |||
873 | IF proc = PROG.sysPUT THEN |
||
874 | PARS.check((e2.type.typ IN PROG.BASICTYPES) OR (e2.type.typ = PROG.tPOINTER) OR (e2.type.typ = PROG.tPROCEDURE), parser, pos, 66); |
||
875 | IF e2.obj = eCONST THEN |
||
876 | IF e2.type.typ = PROG.tREAL THEN |
||
877 | CODE.setlast(endcall.prev(CODE.COMMAND)); |
||
878 | CODE.Float(ARITH.Float(e2.value)); |
||
879 | CODE.savef |
||
880 | ELSE |
||
881 | LoadConst(e2); |
||
882 | CODE.setlast(endcall.prev(CODE.COMMAND)); |
||
883 | CODE.SysPut(e2.type.size) |
||
884 | END |
||
885 | ELSE |
||
886 | CODE.setlast(endcall.prev(CODE.COMMAND)); |
||
887 | IF e2.type.typ = PROG.tREAL THEN |
||
888 | CODE.savef |
||
889 | ELSIF e2.type.typ = PROG.tBYTE THEN |
||
890 | CODE.SysPut(PARS.program.stTypes.tINTEGER.size) |
||
891 | ELSE |
||
892 | CODE.SysPut(e2.type.size) |
||
893 | END |
||
894 | END |
||
895 | |||
896 | ELSIF (proc = PROG.sysPUT8) OR (proc = PROG.sysPUT16) OR (proc = PROG.sysPUT32) THEN |
||
897 | PARS.check(e2.type.typ IN {PROG.tINTEGER, PROG.tBYTE, PROG.tCHAR, PROG.tWCHAR, PROG.tCARD16, PROG.tCARD32}, parser, pos, 66); |
||
898 | IF e2.obj = eCONST THEN |
||
899 | LoadConst(e2) |
||
900 | END; |
||
901 | CODE.setlast(endcall.prev(CODE.COMMAND)); |
||
902 | IF proc = PROG.sysPUT8 THEN |
||
903 | CODE.SysPut(1) |
||
904 | ELSIF proc = PROG.sysPUT16 THEN |
||
905 | CODE.SysPut(2) |
||
906 | ELSIF proc = PROG.sysPUT32 THEN |
||
907 | CODE.SysPut(4) |
||
908 | END |
||
909 | |||
910 | END; |
||
911 | CODE.popBegEnd(begcall, endcall) |
||
912 | |||
913 | |PROG.sysMOVE: |
||
914 | FOR i := 1 TO 2 DO |
||
915 | parser.expression(parser, e); |
||
916 | PARS.check(isInt(e), parser, pos, 66); |
||
917 | IF e.obj = eCONST THEN |
||
918 | LoadConst(e) |
||
919 | END; |
||
920 | PARS.checklex(parser, SCAN.lxCOMMA); |
||
921 | NextPos(parser, pos) |
||
922 | END; |
||
923 | |||
924 | parser.expression(parser, e); |
||
925 | PARS.check(isInt(e), parser, pos, 66); |
||
926 | IF e.obj = eCONST THEN |
||
927 | LoadConst(e) |
||
928 | END; |
||
929 | CODE.AddCmd0(CODE.opMOVE) |
||
930 | |||
931 | |PROG.sysCOPY: |
||
932 | FOR i := 1 TO 2 DO |
||
933 | parser.designator(parser, e); |
||
934 | PARS.check(isVar(e), parser, pos, 93); |
||
935 | n := PROG.Dim(e.type); |
||
936 | WHILE n > 0 DO |
||
937 | CODE.drop; |
||
938 | DEC(n) |
||
939 | END; |
||
940 | PARS.checklex(parser, SCAN.lxCOMMA); |
||
941 | NextPos(parser, pos) |
||
942 | END; |
||
943 | |||
944 | parser.expression(parser, e); |
||
945 | PARS.check(isInt(e), parser, pos, 66); |
||
946 | IF e.obj = eCONST THEN |
||
947 | LoadConst(e) |
||
948 | END; |
||
949 | CODE.AddCmd0(CODE.opMOVE) |
||
950 | |||
951 | |PROG.sysCODE: |
||
952 | REPEAT |
||
953 | getpos(parser, pos); |
||
954 | PARS.ConstExpression(parser, code); |
||
955 | PARS.check(code.typ = ARITH.tINTEGER, parser, pos, 43); |
||
956 | PARS.check(ARITH.range(code, 0, 255), parser, pos, 42); |
||
957 | IF parser.sym = SCAN.lxCOMMA THEN |
||
958 | PARS.Next(parser) |
||
959 | ELSE |
||
960 | PARS.checklex(parser, SCAN.lxRROUND) |
||
961 | END; |
||
962 | CODE.AddCmd(CODE.opCODE, ARITH.getInt(code)) |
||
963 | UNTIL parser.sym = SCAN.lxRROUND |
||
964 | |||
965 | END; |
||
966 | |||
967 | e.obj := eEXPR; |
||
968 | e.type := NIL |
||
969 | |||
970 | ELSIF e.obj IN {eSTFUNC, eSYSFUNC} THEN |
||
971 | |||
972 | CASE e.stproc OF |
||
973 | |PROG.stABS: |
||
974 | parser.expression(parser, e); |
||
975 | PARS.check(isInt(e) OR isReal(e), parser, pos, 66); |
||
976 | IF e.obj = eCONST THEN |
||
977 | PARS.check(ARITH.abs(e.value), parser, pos, 39) |
||
978 | ELSE |
||
979 | CODE.abs(isReal(e)) |
||
980 | END |
||
981 | |||
982 | |PROG.stASR, PROG.stLSL, PROG.stROR, PROG.stLSR, PROG.stMIN, PROG.stMAX: |
||
983 | parser.expression(parser, e); |
||
984 | PARS.check(isInt(e), parser, pos, 66); |
||
985 | PARS.checklex(parser, SCAN.lxCOMMA); |
||
986 | NextPos(parser, pos); |
||
987 | parser.expression(parser, e2); |
||
988 | PARS.check(isInt(e2), parser, pos, 66); |
||
989 | e.type := PARS.program.stTypes.tINTEGER; |
||
990 | IF (e.obj = eCONST) & (e2.obj = eCONST) THEN |
||
991 | ASSERT(ARITH.opInt(e.value, e2.value, shift_minmax(proc))) |
||
992 | ELSE |
||
993 | IF e.obj = eCONST THEN |
||
994 | CODE.shift_minmax1(shift_minmax(proc), ARITH.Int(e.value)) |
||
995 | ELSIF e2.obj = eCONST THEN |
||
996 | CODE.shift_minmax2(shift_minmax(proc), ARITH.Int(e2.value)) |
||
997 | ELSE |
||
998 | CODE.shift_minmax(shift_minmax(proc)) |
||
999 | END; |
||
1000 | e.obj := eEXPR |
||
1001 | END |
||
1002 | |||
1003 | |PROG.stCHR: |
||
1004 | parser.expression(parser, e); |
||
1005 | PARS.check(isInt(e), parser, pos, 66); |
||
1006 | e.type := PARS.program.stTypes.tCHAR; |
||
1007 | IF e.obj = eCONST THEN |
||
1008 | ARITH.setChar(e.value, ARITH.getInt(e.value)); |
||
1009 | PARS.check(ARITH.check(e.value), parser, pos, 107) |
||
1010 | ELSE |
||
1011 | IF chkCHR IN checking THEN |
||
1012 | CheckRange(256, pos.line, errCHR) |
||
1013 | ELSE |
||
1014 | CODE.AddCmd0(CODE.opCHR) |
||
1015 | END |
||
1016 | END |
||
1017 | |||
1018 | |PROG.stWCHR: |
||
1019 | parser.expression(parser, e); |
||
1020 | PARS.check(isInt(e), parser, pos, 66); |
||
1021 | e.type := PARS.program.stTypes.tWCHAR; |
||
1022 | IF e.obj = eCONST THEN |
||
1023 | ARITH.setWChar(e.value, ARITH.getInt(e.value)); |
||
1024 | PARS.check(ARITH.check(e.value), parser, pos, 101) |
||
1025 | ELSE |
||
1026 | IF chkWCHR IN checking THEN |
||
1027 | CheckRange(65536, pos.line, errWCHR) |
||
1028 | ELSE |
||
1029 | CODE.AddCmd0(CODE.opWCHR) |
||
1030 | END |
||
1031 | END |
||
1032 | |||
1033 | |PROG.stFLOOR: |
||
1034 | parser.expression(parser, e); |
||
1035 | PARS.check(isReal(e), parser, pos, 66); |
||
1036 | e.type := PARS.program.stTypes.tINTEGER; |
||
1037 | IF e.obj = eCONST THEN |
||
1038 | PARS.check(ARITH.floor(e.value), parser, pos, 39) |
||
1039 | ELSE |
||
1040 | CODE.floor |
||
1041 | END |
||
1042 | |||
1043 | |PROG.stFLT: |
||
1044 | parser.expression(parser, e); |
||
1045 | PARS.check(isInt(e), parser, pos, 66); |
||
1046 | e.type := PARS.program.stTypes.tREAL; |
||
1047 | IF e.obj = eCONST THEN |
||
1048 | ARITH.flt(e.value) |
||
1049 | ELSE |
||
1050 | PARS.check(CODE.flt(), parser, pos, 41) |
||
1051 | END |
||
1052 | |||
1053 | |PROG.stLEN: |
||
1054 | cmd1 := CODE.getlast(); |
||
1055 | varparam(parser, pos, isArr, FALSE, e); |
||
1056 | IF e.type.length > 0 THEN |
||
1057 | cmd2 := CODE.getlast(); |
||
1058 | CODE.delete2(cmd1.next, cmd2); |
||
1059 | CODE.setlast(cmd1); |
||
1060 | ASSERT(ARITH.setInt(e.value, e.type.length)); |
||
1061 | e.obj := eCONST |
||
1062 | ELSE |
||
1063 | CODE.len(PROG.Dim(e.type)) |
||
1064 | END; |
||
1065 | e.type := PARS.program.stTypes.tINTEGER |
||
1066 | |||
1067 | |PROG.stLENGTH: |
||
1068 | parser.expression(parser, e); |
||
1069 | IF isCharArray(e) THEN |
||
1070 | IF e.type.length > 0 THEN |
||
1071 | CODE.AddCmd(CODE.opCONST, e.type.length) |
||
1072 | END; |
||
1073 | CODE.AddCmd0(CODE.opLENGTH) |
||
1074 | ELSIF isCharArrayW(e) THEN |
||
1075 | IF e.type.length > 0 THEN |
||
1076 | CODE.AddCmd(CODE.opCONST, e.type.length) |
||
1077 | END; |
||
1078 | CODE.AddCmd0(CODE.opLENGTHW) |
||
1079 | ELSE |
||
1080 | PARS.check(FALSE, parser, pos, 66); |
||
1081 | END; |
||
1082 | e.type := PARS.program.stTypes.tINTEGER |
||
1083 | |||
1084 | |PROG.stODD: |
||
1085 | parser.expression(parser, e); |
||
1086 | PARS.check(isInt(e), parser, pos, 66); |
||
1087 | e.type := PARS.program.stTypes.tBOOLEAN; |
||
1088 | IF e.obj = eCONST THEN |
||
1089 | ARITH.odd(e.value) |
||
1090 | ELSE |
||
1091 | CODE.odd |
||
1092 | END |
||
1093 | |||
1094 | |PROG.stORD: |
||
1095 | parser.expression(parser, e); |
||
1096 | PARS.check(isChar(e) OR isBoolean(e) OR isSet(e) OR isCharW(e) OR isStringW1(e), parser, pos, 66); |
||
1097 | IF e.obj = eCONST THEN |
||
1098 | IF isStringW1(e) THEN |
||
1099 | ASSERT(ARITH.setInt(e.value, StrToWChar(e.value.string(SCAN.IDENT).s))) |
||
1100 | ELSE |
||
1101 | ARITH.ord(e.value) |
||
1102 | END |
||
1103 | ELSE |
||
1104 | IF isBoolean(e) THEN |
||
1105 | CODE.ord |
||
1106 | END |
||
1107 | END; |
||
1108 | e.type := PARS.program.stTypes.tINTEGER |
||
1109 | |||
1110 | |PROG.stBITS: |
||
1111 | parser.expression(parser, e); |
||
1112 | PARS.check(isInt(e), parser, pos, 66); |
||
1113 | IF e.obj = eCONST THEN |
||
1114 | ARITH.bits(e.value) |
||
1115 | END; |
||
1116 | e.type := PARS.program.stTypes.tSET |
||
1117 | |||
1118 | |PROG.sysADR: |
||
1119 | parser.designator(parser, e); |
||
1120 | IF isVar(e) THEN |
||
1121 | n := PROG.Dim(e.type); |
||
1122 | WHILE n > 0 DO |
||
1123 | CODE.drop; |
||
1124 | DEC(n) |
||
1125 | END |
||
1126 | ELSIF e.obj = ePROC THEN |
||
1127 | CODE.PushProc(e.ident.proc.label) |
||
1128 | ELSIF e.obj = eIMP THEN |
||
1129 | CODE.PushImpProc(e.ident.import) |
||
1130 | ELSE |
||
1131 | PARS.check(FALSE, parser, pos, 108) |
||
1132 | END; |
||
1133 | e.type := PARS.program.stTypes.tINTEGER |
||
1134 | |||
1135 | |PROG.sysSADR: |
||
1136 | parser.expression(parser, e); |
||
1137 | PARS.check(isString(e), parser, pos, 66); |
||
1138 | CODE.AddCmd(CODE.opSADR, String(e)); |
||
1139 | e.type := PARS.program.stTypes.tINTEGER; |
||
1140 | e.obj := eEXPR |
||
1141 | |||
1142 | |PROG.sysWSADR: |
||
1143 | parser.expression(parser, e); |
||
1144 | PARS.check(isStringW(e), parser, pos, 66); |
||
1145 | CODE.AddCmd(CODE.opSADR, StringW(e)); |
||
1146 | e.type := PARS.program.stTypes.tINTEGER; |
||
1147 | e.obj := eEXPR |
||
1148 | |||
1149 | |PROG.sysTYPEID: |
||
1150 | parser.expression(parser, e); |
||
1151 | PARS.check(e.obj = eTYPE, parser, pos, 68); |
||
1152 | IF e.type.typ = PROG.tRECORD THEN |
||
1153 | ASSERT(ARITH.setInt(e.value, e.type.num)) |
||
1154 | ELSIF e.type.typ = PROG.tPOINTER THEN |
||
1155 | ASSERT(ARITH.setInt(e.value, e.type.base.num)) |
||
1156 | ELSE |
||
1157 | PARS.check(FALSE, parser, pos, 52) |
||
1158 | END; |
||
1159 | e.obj := eCONST; |
||
1160 | e.type := PARS.program.stTypes.tINTEGER |
||
1161 | |||
1162 | |PROG.sysINF: |
||
1163 | PARS.check(CODE.inf(), parser, pos, 41); |
||
1164 | e.obj := eEXPR; |
||
1165 | e.type := PARS.program.stTypes.tREAL |
||
1166 | |||
1167 | |PROG.sysSIZE: |
||
1168 | parser.expression(parser, e); |
||
1169 | PARS.check(e.obj = eTYPE, parser, pos, 68); |
||
1170 | ASSERT(ARITH.setInt(e.value, e.type.size)); |
||
1171 | e.obj := eCONST; |
||
1172 | e.type := PARS.program.stTypes.tINTEGER |
||
1173 | |||
1174 | END |
||
1175 | |||
1176 | END; |
||
1177 | |||
1178 | PARS.checklex(parser, SCAN.lxRROUND); |
||
1179 | PARS.Next(parser); |
||
1180 | |||
1181 | IF e.obj # eCONST THEN |
||
1182 | e.obj := eEXPR |
||
1183 | END |
||
1184 | |||
1185 | END stProc; |
||
1186 | |||
1187 | |||
1188 | PROCEDURE ActualParameters (parser: PARS.PARSER; VAR e: PARS.EXPR); |
||
1189 | VAR |
||
1190 | proc: PROG.TYPE_; |
||
1191 | param: LISTS.ITEM; |
||
1192 | e1: PARS.EXPR; |
||
1193 | pos: SCAN.POSITION; |
||
1194 | |||
1195 | BEGIN |
||
1196 | ASSERT(parser.sym = SCAN.lxLROUND); |
||
1197 | |||
1198 | IF (e.obj IN {ePROC, eIMP}) OR isExpr(e) THEN |
||
1199 | proc := e.type; |
||
1200 | PARS.check1(proc.typ = PROG.tPROCEDURE, parser, 86); |
||
1201 | PARS.Next(parser); |
||
1202 | |||
1203 | param := proc.params.first; |
||
1204 | WHILE param # NIL DO |
||
1205 | getpos(parser, pos); |
||
1206 | |||
1207 | CODE.setlast(begcall); |
||
1208 | |||
1209 | IF param(PROG.PARAM).vPar THEN |
||
1210 | parser.designator(parser, e1) |
||
1211 | ELSE |
||
1212 | parser.expression(parser, e1) |
||
1213 | END; |
||
1214 | paramcomp(parser, pos, e1, param(PROG.PARAM)); |
||
1215 | param := param.next; |
||
1216 | IF param # NIL THEN |
||
1217 | PARS.checklex(parser, SCAN.lxCOMMA); |
||
1218 | PARS.Next(parser) |
||
1219 | END |
||
1220 | END; |
||
1221 | |||
1222 | PARS.checklex(parser, SCAN.lxRROUND); |
||
1223 | PARS.Next(parser); |
||
1224 | |||
1225 | e.obj := eEXPR; |
||
1226 | e.type := proc.base |
||
1227 | |||
1228 | ELSIF e.obj IN {eSTPROC, eSTFUNC, eSYSPROC, eSYSFUNC} THEN |
||
1229 | PARS.Next(parser); |
||
1230 | stProc(parser, e) |
||
1231 | ELSE |
||
1232 | PARS.check1(FALSE, parser, 86) |
||
1233 | END |
||
1234 | |||
1235 | END ActualParameters; |
||
1236 | |||
1237 | |||
1238 | PROCEDURE qualident (parser: PARS.PARSER; VAR e: PARS.EXPR); |
||
1239 | VAR |
||
1240 | ident: PROG.IDENT; |
||
1241 | import: BOOLEAN; |
||
1242 | pos: SCAN.POSITION; |
||
1243 | |||
1244 | BEGIN |
||
1245 | PARS.checklex(parser, SCAN.lxIDENT); |
||
1246 | getpos(parser, pos); |
||
1247 | import := FALSE; |
||
1248 | ident := parser.unit.idents.get(parser.unit, parser.lex.ident, FALSE); |
||
1249 | PARS.check1(ident # NIL, parser, 48); |
||
1250 | IF ident.typ = PROG.idMODULE THEN |
||
1251 | PARS.ExpectSym(parser, SCAN.lxPOINT); |
||
1252 | PARS.ExpectSym(parser, SCAN.lxIDENT); |
||
1253 | ident := ident.unit.idents.get(ident.unit, parser.lex.ident, FALSE); |
||
1254 | PARS.check1((ident # NIL) & ident.export, parser, 48); |
||
1255 | import := TRUE |
||
1256 | END; |
||
1257 | PARS.Next(parser); |
||
1258 | |||
1259 | e.readOnly := FALSE; |
||
1260 | e.ident := ident; |
||
1261 | |||
1262 | CASE ident.typ OF |
||
1263 | |PROG.idCONST: |
||
1264 | e.obj := eCONST; |
||
1265 | e.type := ident.type; |
||
1266 | e.value := ident.value |
||
1267 | |PROG.idTYPE: |
||
1268 | e.obj := eTYPE; |
||
1269 | e.type := ident.type |
||
1270 | |PROG.idVAR: |
||
1271 | e.obj := eVAR; |
||
1272 | e.type := ident.type; |
||
1273 | e.readOnly := import |
||
1274 | |PROG.idPROC: |
||
1275 | e.obj := ePROC; |
||
1276 | e.type := ident.type |
||
1277 | |PROG.idIMP: |
||
1278 | e.obj := eIMP; |
||
1279 | e.type := ident.type |
||
1280 | |PROG.idVPAR: |
||
1281 | e.type := ident.type; |
||
1282 | IF e.type.typ = PROG.tRECORD THEN |
||
1283 | e.obj := eVREC |
||
1284 | ELSE |
||
1285 | e.obj := eVPAR |
||
1286 | END |
||
1287 | |PROG.idPARAM: |
||
1288 | e.obj := ePARAM; |
||
1289 | e.type := ident.type; |
||
1290 | e.readOnly := (e.type.typ IN {PROG.tRECORD, PROG.tARRAY}) |
||
1291 | |PROG.idSTPROC: |
||
1292 | e.obj := eSTPROC; |
||
1293 | e.stproc := ident.stproc |
||
1294 | |PROG.idSTFUNC: |
||
1295 | e.obj := eSTFUNC; |
||
1296 | e.stproc := ident.stproc |
||
1297 | |PROG.idSYSPROC: |
||
1298 | e.obj := eSYSPROC; |
||
1299 | e.stproc := ident.stproc |
||
1300 | |PROG.idSYSFUNC: |
||
1301 | PARS.check(~parser.constexp, parser, pos, 109); |
||
1302 | e.obj := eSYSFUNC; |
||
1303 | e.stproc := ident.stproc |
||
1304 | |PROG.idNONE: |
||
1305 | PARS.check(FALSE, parser, pos, 115) |
||
1306 | END; |
||
1307 | |||
1308 | IF isVar(e) THEN |
||
1309 | PARS.check(e.ident.global OR (e.ident.scopeLvl = parser.unit.scopeLvl), parser, pos, 105) |
||
1310 | END |
||
1311 | |||
1312 | END qualident; |
||
1313 | |||
1314 | |||
1315 | PROCEDURE deref (pos: SCAN.POSITION; e: PARS.EXPR; load: BOOLEAN; error: INTEGER); |
||
1316 | VAR |
||
1317 | label: INTEGER; |
||
1318 | |||
1319 | BEGIN |
||
1320 | IF load THEN |
||
1321 | CODE.load(e.type.size) |
||
1322 | END; |
||
1323 | |||
1324 | IF chkPTR IN checking THEN |
||
1325 | label := CODE.NewLabel(); |
||
1326 | CODE.AddJmpCmd(CODE.opJNZ, label); |
||
1327 | CODE.OnError(pos.line, error); |
||
1328 | CODE.SetLabel(label) |
||
1329 | END |
||
1330 | END deref; |
||
1331 | |||
1332 | |||
1333 | PROCEDURE designator (parser: PARS.PARSER; VAR e: PARS.EXPR); |
||
1334 | VAR |
||
1335 | field: PROG.FIELD; |
||
1336 | pos: SCAN.POSITION; |
||
1337 | t, idx: PARS.EXPR; |
||
1338 | |||
1339 | |||
1340 | PROCEDURE LoadAdr (e: PARS.EXPR); |
||
1341 | VAR |
||
1342 | offset: INTEGER; |
||
1343 | |||
1344 | PROCEDURE OpenArray (e: PARS.EXPR); |
||
1345 | VAR |
||
1346 | offset, n: INTEGER; |
||
1347 | BEGIN |
||
1348 | offset := e.ident.offset; |
||
1349 | n := PROG.Dim(e.type); |
||
1350 | WHILE n >= 0 DO |
||
1351 | CODE.AddCmd(CODE.opVADR, offset); |
||
1352 | DEC(offset); |
||
1353 | DEC(n) |
||
1354 | END |
||
1355 | END OpenArray; |
||
1356 | |||
1357 | |||
1358 | BEGIN |
||
1359 | IF e.obj = eVAR THEN |
||
1360 | offset := PROG.getOffset(PARS.program, e.ident); |
||
1361 | IF e.ident.global THEN |
||
1362 | CODE.AddCmd(CODE.opGADR, offset) |
||
1363 | ELSE |
||
1364 | CODE.AddCmd(CODE.opLADR, -offset) |
||
1365 | END |
||
1366 | ELSIF e.obj = ePARAM THEN |
||
1367 | IF (e.type.typ = PROG.tRECORD) OR ((e.type.typ = PROG.tARRAY) & (e.type.length > 0)) THEN |
||
1368 | CODE.AddCmd(CODE.opVADR, e.ident.offset) |
||
1369 | ELSIF PROG.isOpenArray(e.type) THEN |
||
1370 | OpenArray(e) |
||
1371 | ELSE |
||
1372 | CODE.AddCmd(CODE.opLADR, e.ident.offset) |
||
1373 | END |
||
1374 | ELSIF e.obj IN {eVPAR, eVREC} THEN |
||
1375 | IF PROG.isOpenArray(e.type) THEN |
||
1376 | OpenArray(e) |
||
1377 | ELSE |
||
1378 | CODE.AddCmd(CODE.opVADR, e.ident.offset) |
||
1379 | END |
||
1380 | END |
||
1381 | END LoadAdr; |
||
1382 | |||
1383 | |||
1384 | PROCEDURE OpenIdx (parser: PARS.PARSER; pos: SCAN.POSITION; e: PARS.EXPR); |
||
1385 | VAR |
||
1386 | label: INTEGER; |
||
1387 | type: PROG.TYPE_; |
||
1388 | n, offset, k: INTEGER; |
||
1389 | |||
1390 | BEGIN |
||
1391 | |||
1392 | IF chkIDX IN checking THEN |
||
1393 | label := CODE.NewLabel(); |
||
1394 | CODE.AddCmd2(CODE.opCHKIDX2, label, 0); |
||
1395 | CODE.OnError(pos.line, errIDX); |
||
1396 | CODE.SetLabel(label) |
||
1397 | ELSE |
||
1398 | CODE.AddCmd(CODE.opCHKIDX2, -1) |
||
1399 | END; |
||
1400 | |||
1401 | type := PROG.OpenBase(e.type); |
||
1402 | IF type.size # 1 THEN |
||
1403 | CODE.AddCmd(CODE.opMULC, type.size) |
||
1404 | END; |
||
1405 | n := PROG.Dim(e.type) - 1; |
||
1406 | k := n; |
||
1407 | WHILE n > 0 DO |
||
1408 | CODE.AddCmd0(CODE.opMUL); |
||
1409 | DEC(n) |
||
1410 | END; |
||
1411 | CODE.AddCmd0(CODE.opADD); |
||
1412 | offset := e.ident.offset - 1; |
||
1413 | n := k; |
||
1414 | WHILE n > 0 DO |
||
1415 | CODE.AddCmd(CODE.opVADR, offset); |
||
1416 | DEC(offset); |
||
1417 | DEC(n) |
||
1418 | END |
||
1419 | END OpenIdx; |
||
1420 | |||
1421 | |||
1422 | BEGIN |
||
1423 | qualident(parser, e); |
||
1424 | |||
1425 | IF e.obj IN {ePROC, eIMP} THEN |
||
1426 | PROG.UseProc(parser.unit, e.ident.proc) |
||
1427 | END; |
||
1428 | |||
1429 | IF isVar(e) THEN |
||
1430 | LoadAdr(e) |
||
1431 | END; |
||
1432 | |||
1433 | WHILE parser.sym = SCAN.lxPOINT DO |
||
1434 | getpos(parser, pos); |
||
1435 | PARS.check1(isExpr(e) & (e.type.typ IN {PROG.tRECORD, PROG.tPOINTER}), parser, 73); |
||
1436 | IF e.type.typ = PROG.tPOINTER THEN |
||
1437 | deref(pos, e, TRUE, errPTR) |
||
1438 | END; |
||
1439 | PARS.ExpectSym(parser, SCAN.lxIDENT); |
||
1440 | IF e.type.typ = PROG.tPOINTER THEN |
||
1441 | e.type := e.type.base; |
||
1442 | e.readOnly := FALSE |
||
1443 | END; |
||
1444 | field := e.type.fields.get(e.type, parser.lex.ident, parser.unit); |
||
1445 | PARS.check1(field # NIL, parser, 74); |
||
1446 | e.type := field.type; |
||
1447 | IF e.obj = eVREC THEN |
||
1448 | e.obj := eVPAR |
||
1449 | END; |
||
1450 | IF field.offset # 0 THEN |
||
1451 | CODE.AddCmd(CODE.opADDR, field.offset) |
||
1452 | END; |
||
1453 | PARS.Next(parser); |
||
1454 | e.ident := NIL |
||
1455 | |||
1456 | ELSIF parser.sym = SCAN.lxLSQUARE DO |
||
1457 | |||
1458 | REPEAT |
||
1459 | |||
1460 | PARS.check1(isArr(e), parser, 75); |
||
1461 | NextPos(parser, pos); |
||
1462 | parser.expression(parser, idx); |
||
1463 | PARS.check(isInt(idx), parser, pos, 76); |
||
1464 | |||
1465 | IF idx.obj = eCONST THEN |
||
1466 | IF e.type.length > 0 THEN |
||
1467 | PARS.check(ARITH.range(idx.value, 0, e.type.length - 1), parser, pos, 83); |
||
1468 | IF ARITH.Int(idx.value) > 0 THEN |
||
1469 | CODE.AddCmd(CODE.opADDR, ARITH.Int(idx.value) * e.type.base.size) |
||
1470 | END |
||
1471 | ELSE |
||
1472 | PARS.check(ARITH.range(idx.value, 0, MACHINE.target.maxInt), parser, pos, 83); |
||
1473 | LoadConst(idx); |
||
1474 | OpenIdx(parser, pos, e) |
||
1475 | END |
||
1476 | ELSE |
||
1477 | IF e.type.length > 0 THEN |
||
1478 | IF chkIDX IN checking THEN |
||
1479 | CheckRange(e.type.length, pos.line, errIDX) |
||
1480 | END; |
||
1481 | IF e.type.base.size # 1 THEN |
||
1482 | CODE.AddCmd(CODE.opMULC, e.type.base.size) |
||
1483 | END; |
||
1484 | CODE.AddCmd0(CODE.opADD) |
||
1485 | ELSE |
||
1486 | OpenIdx(parser, pos, e) |
||
1487 | END |
||
1488 | END; |
||
1489 | |||
1490 | e.type := e.type.base |
||
1491 | |||
1492 | UNTIL parser.sym # SCAN.lxCOMMA; |
||
1493 | |||
1494 | PARS.checklex(parser, SCAN.lxRSQUARE); |
||
1495 | PARS.Next(parser); |
||
1496 | e.ident := NIL |
||
1497 | |||
1498 | ELSIF parser.sym = SCAN.lxCARET DO |
||
1499 | getpos(parser, pos); |
||
1500 | PARS.check1(isPtr(e), parser, 77); |
||
1501 | deref(pos, e, TRUE, errPTR); |
||
1502 | e.type := e.type.base; |
||
1503 | e.readOnly := FALSE; |
||
1504 | PARS.Next(parser); |
||
1505 | e.ident := NIL; |
||
1506 | e.obj := eVREC |
||
1507 | |||
1508 | ELSIF (parser.sym = SCAN.lxLROUND) & isExpr(e) & (e.type.typ IN {PROG.tRECORD, PROG.tPOINTER}) DO |
||
1509 | |||
1510 | IF e.type.typ = PROG.tRECORD THEN |
||
1511 | PARS.check1(e.obj = eVREC, parser, 78) |
||
1512 | END; |
||
1513 | NextPos(parser, pos); |
||
1514 | qualident(parser, t); |
||
1515 | PARS.check(t.obj = eTYPE, parser, pos, 79); |
||
1516 | |||
1517 | IF e.type.typ = PROG.tRECORD THEN |
||
1518 | PARS.check(t.type.typ = PROG.tRECORD, parser, pos, 80); |
||
1519 | IF chkGUARD IN checking THEN |
||
1520 | IF e.ident = NIL THEN |
||
1521 | CODE.TypeGuard(CODE.opTYPEGD, t.type.num, pos.line, errGUARD) |
||
1522 | ELSE |
||
1523 | CODE.AddCmd(CODE.opVADR, e.ident.offset - 1); |
||
1524 | CODE.TypeGuard(CODE.opTYPEGR, t.type.num, pos.line, errGUARD) |
||
1525 | END |
||
1526 | END; |
||
1527 | ELSE |
||
1528 | PARS.check(t.type.typ = PROG.tPOINTER, parser, pos, 81); |
||
1529 | IF chkGUARD IN checking THEN |
||
1530 | CODE.TypeGuard(CODE.opTYPEGP, t.type.base.num, pos.line, errGUARD) |
||
1531 | END |
||
1532 | END; |
||
1533 | |||
1534 | PARS.check(PROG.isBaseOf(e.type, t.type), parser, pos, 82); |
||
1535 | |||
1536 | e.type := t.type; |
||
1537 | |||
1538 | PARS.checklex(parser, SCAN.lxRROUND); |
||
1539 | PARS.Next(parser) |
||
1540 | |||
1541 | END |
||
1542 | |||
1543 | END designator; |
||
1544 | |||
1545 | |||
1546 | PROCEDURE ProcCall (e: PARS.EXPR; procType: PROG.TYPE_; isfloat: BOOLEAN; VAR fregs: INTEGER; parser: PARS.PARSER; pos: SCAN.POSITION; CallStat: BOOLEAN); |
||
1547 | VAR |
||
1548 | cconv: INTEGER; |
||
1549 | params: INTEGER; |
||
1550 | callconv: INTEGER; |
||
1551 | fparams: INTEGER; |
||
1552 | int, flt: INTEGER; |
||
1553 | stk_par: INTEGER; |
||
1554 | |||
1555 | BEGIN |
||
1556 | cconv := procType.call; |
||
1557 | params := procType.params.size; |
||
1558 | |||
1559 | IF cconv IN {PROG._win64, PROG.win64} THEN |
||
1560 | callconv := CODE.call_win64; |
||
1561 | fparams := LSL(ORD(procType.params.getfparams(procType, 3, int, flt)), 5) + MIN(params, 4) |
||
1562 | ELSIF cconv IN {PROG._systemv, PROG.systemv} THEN |
||
1563 | callconv := CODE.call_sysv; |
||
1564 | fparams := LSL(ORD(procType.params.getfparams(procType, PROG.MAXSYSVPARAM - 1, int, flt)), 5) + params; |
||
1565 | stk_par := MAX(0, int - 6) + MAX(0, flt - 8) |
||
1566 | ELSE |
||
1567 | callconv := CODE.call_stack; |
||
1568 | fparams := 0 |
||
1569 | END; |
||
1570 | CODE.setlast(begcall); |
||
1571 | fregs := CODE.precall(isfloat); |
||
1572 | |||
1573 | IF cconv IN {PROG._ccall16, PROG.ccall16} THEN |
||
1574 | CODE.AddCmd(CODE.opALIGN16, params) |
||
1575 | ELSIF cconv IN {PROG._win64, PROG.win64} THEN |
||
1576 | CODE.AddCmd(CODE.opWIN64ALIGN16, params) |
||
1577 | ELSIF cconv IN {PROG._systemv, PROG.systemv} THEN |
||
1578 | CODE.AddCmd(CODE.opSYSVALIGN16, params + stk_par) |
||
1579 | END; |
||
1580 | CODE.setlast(endcall.prev(CODE.COMMAND)); |
||
1581 | |||
1582 | IF e.obj = eIMP THEN |
||
1583 | CODE.CallImp(e.ident.import, callconv, fparams) |
||
1584 | ELSIF e.obj = ePROC THEN |
||
1585 | CODE.Call(e.ident.proc.label, callconv, fparams) |
||
1586 | ELSIF isExpr(e) THEN |
||
1587 | deref(pos, e, CallStat, errPROC); |
||
1588 | CODE.CallP(callconv, fparams) |
||
1589 | END; |
||
1590 | |||
1591 | IF cconv IN {PROG._ccall16, PROG.ccall16} THEN |
||
1592 | CODE.AddCmd(CODE.opCLEANUP, params); |
||
1593 | CODE.AddCmd0(CODE.opPOPSP) |
||
1594 | ELSIF cconv IN {PROG._win64, PROG.win64} THEN |
||
1595 | CODE.AddCmd(CODE.opCLEANUP, MAX(params + params MOD 2, 4) + 1); |
||
1596 | CODE.AddCmd0(CODE.opPOPSP) |
||
1597 | ELSIF cconv IN {PROG._systemv, PROG.systemv} THEN |
||
1598 | CODE.AddCmd(CODE.opCLEANUP, params + stk_par); |
||
1599 | CODE.AddCmd0(CODE.opPOPSP) |
||
1600 | ELSIF cconv IN {PROG._ccall, PROG.ccall} THEN |
||
1601 | CODE.AddCmd(CODE.opCLEANUP, params) |
||
1602 | END; |
||
1603 | |||
1604 | IF ~CallStat THEN |
||
1605 | IF isfloat THEN |
||
1606 | PARS.check(CODE.resf(fregs), parser, pos, 41) |
||
1607 | ELSE |
||
1608 | CODE.res(fregs) |
||
1609 | END |
||
1610 | END |
||
1611 | END ProcCall; |
||
1612 | |||
1613 | |||
1614 | PROCEDURE expression (parser: PARS.PARSER; VAR e: PARS.EXPR); |
||
1615 | VAR |
||
1616 | pos, pos0, pos1: SCAN.POSITION; |
||
1617 | |||
1618 | op: INTEGER; |
||
1619 | e1: PARS.EXPR; |
||
1620 | constant: BOOLEAN; |
||
1621 | operator: ARITH.RELATION; |
||
1622 | error: INTEGER; |
||
1623 | |||
1624 | |||
1625 | PROCEDURE relation (sym: INTEGER): BOOLEAN; |
||
1626 | RETURN (sym = SCAN.lxEQ) OR (sym = SCAN.lxNE) OR |
||
1627 | (sym = SCAN.lxLT) OR (sym = SCAN.lxLE) OR |
||
1628 | (sym = SCAN.lxGT) OR (sym = SCAN.lxGE) OR |
||
1629 | (sym = SCAN.lxIN) OR (sym = SCAN.lxIS) |
||
1630 | END relation; |
||
1631 | |||
1632 | |||
1633 | PROCEDURE AddOperator (sym: INTEGER): BOOLEAN; |
||
1634 | RETURN (sym = SCAN.lxPLUS) OR (sym = SCAN.lxMINUS) OR |
||
1635 | (sym = SCAN.lxOR) |
||
1636 | END AddOperator; |
||
1637 | |||
1638 | |||
1639 | PROCEDURE MulOperator (sym: INTEGER): BOOLEAN; |
||
1640 | RETURN (sym = SCAN.lxMUL) OR (sym = SCAN.lxSLASH) OR |
||
1641 | (sym = SCAN.lxDIV) OR (sym = SCAN.lxMOD) OR |
||
1642 | (sym = SCAN.lxAND) |
||
1643 | END MulOperator; |
||
1644 | |||
1645 | |||
1646 | PROCEDURE element (parser: PARS.PARSER; VAR e: PARS.EXPR); |
||
1647 | VAR |
||
1648 | e1, e2: PARS.EXPR; |
||
1649 | pos: SCAN.POSITION; |
||
1650 | range: BOOLEAN; |
||
1651 | |||
1652 | BEGIN |
||
1653 | range := FALSE; |
||
1654 | getpos(parser, pos); |
||
1655 | expression(parser, e1); |
||
1656 | PARS.check(isInt(e1), parser, pos, 76); |
||
1657 | |||
1658 | IF e1.obj = eCONST THEN |
||
1659 | PARS.check(ARITH.range(e1.value, 0, MACHINE.target.maxSet), parser, pos, 44) |
||
1660 | END; |
||
1661 | |||
1662 | range := parser.sym = SCAN.lxRANGE; |
||
1663 | |||
1664 | IF range THEN |
||
1665 | NextPos(parser, pos); |
||
1666 | expression(parser, e2); |
||
1667 | PARS.check(isInt(e2), parser, pos, 76); |
||
1668 | |||
1669 | IF e2.obj = eCONST THEN |
||
1670 | PARS.check(ARITH.range(e2.value, 0, MACHINE.target.maxSet), parser, pos, 44) |
||
1671 | END |
||
1672 | ELSE |
||
1673 | IF e1.obj = eCONST THEN |
||
1674 | e2 := e1 |
||
1675 | END |
||
1676 | END; |
||
1677 | |||
1678 | e.type := PARS.program.stTypes.tSET; |
||
1679 | |||
1680 | IF (e1.obj = eCONST) & (e2.obj = eCONST) THEN |
||
1681 | ARITH.constrSet(e.value, e1.value, e2.value); |
||
1682 | e.obj := eCONST |
||
1683 | ELSE |
||
1684 | IF range THEN |
||
1685 | IF e1.obj = eCONST THEN |
||
1686 | CODE.AddCmd(CODE.opRSETL, ARITH.Int(e1.value)) |
||
1687 | ELSIF e2.obj = eCONST THEN |
||
1688 | CODE.AddCmd(CODE.opRSETR, ARITH.Int(e2.value)) |
||
1689 | ELSE |
||
1690 | CODE.AddCmd0(CODE.opRSET) |
||
1691 | END |
||
1692 | ELSE |
||
1693 | CODE.AddCmd0(CODE.opRSET1) |
||
1694 | END; |
||
1695 | e.obj := eEXPR |
||
1696 | END |
||
1697 | |||
1698 | END element; |
||
1699 | |||
1700 | |||
1701 | PROCEDURE set (parser: PARS.PARSER; VAR e: PARS.EXPR); |
||
1702 | VAR |
||
1703 | e1: PARS.EXPR; |
||
1704 | |||
1705 | BEGIN |
||
1706 | ASSERT(parser.sym = SCAN.lxLCURLY); |
||
1707 | |||
1708 | e.obj := eCONST; |
||
1709 | e.type := PARS.program.stTypes.tSET; |
||
1710 | ARITH.emptySet(e.value); |
||
1711 | |||
1712 | PARS.Next(parser); |
||
1713 | IF parser.sym # SCAN.lxRCURLY THEN |
||
1714 | element(parser, e1); |
||
1715 | |||
1716 | IF e1.obj = eCONST THEN |
||
1717 | ARITH.opSet(e.value, e1.value, "+") |
||
1718 | ELSE |
||
1719 | e.obj := eEXPR |
||
1720 | END; |
||
1721 | |||
1722 | WHILE parser.sym = SCAN.lxCOMMA DO |
||
1723 | PARS.Next(parser); |
||
1724 | element(parser, e1); |
||
1725 | IF (e.obj = eCONST) & (e1.obj = eCONST) THEN |
||
1726 | ARITH.opSet(e.value, e1.value, "+") |
||
1727 | ELSE |
||
1728 | IF e.obj = eCONST THEN |
||
1729 | CODE.AddCmd(CODE.opADDSL, ARITH.Int(e.value)) |
||
1730 | ELSIF e1.obj = eCONST THEN |
||
1731 | CODE.AddCmd(CODE.opADDSR, ARITH.Int(e1.value)) |
||
1732 | ELSE |
||
1733 | CODE.AddCmd0(CODE.opADDS) |
||
1734 | END; |
||
1735 | e.obj := eEXPR |
||
1736 | END |
||
1737 | END; |
||
1738 | PARS.checklex(parser, SCAN.lxRCURLY) |
||
1739 | END; |
||
1740 | PARS.Next(parser); |
||
1741 | END set; |
||
1742 | |||
1743 | |||
1744 | PROCEDURE factor (parser: PARS.PARSER; VAR e: PARS.EXPR); |
||
1745 | VAR |
||
1746 | sym: INTEGER; |
||
1747 | pos: SCAN.POSITION; |
||
1748 | e1: PARS.EXPR; |
||
1749 | isfloat: BOOLEAN; |
||
1750 | fregs: INTEGER; |
||
1751 | |||
1752 | |||
1753 | PROCEDURE LoadVar (e: PARS.EXPR; parser: PARS.PARSER; pos: SCAN.POSITION); |
||
1754 | BEGIN |
||
1755 | IF ~(e.type.typ IN {PROG.tRECORD, PROG.tARRAY}) THEN |
||
1756 | IF e.type.typ = PROG.tREAL THEN |
||
1757 | PARS.check(CODE.loadf(), parser, pos, 41) |
||
1758 | ELSE |
||
1759 | CODE.load(e.type.size) |
||
1760 | END |
||
1761 | END |
||
1762 | END LoadVar; |
||
1763 | |||
1764 | |||
1765 | BEGIN |
||
1766 | sym := parser.sym; |
||
1767 | |||
1768 | IF (sym = SCAN.lxINTEGER) OR (sym = SCAN.lxHEX) OR (sym = SCAN.lxFLOAT) OR (sym = SCAN.lxCHAR) OR (sym = SCAN.lxSTRING) THEN |
||
1769 | e.obj := eCONST; |
||
1770 | e.value := parser.lex.value; |
||
1771 | e.type := PARS.program.getType(PARS.program, e.value.typ); |
||
1772 | PARS.Next(parser) |
||
1773 | |||
1774 | ELSIF sym = SCAN.lxNIL THEN |
||
1775 | e.obj := eCONST; |
||
1776 | e.type := PARS.program.stTypes.tNIL; |
||
1777 | PARS.Next(parser) |
||
1778 | |||
1779 | ELSIF (sym = SCAN.lxTRUE) OR (sym = SCAN.lxFALSE) THEN |
||
1780 | e.obj := eCONST; |
||
1781 | ARITH.setbool(e.value, sym = SCAN.lxTRUE); |
||
1782 | e.type := PARS.program.stTypes.tBOOLEAN; |
||
1783 | PARS.Next(parser) |
||
1784 | |||
1785 | ELSIF sym = SCAN.lxLCURLY THEN |
||
1786 | set(parser, e) |
||
1787 | |||
1788 | ELSIF sym = SCAN.lxIDENT THEN |
||
1789 | getpos(parser, pos); |
||
1790 | |||
1791 | CODE.pushBegEnd(begcall, endcall); |
||
1792 | |||
1793 | designator(parser, e); |
||
1794 | IF isVar(e) THEN |
||
1795 | LoadVar(e, parser, pos) |
||
1796 | END; |
||
1797 | IF parser.sym = SCAN.lxLROUND THEN |
||
1798 | e1 := e; |
||
1799 | ActualParameters(parser, e); |
||
1800 | PARS.check(e.type # NIL, parser, pos, 59); |
||
1801 | isfloat := e.type.typ = PROG.tREAL; |
||
1802 | IF e1.obj IN {ePROC, eIMP} THEN |
||
1803 | ProcCall(e1, e1.ident.type, isfloat, fregs, parser, pos, FALSE) |
||
1804 | ELSIF isExpr(e1) THEN |
||
1805 | ProcCall(e1, e1.type, isfloat, fregs, parser, pos, FALSE) |
||
1806 | END |
||
1807 | END; |
||
1808 | CODE.popBegEnd(begcall, endcall) |
||
1809 | |||
1810 | ELSIF sym = SCAN.lxLROUND THEN |
||
1811 | PARS.Next(parser); |
||
1812 | expression(parser, e); |
||
1813 | PARS.checklex(parser, SCAN.lxRROUND); |
||
1814 | PARS.Next(parser); |
||
1815 | IF isExpr(e) & (e.obj # eCONST) THEN |
||
1816 | e.obj := eEXPR |
||
1817 | END |
||
1818 | |||
1819 | ELSIF sym = SCAN.lxNOT THEN |
||
1820 | NextPos(parser, pos); |
||
1821 | factor(parser, e); |
||
1822 | PARS.check(isBoolean(e), parser, pos, 72); |
||
1823 | IF e.obj # eCONST THEN |
||
1824 | CODE.not; |
||
1825 | e.obj := eEXPR |
||
1826 | ELSE |
||
1827 | ASSERT(ARITH.neg(e.value)) |
||
1828 | END |
||
1829 | |||
1830 | ELSE |
||
1831 | PARS.check1(FALSE, parser, 34) |
||
1832 | END |
||
1833 | END factor; |
||
1834 | |||
1835 | |||
1836 | PROCEDURE term (parser: PARS.PARSER; VAR e: PARS.EXPR); |
||
1837 | VAR |
||
1838 | pos: SCAN.POSITION; |
||
1839 | op: INTEGER; |
||
1840 | e1: PARS.EXPR; |
||
1841 | |||
1842 | label: INTEGER; |
||
1843 | label1: INTEGER; |
||
1844 | |||
1845 | BEGIN |
||
1846 | factor(parser, e); |
||
1847 | label := -1; |
||
1848 | |||
1849 | WHILE MulOperator(parser.sym) DO |
||
1850 | op := parser.sym; |
||
1851 | getpos(parser, pos); |
||
1852 | PARS.Next(parser); |
||
1853 | |||
1854 | IF op = SCAN.lxAND THEN |
||
1855 | IF ~parser.constexp THEN |
||
1856 | |||
1857 | IF label = -1 THEN |
||
1858 | label := CODE.NewLabel() |
||
1859 | END; |
||
1860 | |||
1861 | IF e.obj = eCONST THEN |
||
1862 | CODE.AddCmd(CODE.opCONST, ORD(ARITH.getBool(e.value))) |
||
1863 | END; |
||
1864 | CODE.AddJmpCmd(CODE.opJZ, label); |
||
1865 | CODE.drop |
||
1866 | END |
||
1867 | END; |
||
1868 | |||
1869 | factor(parser, e1); |
||
1870 | |||
1871 | CASE op OF |
||
1872 | |SCAN.lxMUL: |
||
1873 | PARS.check(isInt(e) & isInt(e1) OR isReal(e) & isReal(e1) OR isSet(e) & isSet(e1), parser, pos, 37); |
||
1874 | IF (e.obj = eCONST) & (e1.obj = eCONST) THEN |
||
1875 | |||
1876 | CASE e.value.typ OF |
||
1877 | |ARITH.tINTEGER: PARS.check(ARITH.opInt(e.value, e1.value, "*"), parser, pos, 39) |
||
1878 | |ARITH.tREAL: PARS.check(ARITH.opFloat(e.value, e1.value, "*"), parser, pos, 40) |
||
1879 | |ARITH.tSET: ARITH.opSet(e.value, e1.value, "*") |
||
1880 | END |
||
1881 | |||
1882 | ELSE |
||
1883 | IF isInt(e) THEN |
||
1884 | IF e.obj = eCONST THEN |
||
1885 | CODE.AddCmd(CODE.opMULC, ARITH.Int(e.value)) |
||
1886 | ELSIF e1.obj = eCONST THEN |
||
1887 | CODE.AddCmd(CODE.opMULC, ARITH.Int(e1.value)) |
||
1888 | ELSE |
||
1889 | CODE.AddCmd0(CODE.opMUL) |
||
1890 | END |
||
1891 | ELSIF isReal(e) THEN |
||
1892 | IF e.obj = eCONST THEN |
||
1893 | CODE.Float(ARITH.Float(e.value)) |
||
1894 | ELSIF e1.obj = eCONST THEN |
||
1895 | CODE.Float(ARITH.Float(e1.value)) |
||
1896 | END; |
||
1897 | CODE.fbinop(CODE.opMULF) |
||
1898 | ELSIF isSet(e) THEN |
||
1899 | IF e.obj = eCONST THEN |
||
1900 | CODE.AddCmd(CODE.opMULSC, ARITH.Int(e.value)) |
||
1901 | ELSIF e1.obj = eCONST THEN |
||
1902 | CODE.AddCmd(CODE.opMULSC, ARITH.Int(e1.value)) |
||
1903 | ELSE |
||
1904 | CODE.AddCmd0(CODE.opMULS) |
||
1905 | END |
||
1906 | END; |
||
1907 | e.obj := eEXPR |
||
1908 | END |
||
1909 | |||
1910 | |SCAN.lxSLASH: |
||
1911 | PARS.check(isReal(e) & isReal(e1) OR isSet(e) & isSet(e1), parser, pos, 37); |
||
1912 | IF (e1.obj = eCONST) & isReal(e1) THEN |
||
1913 | PARS.check(~ARITH.isZero(e1.value), parser, pos, 45) |
||
1914 | END; |
||
1915 | IF (e.obj = eCONST) & (e1.obj = eCONST) THEN |
||
1916 | |||
1917 | CASE e.value.typ OF |
||
1918 | |ARITH.tREAL: PARS.check(ARITH.opFloat(e.value, e1.value, "/"), parser, pos, 40) |
||
1919 | |ARITH.tSET: ARITH.opSet(e.value, e1.value, "/") |
||
1920 | END |
||
1921 | |||
1922 | ELSE |
||
1923 | IF isReal(e) THEN |
||
1924 | IF e.obj = eCONST THEN |
||
1925 | CODE.Float(ARITH.Float(e.value)); |
||
1926 | CODE.fbinop(CODE.opDIVFI) |
||
1927 | ELSIF e1.obj = eCONST THEN |
||
1928 | CODE.Float(ARITH.Float(e1.value)); |
||
1929 | CODE.fbinop(CODE.opDIVF) |
||
1930 | ELSE |
||
1931 | CODE.fbinop(CODE.opDIVF) |
||
1932 | END |
||
1933 | ELSIF isSet(e) THEN |
||
1934 | IF e.obj = eCONST THEN |
||
1935 | CODE.AddCmd(CODE.opDIVSC, ARITH.Int(e.value)) |
||
1936 | ELSIF e1.obj = eCONST THEN |
||
1937 | CODE.AddCmd(CODE.opDIVSC, ARITH.Int(e1.value)) |
||
1938 | ELSE |
||
1939 | CODE.AddCmd0(CODE.opDIVS) |
||
1940 | END |
||
1941 | END; |
||
1942 | e.obj := eEXPR |
||
1943 | END |
||
1944 | |||
1945 | |SCAN.lxDIV, SCAN.lxMOD: |
||
1946 | PARS.check(isInt(e) & isInt(e1), parser, pos, 37); |
||
1947 | IF e1.obj = eCONST THEN |
||
1948 | PARS.check(~ARITH.isZero(e1.value), parser, pos, 46) |
||
1949 | END; |
||
1950 | IF (e.obj = eCONST) & (e1.obj = eCONST) THEN |
||
1951 | |||
1952 | IF op = SCAN.lxDIV THEN |
||
1953 | PARS.check(ARITH.opInt(e.value, e1.value, "D"), parser, pos, 39) |
||
1954 | ELSE |
||
1955 | ASSERT(ARITH.opInt(e.value, e1.value, "M")) |
||
1956 | END |
||
1957 | |||
1958 | ELSE |
||
1959 | IF e1.obj # eCONST THEN |
||
1960 | label1 := CODE.NewLabel(); |
||
1961 | CODE.AddJmpCmd(CODE.opJNZ, label1) |
||
1962 | END; |
||
1963 | IF e.obj = eCONST THEN |
||
1964 | CODE.OnError(pos.line, errDIV); |
||
1965 | CODE.SetLabel(label1); |
||
1966 | CODE.AddCmd(CODE.opDIVL + ORD(op = SCAN.lxMOD), ARITH.Int(e.value)) |
||
1967 | ELSIF e1.obj = eCONST THEN |
||
1968 | CODE.AddCmd(CODE.opDIVR + ORD(op = SCAN.lxMOD), ARITH.Int(e1.value)) |
||
1969 | ELSE |
||
1970 | CODE.OnError(pos.line, errDIV); |
||
1971 | CODE.SetLabel(label1); |
||
1972 | CODE.AddCmd0(CODE.opDIV + ORD(op = SCAN.lxMOD)) |
||
1973 | END; |
||
1974 | e.obj := eEXPR |
||
1975 | END |
||
1976 | |||
1977 | |SCAN.lxAND: |
||
1978 | PARS.check(isBoolean(e) & isBoolean(e1), parser, pos, 37); |
||
1979 | |||
1980 | IF (e.obj = eCONST) & (e1.obj = eCONST) THEN |
||
1981 | ARITH.opBoolean(e.value, e1.value, "&") |
||
1982 | ELSE |
||
1983 | e.obj := eEXPR; |
||
1984 | IF e1.obj = eCONST THEN |
||
1985 | CODE.AddCmd(CODE.opCONST, ORD(ARITH.getBool(e1.value))) |
||
1986 | END |
||
1987 | END |
||
1988 | |||
1989 | END |
||
1990 | END; |
||
1991 | |||
1992 | IF label # -1 THEN |
||
1993 | CODE.SetLabel(label) |
||
1994 | END |
||
1995 | END term; |
||
1996 | |||
1997 | |||
1998 | PROCEDURE SimpleExpression (parser: PARS.PARSER; VAR e: PARS.EXPR); |
||
1999 | VAR |
||
2000 | pos: SCAN.POSITION; |
||
2001 | op: INTEGER; |
||
2002 | e1: PARS.EXPR; |
||
2003 | |||
2004 | plus, minus: BOOLEAN; |
||
2005 | |||
2006 | label: INTEGER; |
||
2007 | |||
2008 | BEGIN |
||
2009 | plus := parser.sym = SCAN.lxPLUS; |
||
2010 | minus := parser.sym = SCAN.lxMINUS; |
||
2011 | |||
2012 | IF plus OR minus THEN |
||
2013 | getpos(parser, pos); |
||
2014 | PARS.Next(parser) |
||
2015 | END; |
||
2016 | |||
2017 | term(parser, e); |
||
2018 | |||
2019 | IF plus OR minus THEN |
||
2020 | PARS.check(isInt(e) OR isReal(e) OR isSet(e), parser, pos, 36); |
||
2021 | |||
2022 | IF minus & (e.obj = eCONST) THEN |
||
2023 | PARS.check(ARITH.neg(e.value), parser, pos, 39) |
||
2024 | END; |
||
2025 | |||
2026 | IF e.obj # eCONST THEN |
||
2027 | IF minus THEN |
||
2028 | IF isInt(e) THEN |
||
2029 | CODE.AddCmd0(CODE.opUMINUS) |
||
2030 | ELSIF isReal(e) THEN |
||
2031 | CODE.AddCmd0(CODE.opUMINF) |
||
2032 | ELSIF isSet(e) THEN |
||
2033 | CODE.AddCmd0(CODE.opUMINS) |
||
2034 | END |
||
2035 | END; |
||
2036 | e.obj := eEXPR |
||
2037 | END |
||
2038 | END; |
||
2039 | |||
2040 | label := -1; |
||
2041 | |||
2042 | WHILE AddOperator(parser.sym) DO |
||
2043 | |||
2044 | op := parser.sym; |
||
2045 | getpos(parser, pos); |
||
2046 | PARS.Next(parser); |
||
2047 | |||
2048 | IF op = SCAN.lxOR THEN |
||
2049 | |||
2050 | IF ~parser.constexp THEN |
||
2051 | |||
2052 | IF label = -1 THEN |
||
2053 | label := CODE.NewLabel() |
||
2054 | END; |
||
2055 | |||
2056 | IF e.obj = eCONST THEN |
||
2057 | CODE.AddCmd(CODE.opCONST, ORD(ARITH.getBool(e.value))) |
||
2058 | END; |
||
2059 | CODE.AddJmpCmd(CODE.opJNZ, label); |
||
2060 | CODE.drop |
||
2061 | END |
||
2062 | |||
2063 | END; |
||
2064 | |||
2065 | term(parser, e1); |
||
2066 | |||
2067 | CASE op OF |
||
2068 | |SCAN.lxPLUS, SCAN.lxMINUS: |
||
2069 | |||
2070 | IF op = SCAN.lxPLUS THEN |
||
2071 | op := ORD("+") |
||
2072 | ELSE |
||
2073 | op := ORD("-") |
||
2074 | END; |
||
2075 | |||
2076 | PARS.check(isInt(e) & isInt(e1) OR isReal(e) & isReal(e1) OR isSet(e) & isSet(e1), parser, pos, 37); |
||
2077 | IF (e.obj = eCONST) & (e1.obj = eCONST) THEN |
||
2078 | |||
2079 | CASE e.value.typ OF |
||
2080 | |ARITH.tINTEGER: PARS.check(ARITH.opInt(e.value, e1.value, CHR(op)), parser, pos, 39) |
||
2081 | |ARITH.tREAL: PARS.check(ARITH.opFloat(e.value, e1.value, CHR(op)), parser, pos, 40) |
||
2082 | |ARITH.tSET: ARITH.opSet(e.value, e1.value, CHR(op)) |
||
2083 | END |
||
2084 | |||
2085 | ELSE |
||
2086 | IF isInt(e) THEN |
||
2087 | IF e.obj = eCONST THEN |
||
2088 | CODE.AddCmd(CODE.opADDL + ORD(op = ORD("-")), ARITH.Int(e.value)) |
||
2089 | ELSIF e1.obj = eCONST THEN |
||
2090 | CODE.AddCmd(CODE.opADDR + ORD(op = ORD("-")), ARITH.Int(e1.value)) |
||
2091 | ELSE |
||
2092 | CODE.AddCmd0(CODE.opADD + ORD(op = ORD("-"))) |
||
2093 | END |
||
2094 | ELSIF isReal(e) THEN |
||
2095 | IF e.obj = eCONST THEN |
||
2096 | CODE.Float(ARITH.Float(e.value)); |
||
2097 | CODE.fbinop(CODE.opADDFI + ORD(op = ORD("-"))) |
||
2098 | ELSIF e1.obj = eCONST THEN |
||
2099 | CODE.Float(ARITH.Float(e1.value)); |
||
2100 | CODE.fbinop(CODE.opADDF + ORD(op = ORD("-"))) |
||
2101 | ELSE |
||
2102 | CODE.fbinop(CODE.opADDF + ORD(op = ORD("-"))) |
||
2103 | END |
||
2104 | ELSIF isSet(e) THEN |
||
2105 | IF e.obj = eCONST THEN |
||
2106 | CODE.AddCmd(CODE.opADDSL + ORD(op = ORD("-")), ARITH.Int(e.value)) |
||
2107 | ELSIF e1.obj = eCONST THEN |
||
2108 | CODE.AddCmd(CODE.opADDSR + ORD(op = ORD("-")), ARITH.Int(e1.value)) |
||
2109 | ELSE |
||
2110 | CODE.AddCmd0(CODE.opADDS + ORD(op = ORD("-"))) |
||
2111 | END |
||
2112 | END; |
||
2113 | e.obj := eEXPR |
||
2114 | END |
||
2115 | |||
2116 | |SCAN.lxOR: |
||
2117 | PARS.check(isBoolean(e) & isBoolean(e1), parser, pos, 37); |
||
2118 | |||
2119 | IF (e.obj = eCONST) & (e1.obj = eCONST) THEN |
||
2120 | ARITH.opBoolean(e.value, e1.value, "|") |
||
2121 | ELSE |
||
2122 | e.obj := eEXPR; |
||
2123 | IF e1.obj = eCONST THEN |
||
2124 | CODE.AddCmd(CODE.opCONST, ORD(ARITH.getBool(e1.value))) |
||
2125 | END |
||
2126 | END |
||
2127 | |||
2128 | END |
||
2129 | END; |
||
2130 | |||
2131 | IF label # -1 THEN |
||
2132 | CODE.SetLabel(label) |
||
2133 | END |
||
2134 | |||
2135 | END SimpleExpression; |
||
2136 | |||
2137 | |||
2138 | PROCEDURE cmpcode (op: INTEGER): INTEGER; |
||
2139 | VAR |
||
2140 | res: INTEGER; |
||
2141 | BEGIN |
||
2142 | CASE op OF |
||
2143 | |SCAN.lxEQ: res := 0 |
||
2144 | |SCAN.lxNE: res := 1 |
||
2145 | |SCAN.lxLT: res := 2 |
||
2146 | |SCAN.lxLE: res := 3 |
||
2147 | |SCAN.lxGT: res := 4 |
||
2148 | |SCAN.lxGE: res := 5 |
||
2149 | END |
||
2150 | |||
2151 | RETURN res |
||
2152 | END cmpcode; |
||
2153 | |||
2154 | |||
2155 | PROCEDURE BoolCmp (eq, val: BOOLEAN); |
||
2156 | BEGIN |
||
2157 | IF eq = val THEN |
||
2158 | CODE.AddCmd0(CODE.opNER) |
||
2159 | ELSE |
||
2160 | CODE.AddCmd0(CODE.opEQR) |
||
2161 | END |
||
2162 | END BoolCmp; |
||
2163 | |||
2164 | |||
2165 | PROCEDURE strcmp (VAR e, e1: PARS.EXPR; op: INTEGER): BOOLEAN; |
||
2166 | VAR |
||
2167 | res: BOOLEAN; |
||
2168 | |||
2169 | BEGIN |
||
2170 | |||
2171 | res := TRUE; |
||
2172 | |||
2173 | IF isString(e) & isCharArray(e1) THEN |
||
2174 | CODE.AddCmd(CODE.opSADR, String(e)); |
||
2175 | CODE.AddCmd(CODE.opCONST, strlen(e) + 1); |
||
2176 | CODE.AddCmd0(CODE.opEQS2 + cmpcode(op)) |
||
2177 | |||
2178 | ELSIF isString(e) & isCharArrayW(e1) THEN |
||
2179 | CODE.AddCmd(CODE.opSADR, StringW(e)); |
||
2180 | CODE.AddCmd(CODE.opCONST, utf8strlen(e) + 1); |
||
2181 | CODE.AddCmd0(CODE.opEQSW2 + cmpcode(op)) |
||
2182 | |||
2183 | ELSIF isStringW(e) & isCharArrayW(e1) THEN |
||
2184 | CODE.AddCmd(CODE.opSADR, StringW(e)); |
||
2185 | CODE.AddCmd(CODE.opCONST, utf8strlen(e) + 1); |
||
2186 | CODE.AddCmd0(CODE.opEQSW2 + cmpcode(op)) |
||
2187 | |||
2188 | ELSIF isCharArray(e) & isString(e1) THEN |
||
2189 | CODE.AddCmd(CODE.opSADR, String(e1)); |
||
2190 | CODE.AddCmd(CODE.opCONST, strlen(e1) + 1); |
||
2191 | CODE.AddCmd0(CODE.opEQS + cmpcode(op)) |
||
2192 | |||
2193 | ELSIF isCharArrayW(e) & isString(e1) THEN |
||
2194 | CODE.AddCmd(CODE.opSADR, StringW(e1)); |
||
2195 | CODE.AddCmd(CODE.opCONST, utf8strlen(e1) + 1); |
||
2196 | CODE.AddCmd0(CODE.opEQSW + cmpcode(op)) |
||
2197 | |||
2198 | ELSIF isCharArrayW(e) & isStringW(e1) THEN |
||
2199 | CODE.AddCmd(CODE.opSADR, StringW(e1)); |
||
2200 | CODE.AddCmd(CODE.opCONST, utf8strlen(e1) + 1); |
||
2201 | CODE.AddCmd0(CODE.opEQSW + cmpcode(op)) |
||
2202 | |||
2203 | ELSIF isCharArrayW(e) & isCharArrayW(e1) THEN |
||
2204 | CODE.AddCmd0(CODE.opEQSW + cmpcode(op)) |
||
2205 | |||
2206 | ELSIF isCharArray(e) & isCharArray(e1) THEN |
||
2207 | CODE.AddCmd0(CODE.opEQS + cmpcode(op)) |
||
2208 | |||
2209 | ELSIF isString(e) & isString(e1) THEN |
||
2210 | PARS.strcmp(e.value, e1.value, op) |
||
2211 | |||
2212 | ELSE |
||
2213 | res := FALSE |
||
2214 | |||
2215 | END |
||
2216 | |||
2217 | RETURN res |
||
2218 | END strcmp; |
||
2219 | |||
2220 | |||
2221 | BEGIN |
||
2222 | getpos(parser, pos0); |
||
2223 | SimpleExpression(parser, e); |
||
2224 | IF relation(parser.sym) THEN |
||
2225 | IF (isCharArray(e) OR isCharArrayW(e)) & (e.type.length # 0) THEN |
||
2226 | CODE.AddCmd(CODE.opCONST, e.type.length) |
||
2227 | END; |
||
2228 | op := parser.sym; |
||
2229 | getpos(parser, pos); |
||
2230 | PARS.Next(parser); |
||
2231 | |||
2232 | pos1 := parser.lex.pos; |
||
2233 | SimpleExpression(parser, e1); |
||
2234 | |||
2235 | IF (isCharArray(e1) OR isCharArrayW(e1)) & (e1.type.length # 0) THEN |
||
2236 | CODE.AddCmd(CODE.opCONST, e1.type.length) |
||
2237 | END; |
||
2238 | |||
2239 | constant := (e.obj = eCONST) & (e1.obj = eCONST); |
||
2240 | |||
2241 | CASE op OF |
||
2242 | |SCAN.lxEQ: operator := "=" |
||
2243 | |SCAN.lxNE: operator := "#" |
||
2244 | |SCAN.lxLT: operator := "<" |
||
2245 | |SCAN.lxLE: operator := "<=" |
||
2246 | |SCAN.lxGT: operator := ">" |
||
2247 | |SCAN.lxGE: operator := ">=" |
||
2248 | |SCAN.lxIN: operator := "IN" |
||
2249 | |SCAN.lxIS: operator := "" |
||
2250 | END; |
||
2251 | |||
2252 | error := 0; |
||
2253 | |||
2254 | CASE op OF |
||
2255 | |SCAN.lxEQ, SCAN.lxNE: |
||
2256 | |||
2257 | IF isInt(e) & isInt(e1) OR isSet(e) & isSet(e1) OR isChar(e) & isChar(e1) OR isCharW(e) & isCharW(e1) OR |
||
2258 | isCharW(e) & isChar(e1) & (e1.obj = eCONST) OR isCharW(e1) & isChar(e) & (e.obj = eCONST) OR |
||
2259 | isCharW(e1) & (e1.obj = eCONST) & isChar(e) & (e.obj = eCONST) OR |
||
2260 | isCharW(e) & (e.obj = eCONST) & isChar(e1) & (e1.obj = eCONST) OR |
||
2261 | isPtr(e) & isPtr(e1) & (PROG.isBaseOf(e.type, e1.type) OR PROG.isBaseOf(e1.type, e.type)) THEN |
||
2262 | IF constant THEN |
||
2263 | ARITH.relation(e.value, e1.value, operator, error) |
||
2264 | ELSE |
||
2265 | IF e.obj = eCONST THEN |
||
2266 | CODE.AddCmd(CODE.opEQ + cmpcode(op) + 6, ARITH.Int(e.value)) |
||
2267 | ELSIF e1.obj = eCONST THEN |
||
2268 | CODE.AddCmd(CODE.opEQ + cmpcode(op) + 12, ARITH.Int(e1.value)) |
||
2269 | ELSE |
||
2270 | CODE.AddCmd0(CODE.opEQ + cmpcode(op)) |
||
2271 | END |
||
2272 | END |
||
2273 | |||
2274 | ELSIF isStringW1(e) & isCharW(e1) THEN |
||
2275 | CODE.AddCmd(CODE.opEQ + cmpcode(op) + 6, StrToWChar(e.value.string(SCAN.IDENT).s)) |
||
2276 | |||
2277 | ELSIF isStringW1(e1) & isCharW(e) THEN |
||
2278 | CODE.AddCmd(CODE.opEQ + cmpcode(op) + 12, StrToWChar(e1.value.string(SCAN.IDENT).s)) |
||
2279 | |||
2280 | ELSIF isBoolean(e) & isBoolean(e1) THEN |
||
2281 | IF constant THEN |
||
2282 | ARITH.relation(e.value, e1.value, operator, error) |
||
2283 | ELSE |
||
2284 | IF e.obj = eCONST THEN |
||
2285 | BoolCmp(op = SCAN.lxEQ, ARITH.Int(e.value) # 0) |
||
2286 | ELSIF e1.obj = eCONST THEN |
||
2287 | BoolCmp(op = SCAN.lxEQ, ARITH.Int(e1.value) # 0) |
||
2288 | ELSE |
||
2289 | IF op = SCAN.lxEQ THEN |
||
2290 | CODE.AddCmd0(CODE.opEQB) |
||
2291 | ELSE |
||
2292 | CODE.AddCmd0(CODE.opNEB) |
||
2293 | END |
||
2294 | END |
||
2295 | END |
||
2296 | |||
2297 | ELSIF isReal(e) & isReal(e1) THEN |
||
2298 | IF constant THEN |
||
2299 | ARITH.relation(e.value, e1.value, operator, error) |
||
2300 | ELSE |
||
2301 | IF e.obj = eCONST THEN |
||
2302 | CODE.Float(ARITH.Float(e.value)); |
||
2303 | CODE.fcmp(CODE.opEQF + cmpcode(op) + 6) |
||
2304 | ELSIF e1.obj = eCONST THEN |
||
2305 | CODE.Float(ARITH.Float(e1.value)); |
||
2306 | CODE.fcmp(CODE.opEQF + cmpcode(op)) |
||
2307 | ELSE |
||
2308 | CODE.fcmp(CODE.opEQF + cmpcode(op)) |
||
2309 | END |
||
2310 | END |
||
2311 | |||
2312 | ELSIF (isStringW(e) OR isCharArrayX(e)) & (isStringW(e1) OR isCharArrayX(e1)) THEN |
||
2313 | IF ~strcmp(e, e1, op) THEN |
||
2314 | PARS.error(parser, pos, 37) |
||
2315 | END |
||
2316 | |||
2317 | ELSIF isPtr(e) & isNil(e1) OR isNil(e) & isPtr(e1) THEN |
||
2318 | CODE.AddCmd0(CODE.opEQ + cmpcode(op) + 6) |
||
2319 | |||
2320 | ELSIF isProc(e) & isNil(e1) THEN |
||
2321 | IF e.obj IN {ePROC, eIMP} THEN |
||
2322 | PARS.check(e.ident.global, parser, pos0, 85); |
||
2323 | constant := TRUE; |
||
2324 | e.obj := eCONST; |
||
2325 | ARITH.setbool(e.value, op = SCAN.lxNE) |
||
2326 | ELSE |
||
2327 | CODE.AddCmd0(CODE.opEQ + cmpcode(op) + 6) |
||
2328 | END |
||
2329 | |||
2330 | ELSIF isNil(e) & isProc(e1) THEN |
||
2331 | IF e1.obj IN {ePROC, eIMP} THEN |
||
2332 | PARS.check(e1.ident.global, parser, pos1, 85); |
||
2333 | constant := TRUE; |
||
2334 | e.obj := eCONST; |
||
2335 | ARITH.setbool(e.value, op = SCAN.lxNE) |
||
2336 | ELSE |
||
2337 | CODE.AddCmd0(CODE.opEQ + cmpcode(op) + 6) |
||
2338 | END |
||
2339 | |||
2340 | ELSIF isProc(e) & isProc(e1) & PROG.isTypeEq(e.type, e1.type) THEN |
||
2341 | IF e.obj = ePROC THEN |
||
2342 | PARS.check(e.ident.global, parser, pos0, 85) |
||
2343 | END; |
||
2344 | IF e1.obj = ePROC THEN |
||
2345 | PARS.check(e1.ident.global, parser, pos1, 85) |
||
2346 | END; |
||
2347 | IF (e.obj IN {ePROC, eIMP}) & (e1.obj IN {ePROC, eIMP}) THEN |
||
2348 | constant := TRUE; |
||
2349 | e.obj := eCONST; |
||
2350 | IF op = SCAN.lxEQ THEN |
||
2351 | ARITH.setbool(e.value, e.ident = e1.ident) |
||
2352 | ELSE |
||
2353 | ARITH.setbool(e.value, e.ident # e1.ident) |
||
2354 | END |
||
2355 | ELSIF e.obj = ePROC THEN |
||
2356 | CODE.ProcCmp(e.ident.proc.label, cmpcode(op) = 0) |
||
2357 | ELSIF e1.obj = ePROC THEN |
||
2358 | CODE.ProcCmp(e1.ident.proc.label, cmpcode(op) = 0) |
||
2359 | ELSIF e.obj = eIMP THEN |
||
2360 | CODE.ProcImpCmp(e.ident.import, cmpcode(op) = 0) |
||
2361 | ELSIF e1.obj = eIMP THEN |
||
2362 | CODE.ProcImpCmp(e1.ident.import, cmpcode(op) = 0) |
||
2363 | ELSE |
||
2364 | CODE.AddCmd0(CODE.opEQ + cmpcode(op)) |
||
2365 | END |
||
2366 | |||
2367 | ELSIF isNil(e) & isNil(e1) THEN |
||
2368 | constant := TRUE; |
||
2369 | e.obj := eCONST; |
||
2370 | ARITH.setbool(e.value, op = SCAN.lxEQ) |
||
2371 | |||
2372 | ELSE |
||
2373 | PARS.error(parser, pos, 37) |
||
2374 | END |
||
2375 | |||
2376 | |SCAN.lxLT, SCAN.lxLE, SCAN.lxGT, SCAN.lxGE: |
||
2377 | IF isInt(e) & isInt(e1) OR isChar(e) & isChar(e1) OR isCharW(e) & isCharW(e1) OR |
||
2378 | isCharW(e) & isChar(e1) & (e1.obj = eCONST) OR isCharW(e1) & isChar(e) & (e.obj = eCONST) OR |
||
2379 | isCharW(e1) & (e1.obj = eCONST) & isChar(e) & (e.obj = eCONST) OR |
||
2380 | isCharW(e) & (e.obj = eCONST) & isChar(e1) & (e1.obj = eCONST) THEN |
||
2381 | |||
2382 | IF constant THEN |
||
2383 | ARITH.relation(e.value, e1.value, operator, error) |
||
2384 | ELSE |
||
2385 | IF e.obj = eCONST THEN |
||
2386 | CODE.AddCmd(CODE.opEQ + cmpcode(op) + 6, ARITH.Int(e.value)) |
||
2387 | ELSIF e1.obj = eCONST THEN |
||
2388 | CODE.AddCmd(CODE.opEQ + cmpcode(op) + 12, ARITH.Int(e1.value)) |
||
2389 | ELSE |
||
2390 | CODE.AddCmd0(CODE.opEQ + cmpcode(op)) |
||
2391 | END |
||
2392 | END |
||
2393 | |||
2394 | ELSIF isStringW1(e) & isCharW(e1) THEN |
||
2395 | CODE.AddCmd(CODE.opEQ + cmpcode(op) + 6, StrToWChar(e.value.string(SCAN.IDENT).s)) |
||
2396 | |||
2397 | ELSIF isStringW1(e1) & isCharW(e) THEN |
||
2398 | CODE.AddCmd(CODE.opEQ + cmpcode(op) + 12, StrToWChar(e1.value.string(SCAN.IDENT).s)) |
||
2399 | |||
2400 | ELSIF isReal(e) & isReal(e1) THEN |
||
2401 | IF constant THEN |
||
2402 | ARITH.relation(e.value, e1.value, operator, error) |
||
2403 | ELSE |
||
2404 | IF e.obj = eCONST THEN |
||
2405 | CODE.Float(ARITH.Float(e.value)); |
||
2406 | CODE.fcmp(CODE.opEQF + cmpcode(op) + 6) |
||
2407 | ELSIF e1.obj = eCONST THEN |
||
2408 | CODE.Float(ARITH.Float(e1.value)); |
||
2409 | CODE.fcmp(CODE.opEQF + cmpcode(op)) |
||
2410 | ELSE |
||
2411 | CODE.fcmp(CODE.opEQF + cmpcode(op)) |
||
2412 | END |
||
2413 | END |
||
2414 | |||
2415 | ELSIF (isStringW(e) OR isCharArrayX(e)) & (isStringW(e1) OR isCharArrayX(e1)) THEN |
||
2416 | IF ~strcmp(e, e1, op) THEN |
||
2417 | PARS.error(parser, pos, 37) |
||
2418 | END |
||
2419 | |||
2420 | ELSE |
||
2421 | PARS.error(parser, pos, 37) |
||
2422 | END |
||
2423 | |||
2424 | |SCAN.lxIN: |
||
2425 | PARS.check(isInt(e) & isSet(e1), parser, pos, 37); |
||
2426 | IF e.obj = eCONST THEN |
||
2427 | PARS.check(ARITH.range(e.value, 0, MACHINE.target.maxSet), parser, pos0, 56) |
||
2428 | END; |
||
2429 | IF constant THEN |
||
2430 | ARITH.relation(e.value, e1.value, operator, error) |
||
2431 | ELSE |
||
2432 | IF e.obj = eCONST THEN |
||
2433 | CODE.AddCmd(CODE.opINL, ARITH.Int(e.value)) |
||
2434 | ELSIF e1.obj = eCONST THEN |
||
2435 | CODE.AddCmd(CODE.opINR, ARITH.Int(e1.value)) |
||
2436 | ELSE |
||
2437 | CODE.AddCmd0(CODE.opIN) |
||
2438 | END |
||
2439 | END |
||
2440 | |||
2441 | |SCAN.lxIS: |
||
2442 | PARS.check(isExpr(e) & (e.type.typ IN {PROG.tRECORD, PROG.tPOINTER}), parser, pos, 73); |
||
2443 | IF e.type.typ = PROG.tRECORD THEN |
||
2444 | PARS.check(e.obj = eVREC, parser, pos0, 78) |
||
2445 | END; |
||
2446 | PARS.check(e1.obj = eTYPE, parser, pos1, 79); |
||
2447 | |||
2448 | IF e.type.typ = PROG.tRECORD THEN |
||
2449 | PARS.check(e1.type.typ = PROG.tRECORD, parser, pos1, 80); |
||
2450 | IF e.ident = NIL THEN |
||
2451 | CODE.TypeCheck(e1.type.num) |
||
2452 | ELSE |
||
2453 | CODE.AddCmd(CODE.opVADR, e.ident.offset - 1); |
||
2454 | CODE.TypeCheckRec(e1.type.num) |
||
2455 | END |
||
2456 | ELSE |
||
2457 | PARS.check(e1.type.typ = PROG.tPOINTER, parser, pos1, 81); |
||
2458 | CODE.TypeCheck(e1.type.base.num) |
||
2459 | END; |
||
2460 | |||
2461 | PARS.check(PROG.isBaseOf(e.type, e1.type), parser, pos1, 82) |
||
2462 | |||
2463 | END; |
||
2464 | |||
2465 | ASSERT(error = 0); |
||
2466 | |||
2467 | e.type := PARS.program.stTypes.tBOOLEAN; |
||
2468 | |||
2469 | IF ~constant THEN |
||
2470 | e.obj := eEXPR |
||
2471 | END |
||
2472 | |||
2473 | END |
||
2474 | END expression; |
||
2475 | |||
2476 | |||
2477 | PROCEDURE ElementaryStatement (parser: PARS.PARSER); |
||
2478 | VAR |
||
2479 | e, e1: PARS.EXPR; |
||
2480 | pos: SCAN.POSITION; |
||
2481 | line: INTEGER; |
||
2482 | call: BOOLEAN; |
||
2483 | fregs: INTEGER; |
||
2484 | |||
2485 | BEGIN |
||
2486 | getpos(parser, pos); |
||
2487 | |||
2488 | CODE.pushBegEnd(begcall, endcall); |
||
2489 | |||
2490 | designator(parser, e); |
||
2491 | |||
2492 | IF parser.sym = SCAN.lxASSIGN THEN |
||
2493 | line := parser.lex.pos.line; |
||
2494 | PARS.check(isVar(e), parser, pos, 93); |
||
2495 | PARS.check(~e.readOnly, parser, pos, 94); |
||
2496 | |||
2497 | CODE.setlast(begcall); |
||
2498 | |||
2499 | NextPos(parser, pos); |
||
2500 | expression(parser, e1); |
||
2501 | |||
2502 | CODE.setlast(endcall.prev(CODE.COMMAND)); |
||
2503 | |||
2504 | PARS.check(assign(e1, e.type, line), parser, pos, 91); |
||
2505 | IF e1.obj = ePROC THEN |
||
2506 | PARS.check(e1.ident.global, parser, pos, 85) |
||
2507 | END; |
||
2508 | call := FALSE |
||
2509 | ELSIF parser.sym = SCAN.lxEQ THEN |
||
2510 | PARS.check1(FALSE, parser, 96) |
||
2511 | ELSIF parser.sym = SCAN.lxLROUND THEN |
||
2512 | e1 := e; |
||
2513 | ActualParameters(parser, e1); |
||
2514 | PARS.check((e1.type = NIL) OR ODD(e.type.call), parser, pos, 92); |
||
2515 | call := TRUE |
||
2516 | ELSE |
||
2517 | PARS.check(isProc(e), parser, pos, 86); |
||
2518 | PARS.check((e.type.base = NIL) OR ODD(e.type.call), parser, pos, 92); |
||
2519 | PARS.check1(e.type.params.first = NIL, parser, 64); |
||
2520 | call := TRUE |
||
2521 | END; |
||
2522 | |||
2523 | IF call THEN |
||
2524 | IF e.obj IN {ePROC, eIMP} THEN |
||
2525 | ProcCall(e, e.ident.type, FALSE, fregs, parser, pos, TRUE) |
||
2526 | ELSIF isExpr(e) THEN |
||
2527 | ProcCall(e, e.type, FALSE, fregs, parser, pos, TRUE) |
||
2528 | END |
||
2529 | END; |
||
2530 | |||
2531 | CODE.popBegEnd(begcall, endcall) |
||
2532 | END ElementaryStatement; |
||
2533 | |||
2534 | |||
2535 | PROCEDURE IfStatement (parser: PARS.PARSER; if: BOOLEAN); |
||
2536 | VAR |
||
2537 | e: PARS.EXPR; |
||
2538 | pos: SCAN.POSITION; |
||
2539 | |||
2540 | label, L: INTEGER; |
||
2541 | |||
2542 | BEGIN |
||
2543 | L := CODE.NewLabel(); |
||
2544 | |||
2545 | IF ~if THEN |
||
2546 | CODE.AddCmd0(CODE.opLOOP); |
||
2547 | CODE.SetLabel(L) |
||
2548 | END; |
||
2549 | |||
2550 | REPEAT |
||
2551 | NextPos(parser, pos); |
||
2552 | |||
2553 | label := CODE.NewLabel(); |
||
2554 | |||
2555 | expression(parser, e); |
||
2556 | PARS.check(isBoolean(e), parser, pos, 72); |
||
2557 | |||
2558 | IF e.obj = eCONST THEN |
||
2559 | IF ~ARITH.getBool(e.value) THEN |
||
2560 | CODE.AddJmpCmd(CODE.opJMP, label) |
||
2561 | END |
||
2562 | ELSE |
||
2563 | CODE.AddJmpCmd(CODE.opJNE, label) |
||
2564 | END; |
||
2565 | |||
2566 | IF if THEN |
||
2567 | PARS.checklex(parser, SCAN.lxTHEN) |
||
2568 | ELSE |
||
2569 | PARS.checklex(parser, SCAN.lxDO) |
||
2570 | END; |
||
2571 | |||
2572 | PARS.Next(parser); |
||
2573 | parser.StatSeq(parser); |
||
2574 | |||
2575 | CODE.AddJmpCmd(CODE.opJMP, L); |
||
2576 | CODE.SetLabel(label) |
||
2577 | |||
2578 | UNTIL parser.sym # SCAN.lxELSIF; |
||
2579 | |||
2580 | IF if THEN |
||
2581 | IF parser.sym = SCAN.lxELSE THEN |
||
2582 | PARS.Next(parser); |
||
2583 | parser.StatSeq(parser) |
||
2584 | END; |
||
2585 | CODE.SetLabel(L) |
||
2586 | END; |
||
2587 | |||
2588 | PARS.checklex(parser, SCAN.lxEND); |
||
2589 | |||
2590 | IF ~if THEN |
||
2591 | CODE.AddCmd0(CODE.opENDLOOP) |
||
2592 | END; |
||
2593 | |||
2594 | PARS.Next(parser) |
||
2595 | END IfStatement; |
||
2596 | |||
2597 | |||
2598 | PROCEDURE RepeatStatement (parser: PARS.PARSER); |
||
2599 | VAR |
||
2600 | e: PARS.EXPR; |
||
2601 | pos: SCAN.POSITION; |
||
2602 | label: INTEGER; |
||
2603 | |||
2604 | BEGIN |
||
2605 | CODE.AddCmd0(CODE.opLOOP); |
||
2606 | |||
2607 | label := CODE.NewLabel(); |
||
2608 | CODE.SetLabel(label); |
||
2609 | |||
2610 | PARS.Next(parser); |
||
2611 | parser.StatSeq(parser); |
||
2612 | PARS.checklex(parser, SCAN.lxUNTIL); |
||
2613 | NextPos(parser, pos); |
||
2614 | expression(parser, e); |
||
2615 | PARS.check(isBoolean(e), parser, pos, 72); |
||
2616 | |||
2617 | IF e.obj = eCONST THEN |
||
2618 | IF ~ARITH.getBool(e.value) THEN |
||
2619 | CODE.AddJmpCmd(CODE.opJMP, label) |
||
2620 | END |
||
2621 | ELSE |
||
2622 | CODE.AddJmpCmd(CODE.opJNE, label) |
||
2623 | END; |
||
2624 | |||
2625 | CODE.AddCmd0(CODE.opENDLOOP) |
||
2626 | END RepeatStatement; |
||
2627 | |||
2628 | |||
2629 | PROCEDURE LabelCmp (a, b: AVL.DATA): INTEGER; |
||
2630 | VAR |
||
2631 | La, Ra, Lb, Rb, res: INTEGER; |
||
2632 | |||
2633 | BEGIN |
||
2634 | La := a(CASE_LABEL).range.a; |
||
2635 | Ra := a(CASE_LABEL).range.b; |
||
2636 | Lb := b(CASE_LABEL).range.a; |
||
2637 | Rb := b(CASE_LABEL).range.b; |
||
2638 | IF (Ra < Lb) OR (La > Rb) THEN |
||
2639 | res := ORD(La > Lb) - ORD(La < Lb) |
||
2640 | ELSE |
||
2641 | res := 0 |
||
2642 | END |
||
2643 | |||
2644 | RETURN res |
||
2645 | END LabelCmp; |
||
2646 | |||
2647 | |||
2648 | PROCEDURE DestroyLabel (VAR label: AVL.DATA); |
||
2649 | BEGIN |
||
2650 | C.push(CaseLabels, label); |
||
2651 | label := NIL |
||
2652 | END DestroyLabel; |
||
2653 | |||
2654 | |||
2655 | PROCEDURE NewVariant (label: INTEGER; cmd: CODE.COMMAND): CASE_VARIANT; |
||
2656 | VAR |
||
2657 | res: CASE_VARIANT; |
||
2658 | citem: C.ITEM; |
||
2659 | |||
2660 | BEGIN |
||
2661 | citem := C.pop(CaseVar); |
||
2662 | IF citem = NIL THEN |
||
2663 | NEW(res) |
||
2664 | ELSE |
||
2665 | res := citem(CASE_VARIANT) |
||
2666 | END; |
||
2667 | |||
2668 | res.label := label; |
||
2669 | res.cmd := cmd; |
||
2670 | res.processed := FALSE |
||
2671 | |||
2672 | RETURN res |
||
2673 | END NewVariant; |
||
2674 | |||
2675 | |||
2676 | PROCEDURE CaseStatement (parser: PARS.PARSER); |
||
2677 | VAR |
||
2678 | e: PARS.EXPR; |
||
2679 | pos: SCAN.POSITION; |
||
2680 | |||
2681 | |||
2682 | PROCEDURE isRecPtr (caseExpr: PARS.EXPR): BOOLEAN; |
||
2683 | RETURN isRec(caseExpr) OR isPtr(caseExpr) |
||
2684 | END isRecPtr; |
||
2685 | |||
2686 | |||
2687 | PROCEDURE Label (parser: PARS.PARSER; caseExpr: PARS.EXPR; VAR type: PROG.TYPE_): INTEGER; |
||
2688 | VAR |
||
2689 | a: INTEGER; |
||
2690 | label: PARS.EXPR; |
||
2691 | pos: SCAN.POSITION; |
||
2692 | value: ARITH.VALUE; |
||
2693 | |||
2694 | BEGIN |
||
2695 | getpos(parser, pos); |
||
2696 | type := NIL; |
||
2697 | |||
2698 | IF isChar(caseExpr) THEN |
||
2699 | PARS.ConstExpression(parser, value); |
||
2700 | PARS.check(value.typ = ARITH.tCHAR, parser, pos, 99); |
||
2701 | a := ARITH.getInt(value) |
||
2702 | ELSIF isCharW(caseExpr) THEN |
||
2703 | PARS.ConstExpression(parser, value); |
||
2704 | IF (value.typ = ARITH.tSTRING) & (_length(value.string(SCAN.IDENT).s) = 1) & (LENGTH(value.string(SCAN.IDENT).s) > 1) THEN |
||
2705 | ASSERT(ARITH.setInt(value, StrToWChar(value.string(SCAN.IDENT).s))) |
||
2706 | ELSE |
||
2707 | PARS.check(value.typ IN {ARITH.tWCHAR, ARITH.tCHAR}, parser, pos, 99) |
||
2708 | END; |
||
2709 | a := ARITH.getInt(value) |
||
2710 | ELSIF isInt(caseExpr) THEN |
||
2711 | PARS.ConstExpression(parser, value); |
||
2712 | PARS.check(value.typ = ARITH.tINTEGER, parser, pos, 99); |
||
2713 | a := ARITH.getInt(value) |
||
2714 | ELSIF isRecPtr(caseExpr) THEN |
||
2715 | qualident(parser, label); |
||
2716 | PARS.check(label.obj = eTYPE, parser, pos, 79); |
||
2717 | PARS.check(PROG.isBaseOf(caseExpr.type, label.type), parser, pos, 99); |
||
2718 | IF isRec(caseExpr) THEN |
||
2719 | a := label.type.num |
||
2720 | ELSE |
||
2721 | a := label.type.base.num |
||
2722 | END; |
||
2723 | type := label.type |
||
2724 | END |
||
2725 | |||
2726 | RETURN a |
||
2727 | END Label; |
||
2728 | |||
2729 | |||
2730 | PROCEDURE CheckType (node: AVL.NODE; type: PROG.TYPE_; parser: PARS.PARSER; pos: SCAN.POSITION); |
||
2731 | BEGIN |
||
2732 | IF node # NIL THEN |
||
2733 | PARS.check(~(PROG.isBaseOf(node.data(CASE_LABEL).type, type) OR PROG.isBaseOf(type, node.data(CASE_LABEL).type)), parser, pos, 100); |
||
2734 | CheckType(node.left, type, parser, pos); |
||
2735 | CheckType(node.right, type, parser, pos) |
||
2736 | END |
||
2737 | END CheckType; |
||
2738 | |||
2739 | |||
2740 | PROCEDURE LabelRange (parser: PARS.PARSER; caseExpr: PARS.EXPR; VAR tree: AVL.NODE; variant: INTEGER): AVL.NODE; |
||
2741 | VAR |
||
2742 | label: CASE_LABEL; |
||
2743 | citem: C.ITEM; |
||
2744 | pos, pos1: SCAN.POSITION; |
||
2745 | node: AVL.NODE; |
||
2746 | newnode: BOOLEAN; |
||
2747 | range: RANGE; |
||
2748 | |||
2749 | BEGIN |
||
2750 | citem := C.pop(CaseLabels); |
||
2751 | IF citem = NIL THEN |
||
2752 | NEW(label) |
||
2753 | ELSE |
||
2754 | label := citem(CASE_LABEL) |
||
2755 | END; |
||
2756 | |||
2757 | label.variant := variant; |
||
2758 | label.self := CODE.NewLabel(); |
||
2759 | |||
2760 | getpos(parser, pos1); |
||
2761 | range.a := Label(parser, caseExpr, label.type); |
||
2762 | |||
2763 | IF parser.sym = SCAN.lxRANGE THEN |
||
2764 | PARS.check1(~isRecPtr(caseExpr), parser, 53); |
||
2765 | NextPos(parser, pos); |
||
2766 | range.b := Label(parser, caseExpr, label.type); |
||
2767 | PARS.check(range.a <= range.b, parser, pos, 103) |
||
2768 | ELSE |
||
2769 | range.b := range.a |
||
2770 | END; |
||
2771 | |||
2772 | label.range := range; |
||
2773 | |||
2774 | IF isRecPtr(caseExpr) THEN |
||
2775 | CheckType(tree, label.type, parser, pos1) |
||
2776 | END; |
||
2777 | tree := AVL.insert(tree, label, LabelCmp, newnode, node); |
||
2778 | PARS.check(newnode, parser, pos1, 100) |
||
2779 | |||
2780 | RETURN node |
||
2781 | |||
2782 | END LabelRange; |
||
2783 | |||
2784 | |||
2785 | PROCEDURE CaseLabelList (parser: PARS.PARSER; caseExpr: PARS.EXPR; VAR tree: AVL.NODE; variant: INTEGER): AVL.NODE; |
||
2786 | VAR |
||
2787 | exit: BOOLEAN; |
||
2788 | res: AVL.NODE; |
||
2789 | |||
2790 | BEGIN |
||
2791 | exit := FALSE; |
||
2792 | REPEAT |
||
2793 | res := LabelRange(parser, caseExpr, tree, variant); |
||
2794 | IF parser.sym = SCAN.lxCOMMA THEN |
||
2795 | PARS.check1(~isRecPtr(caseExpr), parser, 53); |
||
2796 | PARS.Next(parser) |
||
2797 | ELSE |
||
2798 | exit := TRUE |
||
2799 | END |
||
2800 | UNTIL exit |
||
2801 | |||
2802 | RETURN res |
||
2803 | END CaseLabelList; |
||
2804 | |||
2805 | |||
2806 | PROCEDURE case (parser: PARS.PARSER; caseExpr: PARS.EXPR; VAR tree: AVL.NODE; end: INTEGER); |
||
2807 | VAR |
||
2808 | sym: INTEGER; |
||
2809 | t: PROG.TYPE_; |
||
2810 | variant: INTEGER; |
||
2811 | node: AVL.NODE; |
||
2812 | last: CODE.COMMAND; |
||
2813 | |||
2814 | BEGIN |
||
2815 | sym := parser.sym; |
||
2816 | IF sym # SCAN.lxBAR THEN |
||
2817 | variant := CODE.NewLabel(); |
||
2818 | node := CaseLabelList(parser, caseExpr, tree, variant); |
||
2819 | PARS.checklex(parser, SCAN.lxCOLON); |
||
2820 | PARS.Next(parser); |
||
2821 | IF isRecPtr(caseExpr) THEN |
||
2822 | t := caseExpr.type; |
||
2823 | caseExpr.ident.type := node.data(CASE_LABEL).type |
||
2824 | END; |
||
2825 | |||
2826 | last := CODE.getlast(); |
||
2827 | CODE.SetLabel(variant); |
||
2828 | |||
2829 | IF ~isRecPtr(caseExpr) THEN |
||
2830 | LISTS.push(CaseVariants, NewVariant(variant, last)) |
||
2831 | END; |
||
2832 | |||
2833 | parser.StatSeq(parser); |
||
2834 | CODE.AddJmpCmd(CODE.opJMP, end); |
||
2835 | |||
2836 | IF isRecPtr(caseExpr) THEN |
||
2837 | caseExpr.ident.type := t |
||
2838 | END |
||
2839 | END |
||
2840 | END case; |
||
2841 | |||
2842 | |||
2843 | PROCEDURE Table (node: AVL.NODE; else: INTEGER); |
||
2844 | VAR |
||
2845 | L, R: INTEGER; |
||
2846 | range: RANGE; |
||
2847 | left, right: AVL.NODE; |
||
2848 | last: CODE.COMMAND; |
||
2849 | v: CASE_VARIANT; |
||
2850 | |||
2851 | BEGIN |
||
2852 | IF node # NIL THEN |
||
2853 | |||
2854 | range := node.data(CASE_LABEL).range; |
||
2855 | |||
2856 | left := node.left; |
||
2857 | IF left # NIL THEN |
||
2858 | L := left.data(CASE_LABEL).self |
||
2859 | ELSE |
||
2860 | L := else |
||
2861 | END; |
||
2862 | |||
2863 | right := node.right; |
||
2864 | IF right # NIL THEN |
||
2865 | R := right.data(CASE_LABEL).self |
||
2866 | ELSE |
||
2867 | R := else |
||
2868 | END; |
||
2869 | |||
2870 | last := CODE.getlast(); |
||
2871 | |||
2872 | v := CaseVariants.last(CASE_VARIANT); |
||
2873 | WHILE (v # NIL) & (v.label # 0) & (v.label # node.data(CASE_LABEL).variant) DO |
||
2874 | v := v.prev(CASE_VARIANT) |
||
2875 | END; |
||
2876 | |||
2877 | ASSERT((v # NIL) & (v.label # 0)); |
||
2878 | CODE.setlast(v.cmd); |
||
2879 | |||
2880 | CODE.SetLabel(node.data(CASE_LABEL).self); |
||
2881 | CODE.case(range.a, range.b, L, R); |
||
2882 | IF v.processed THEN |
||
2883 | CODE.AddJmpCmd(CODE.opJMP, node.data(CASE_LABEL).variant) |
||
2884 | END; |
||
2885 | v.processed := TRUE; |
||
2886 | |||
2887 | CODE.setlast(last); |
||
2888 | |||
2889 | Table(left, else); |
||
2890 | Table(right, else) |
||
2891 | END |
||
2892 | END Table; |
||
2893 | |||
2894 | |||
2895 | PROCEDURE TableT (node: AVL.NODE); |
||
2896 | BEGIN |
||
2897 | IF node # NIL THEN |
||
2898 | CODE.caset(node.data(CASE_LABEL).range.a, node.data(CASE_LABEL).variant); |
||
2899 | |||
2900 | TableT(node.left); |
||
2901 | TableT(node.right) |
||
2902 | END |
||
2903 | END TableT; |
||
2904 | |||
2905 | |||
2906 | PROCEDURE ParseCase (parser: PARS.PARSER; e: PARS.EXPR; pos: SCAN.POSITION); |
||
2907 | VAR |
||
2908 | table, end, else: INTEGER; |
||
2909 | tree: AVL.NODE; |
||
2910 | item: LISTS.ITEM; |
||
2911 | |||
2912 | BEGIN |
||
2913 | LISTS.push(CaseVariants, NewVariant(0, NIL)); |
||
2914 | end := CODE.NewLabel(); |
||
2915 | else := CODE.NewLabel(); |
||
2916 | table := CODE.NewLabel(); |
||
2917 | CODE.AddCmd(CODE.opSWITCH, ORD(isRecPtr(e))); |
||
2918 | CODE.AddJmpCmd(CODE.opJMP, table); |
||
2919 | |||
2920 | tree := NIL; |
||
2921 | |||
2922 | case(parser, e, tree, end); |
||
2923 | WHILE parser.sym = SCAN.lxBAR DO |
||
2924 | PARS.Next(parser); |
||
2925 | case(parser, e, tree, end) |
||
2926 | END; |
||
2927 | |||
2928 | CODE.SetLabel(else); |
||
2929 | IF parser.sym = SCAN.lxELSE THEN |
||
2930 | PARS.Next(parser); |
||
2931 | parser.StatSeq(parser); |
||
2932 | CODE.AddJmpCmd(CODE.opJMP, end) |
||
2933 | ELSE |
||
2934 | CODE.OnError(pos.line, errCASE) |
||
2935 | END; |
||
2936 | |||
2937 | PARS.checklex(parser, SCAN.lxEND); |
||
2938 | PARS.Next(parser); |
||
2939 | |||
2940 | IF isRecPtr(e) THEN |
||
2941 | CODE.SetLabel(table); |
||
2942 | TableT(tree); |
||
2943 | CODE.AddJmpCmd(CODE.opJMP, else) |
||
2944 | ELSE |
||
2945 | tree.data(CASE_LABEL).self := table; |
||
2946 | Table(tree, else) |
||
2947 | END; |
||
2948 | |||
2949 | AVL.destroy(tree, DestroyLabel); |
||
2950 | CODE.SetLabel(end); |
||
2951 | CODE.AddCmd0(CODE.opENDSW); |
||
2952 | |||
2953 | REPEAT |
||
2954 | item := LISTS.pop(CaseVariants); |
||
2955 | C.push(CaseVar, item) |
||
2956 | UNTIL item(CASE_VARIANT).cmd = NIL |
||
2957 | |||
2958 | END ParseCase; |
||
2959 | |||
2960 | |||
2961 | BEGIN |
||
2962 | NextPos(parser, pos); |
||
2963 | expression(parser, e); |
||
2964 | PARS.check(isInt(e) OR isChar(e) OR isCharW(e) OR isPtr(e) OR isRec(e), parser, pos, 95); |
||
2965 | IF isRecPtr(e) THEN |
||
2966 | PARS.check(isVar(e), parser, pos, 93); |
||
2967 | PARS.check(e.ident # NIL, parser, pos, 106) |
||
2968 | END; |
||
2969 | IF isRec(e) THEN |
||
2970 | PARS.check(e.obj = eVREC, parser, pos, 78) |
||
2971 | END; |
||
2972 | |||
2973 | IF e.obj = eCONST THEN |
||
2974 | LoadConst(e) |
||
2975 | ELSIF isRec(e) THEN |
||
2976 | CODE.drop; |
||
2977 | CODE.AddCmd(CODE.opLADR, e.ident.offset - 1); |
||
2978 | CODE.load(PARS.program.target.word) |
||
2979 | ELSIF isPtr(e) THEN |
||
2980 | deref(pos, e, FALSE, errPTR); |
||
2981 | CODE.AddCmd(CODE.opSUBR, PARS.program.target.word); |
||
2982 | CODE.load(PARS.program.target.word) |
||
2983 | END; |
||
2984 | |||
2985 | PARS.checklex(parser, SCAN.lxOF); |
||
2986 | PARS.Next(parser); |
||
2987 | ParseCase(parser, e, pos) |
||
2988 | END CaseStatement; |
||
2989 | |||
2990 | |||
2991 | PROCEDURE ForStatement (parser: PARS.PARSER); |
||
2992 | VAR |
||
2993 | e: PARS.EXPR; |
||
2994 | pos: SCAN.POSITION; |
||
2995 | step: ARITH.VALUE; |
||
2996 | st: INTEGER; |
||
2997 | ident: PROG.IDENT; |
||
2998 | offset: INTEGER; |
||
2999 | L1, L2: INTEGER; |
||
3000 | |||
3001 | BEGIN |
||
3002 | CODE.AddCmd0(CODE.opLOOP); |
||
3003 | |||
3004 | L1 := CODE.NewLabel(); |
||
3005 | L2 := CODE.NewLabel(); |
||
3006 | |||
3007 | PARS.ExpectSym(parser, SCAN.lxIDENT); |
||
3008 | ident := parser.unit.idents.get(parser.unit, parser.lex.ident, TRUE); |
||
3009 | PARS.check1(ident # NIL, parser, 48); |
||
3010 | PARS.check1(ident.typ = PROG.idVAR, parser, 93); |
||
3011 | PARS.check1(ident.type.typ = PROG.tINTEGER, parser, 97); |
||
3012 | PARS.ExpectSym(parser, SCAN.lxASSIGN); |
||
3013 | NextPos(parser, pos); |
||
3014 | expression(parser, e); |
||
3015 | PARS.check(isInt(e), parser, pos, 76); |
||
3016 | |||
3017 | offset := PROG.getOffset(PARS.program, ident); |
||
3018 | |||
3019 | IF ident.global THEN |
||
3020 | CODE.AddCmd(CODE.opGADR, offset) |
||
3021 | ELSE |
||
3022 | CODE.AddCmd(CODE.opLADR, -offset) |
||
3023 | END; |
||
3024 | |||
3025 | IF e.obj = eCONST THEN |
||
3026 | CODE.AddCmd(CODE.opSAVEC, ARITH.Int(e.value)) |
||
3027 | ELSE |
||
3028 | CODE.AddCmd0(CODE.opSAVE) |
||
3029 | END; |
||
3030 | |||
3031 | CODE.SetLabel(L1); |
||
3032 | |||
3033 | IF ident.global THEN |
||
3034 | CODE.AddCmd(CODE.opGADR, offset) |
||
3035 | ELSE |
||
3036 | CODE.AddCmd(CODE.opLADR, -offset) |
||
3037 | END; |
||
3038 | CODE.load(ident.type.size); |
||
3039 | |||
3040 | PARS.checklex(parser, SCAN.lxTO); |
||
3041 | NextPos(parser, pos); |
||
3042 | expression(parser, e); |
||
3043 | PARS.check(isInt(e), parser, pos, 76); |
||
3044 | |||
3045 | IF parser.sym = SCAN.lxBY THEN |
||
3046 | NextPos(parser, pos); |
||
3047 | PARS.ConstExpression(parser, step); |
||
3048 | PARS.check(step.typ = ARITH.tINTEGER, parser, pos, 76); |
||
3049 | st := ARITH.getInt(step); |
||
3050 | PARS.check(st # 0, parser, pos, 98) |
||
3051 | ELSE |
||
3052 | st := 1 |
||
3053 | END; |
||
3054 | |||
3055 | IF e.obj = eCONST THEN |
||
3056 | IF st > 0 THEN |
||
3057 | CODE.AddCmd(CODE.opLER, ARITH.Int(e.value)) |
||
3058 | ELSE |
||
3059 | CODE.AddCmd(CODE.opGER, ARITH.Int(e.value)) |
||
3060 | END |
||
3061 | ELSE |
||
3062 | IF st > 0 THEN |
||
3063 | CODE.AddCmd0(CODE.opLE) |
||
3064 | ELSE |
||
3065 | CODE.AddCmd0(CODE.opGE) |
||
3066 | END |
||
3067 | END; |
||
3068 | |||
3069 | CODE.AddJmpCmd(CODE.opJNE, L2); |
||
3070 | |||
3071 | PARS.checklex(parser, SCAN.lxDO); |
||
3072 | PARS.Next(parser); |
||
3073 | parser.StatSeq(parser); |
||
3074 | |||
3075 | IF ident.global THEN |
||
3076 | CODE.AddCmd(CODE.opGADR, offset) |
||
3077 | ELSE |
||
3078 | CODE.AddCmd(CODE.opLADR, -offset) |
||
3079 | END; |
||
3080 | |||
3081 | IF st = 1 THEN |
||
3082 | CODE.AddCmd0(CODE.opINC1) |
||
3083 | ELSIF st = -1 THEN |
||
3084 | CODE.AddCmd0(CODE.opDEC1) |
||
3085 | ELSE |
||
3086 | IF st > 0 THEN |
||
3087 | CODE.AddCmd(CODE.opINCC, st) |
||
3088 | ELSE |
||
3089 | CODE.AddCmd(CODE.opDECC, -st) |
||
3090 | END |
||
3091 | END; |
||
3092 | |||
3093 | CODE.AddJmpCmd(CODE.opJMP, L1); |
||
3094 | |||
3095 | PARS.checklex(parser, SCAN.lxEND); |
||
3096 | PARS.Next(parser); |
||
3097 | |||
3098 | CODE.SetLabel(L2); |
||
3099 | |||
3100 | CODE.AddCmd0(CODE.opENDLOOP) |
||
3101 | |||
3102 | END ForStatement; |
||
3103 | |||
3104 | |||
3105 | PROCEDURE statement (parser: PARS.PARSER); |
||
3106 | VAR |
||
3107 | sym: INTEGER; |
||
3108 | |||
3109 | BEGIN |
||
3110 | sym := parser.sym; |
||
3111 | |||
3112 | IF sym = SCAN.lxIDENT THEN |
||
3113 | ElementaryStatement(parser) |
||
3114 | ELSIF sym = SCAN.lxIF THEN |
||
3115 | IfStatement(parser, TRUE) |
||
3116 | ELSIF sym = SCAN.lxWHILE THEN |
||
3117 | IfStatement(parser, FALSE) |
||
3118 | ELSIF sym = SCAN.lxREPEAT THEN |
||
3119 | RepeatStatement(parser) |
||
3120 | ELSIF sym = SCAN.lxCASE THEN |
||
3121 | CaseStatement(parser) |
||
3122 | ELSIF sym = SCAN.lxFOR THEN |
||
3123 | ForStatement(parser) |
||
3124 | END |
||
3125 | END statement; |
||
3126 | |||
3127 | |||
3128 | PROCEDURE StatSeq (parser: PARS.PARSER); |
||
3129 | BEGIN |
||
3130 | statement(parser); |
||
3131 | WHILE parser.sym = SCAN.lxSEMI DO |
||
3132 | PARS.Next(parser); |
||
3133 | statement(parser) |
||
3134 | END |
||
3135 | END StatSeq; |
||
3136 | |||
3137 | |||
3138 | PROCEDURE chkreturn (parser: PARS.PARSER; e: PARS.EXPR; t: PROG.TYPE_; pos: SCAN.POSITION): BOOLEAN; |
||
3139 | VAR |
||
3140 | res: BOOLEAN; |
||
3141 | |||
3142 | BEGIN |
||
3143 | res := assigncomp(e, t); |
||
3144 | IF res THEN |
||
3145 | IF e.obj = eCONST THEN |
||
3146 | IF e.type.typ = PROG.tREAL THEN |
||
3147 | CODE.Float(ARITH.Float(e.value)) |
||
3148 | ELSIF e.type.typ = PROG.tNIL THEN |
||
3149 | CODE.AddCmd(CODE.opCONST, 0) |
||
3150 | ELSE |
||
3151 | LoadConst(e) |
||
3152 | END |
||
3153 | ELSIF (e.type.typ = PROG.tINTEGER) & (t.typ = PROG.tBYTE) & (chkBYTE IN checking) THEN |
||
3154 | CheckRange(256, pos.line, errBYTE) |
||
3155 | ELSIF e.obj = ePROC THEN |
||
3156 | PARS.check(e.ident.global, parser, pos, 85); |
||
3157 | CODE.PushProc(e.ident.proc.label) |
||
3158 | ELSIF e.obj = eIMP THEN |
||
3159 | CODE.PushImpProc(e.ident.import) |
||
3160 | END; |
||
3161 | |||
3162 | IF e.type.typ = PROG.tREAL THEN |
||
3163 | CODE.retf |
||
3164 | END |
||
3165 | END |
||
3166 | |||
3167 | RETURN res |
||
3168 | END chkreturn; |
||
3169 | |||
3170 | |||
3171 | PROCEDURE setrtl; |
||
3172 | VAR |
||
3173 | rtl: PROG.UNIT; |
||
3174 | |||
3175 | |||
3176 | PROCEDURE getproc (rtl: PROG.UNIT; name: SCAN.LEXSTR; idx: INTEGER); |
||
3177 | VAR |
||
3178 | id: PROG.IDENT; |
||
3179 | |||
3180 | BEGIN |
||
3181 | id := rtl.idents.get(rtl, SCAN.enterid(name), FALSE); |
||
3182 | |||
3183 | IF (id # NIL) & (id.import # NIL) THEN |
||
3184 | CODE.codes.rtl[idx] := -id.import(CODE.IMPORT_PROC).label; |
||
3185 | id.proc.used := TRUE |
||
3186 | ELSIF (id # NIL) & (id.proc # NIL) THEN |
||
3187 | CODE.codes.rtl[idx] := id.proc.label; |
||
3188 | id.proc.used := TRUE |
||
3189 | ELSE |
||
3190 | ERRORS.error5("procedure ", mConst.RTL_NAME, ".", name, " not found") |
||
3191 | END |
||
3192 | END getproc; |
||
3193 | |||
3194 | |||
3195 | BEGIN |
||
3196 | rtl := PARS.program.rtl; |
||
3197 | ASSERT(rtl # NIL); |
||
3198 | |||
3199 | getproc(rtl, "_move", CODE._move); |
||
3200 | getproc(rtl, "_move2", CODE._move2); |
||
3201 | getproc(rtl, "_set", CODE._set); |
||
3202 | getproc(rtl, "_set2", CODE._set2); |
||
3203 | getproc(rtl, "_div", CODE._div); |
||
3204 | getproc(rtl, "_mod", CODE._mod); |
||
3205 | getproc(rtl, "_div2", CODE._div2); |
||
3206 | getproc(rtl, "_mod2", CODE._mod2); |
||
3207 | getproc(rtl, "_arrcpy", CODE._arrcpy); |
||
3208 | getproc(rtl, "_rot", CODE._rot); |
||
3209 | getproc(rtl, "_new", CODE._new); |
||
3210 | getproc(rtl, "_dispose", CODE._dispose); |
||
3211 | getproc(rtl, "_strcmp", CODE._strcmp); |
||
3212 | getproc(rtl, "_error", CODE._error); |
||
3213 | getproc(rtl, "_is", CODE._is); |
||
3214 | getproc(rtl, "_isrec", CODE._isrec); |
||
3215 | getproc(rtl, "_guard", CODE._guard); |
||
3216 | getproc(rtl, "_guardrec", CODE._guardrec); |
||
3217 | getproc(rtl, "_length", CODE._length); |
||
3218 | getproc(rtl, "_init", CODE._init); |
||
3219 | getproc(rtl, "_dllentry", CODE._dllentry); |
||
3220 | getproc(rtl, "_strcpy", CODE._strcpy); |
||
3221 | getproc(rtl, "_exit", CODE._exit); |
||
3222 | getproc(rtl, "_strcpy2", CODE._strcpy2); |
||
3223 | getproc(rtl, "_lengthw", CODE._lengthw); |
||
3224 | getproc(rtl, "_strcmp2", CODE._strcmp2); |
||
3225 | getproc(rtl, "_strcmpw", CODE._strcmpw); |
||
3226 | getproc(rtl, "_strcmpw2", CODE._strcmpw2); |
||
3227 | |||
3228 | END setrtl; |
||
3229 | |||
3230 | |||
3231 | PROCEDURE compile* (path, lib_path, modname, outname: PARS.PATH; target, version, stack, base: INTEGER; pic: BOOLEAN; chk: SET); |
||
3232 | VAR |
||
3233 | parser: PARS.PARSER; |
||
3234 | ext: PARS.PATH; |
||
3235 | amd64: BOOLEAN; |
||
3236 | |||
3237 | BEGIN |
||
3238 | amd64 := target IN {mConst.Target_iConsole64, mConst.Target_iGUI64, mConst.Target_iDLL64, mConst.Target_iELF64}; |
||
3239 | ext := mConst.FILE_EXT; |
||
3240 | CaseLabels := C.create(); |
||
3241 | CaseVar := C.create(); |
||
3242 | |||
3243 | CaseVariants := LISTS.create(NIL); |
||
3244 | LISTS.push(CaseVariants, NewVariant(0, NIL)); |
||
3245 | |||
3246 | checking := chk; |
||
3247 | |||
3248 | IF amd64 THEN |
||
3249 | CODE.init(6, CODE.little_endian) |
||
3250 | ELSE |
||
3251 | CODE.init(8, CODE.little_endian) |
||
3252 | END; |
||
3253 | |||
3254 | parser := PARS.create(path, lib_path, StatSeq, expression, designator, chkreturn); |
||
3255 | IF parser.open(parser, mConst.RTL_NAME) THEN |
||
3256 | parser.parse(parser); |
||
3257 | PARS.destroy(parser) |
||
3258 | ELSE |
||
3259 | PARS.destroy(parser); |
||
3260 | parser := PARS.create(lib_path, lib_path, StatSeq, expression, designator, chkreturn); |
||
3261 | IF parser.open(parser, mConst.RTL_NAME) THEN |
||
3262 | parser.parse(parser); |
||
3263 | PARS.destroy(parser) |
||
3264 | ELSE |
||
3265 | ERRORS.error5("file ", lib_path, mConst.RTL_NAME, mConst.FILE_EXT, " not found") |
||
3266 | END |
||
3267 | END; |
||
3268 | |||
3269 | parser := PARS.create(path, lib_path, StatSeq, expression, designator, chkreturn); |
||
3270 | parser.main := TRUE; |
||
3271 | |||
3272 | IF parser.open(parser, modname) THEN |
||
3273 | parser.parse(parser) |
||
3274 | ELSE |
||
3275 | ERRORS.error5("file ", path, modname, mConst.FILE_EXT, " not found") |
||
3276 | END; |
||
3277 | |||
3278 | PARS.destroy(parser); |
||
3279 | |||
3280 | IF PARS.program.bss > mConst.MAX_GLOBAL_SIZE THEN |
||
3281 | ERRORS.error1("size of global variables is too large") |
||
3282 | END; |
||
3283 | |||
3284 | setrtl; |
||
3285 | |||
3286 | PROG.DelUnused(PARS.program, CODE.DelImport); |
||
3287 | |||
3288 | CODE.codes.bss := PARS.program.bss; |
||
3289 | IF amd64 THEN |
||
3290 | AMD64.CodeGen(CODE.codes, outname, target, stack, base) |
||
3291 | ELSE |
||
3292 | X86.CodeGen(CODE.codes, outname, target, stack, base, version, pic) |
||
3293 | END |
||
3294 | END compile; |
||
3295 | |||
3296 | |||
3297 | END STATEMENTS.=>>>=" |