CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutSign UpSign In

Real-time collaboration for Jupyter Notebooks, Linux Terminals, LaTeX, VS Code, R IDE, and more,
all in one place.

| Download

GAP 4.8.9 installation with standard packages -- copy to your CoCalc project to get it

Path: gap4r8 / src / code.c
Views: 418346
1
/****************************************************************************
2
**
3
*W code.c GAP source Martin Schönert
4
**
5
**
6
*Y Copyright (C) 1996, Lehrstuhl D für Mathematik, RWTH Aachen, Germany
7
*Y (C) 1998 School Math and Comp. Sci., University of St Andrews, Scotland
8
*Y Copyright (C) 2002 The GAP Group
9
**
10
** This file contains the functions of the coder package.
11
**
12
** The coder package is the part of the interpreter that creates the
13
** expressions. Its functions are called from the reader.
14
*/
15
#include <stdio.h> /* on SunOS, assert.h uses stderr
16
but does not include stdio.h */
17
#include <assert.h> /* assert */
18
#include "system.h" /* Ints, UInts */
19
20
21
#include "gasman.h" /* garbage collector */
22
#include "objects.h" /* objects */
23
#include "scanner.h" /* scanner */
24
25
#include "gap.h" /* error handling, initialisation */
26
27
#include "calls.h" /* generic call mechanism */
28
/*N 1996/06/16 mschoene func expressions should be different from funcs */
29
30
#include "records.h" /* generic records */
31
32
#include "integer.h" /* integers */
33
34
#include "records.h" /* generic records */
35
#include "precord.h" /* plain records */
36
37
#include "lists.h" /* generic lists */
38
#include "plist.h" /* plain lists */
39
#include "string.h" /* strings */
40
41
#include "funcs.h" /* functions */
42
43
#include "code.h" /* coder */
44
45
#include "saveload.h" /* saving and loading */
46
#include "read.h" /* to access stack of for loop globals */
47
#include "gvars.h"
48
#include "thread.h" /* threads */
49
#include "tls.h" /* thread-local storage */
50
#include "aobjects.h" /* atomic objects */
51
52
#include "vars.h" /* variables */
53
54
55
#include "profile.h" /* access to stat register function*/
56
57
/****************************************************************************
58
**
59
60
*V PtrBody . . . . . . . . . . . . . . . . . . . . . pointer to current body
61
**
62
** 'PtrBody' is a pointer to the current body.
63
*/
64
Stat * PtrBody;
65
66
/****************************************************************************
67
**
68
69
*V FilenameCache . . . . . . . . . . . . . . . . . . list of filenames
70
**
71
** 'FilenameCache' is a list of previously opened filenames.
72
*/
73
Obj FilenameCache;
74
75
/****************************************************************************
76
**
77
*V OffsBody . . . . . . . . . . . . . . . . . . . . offset in current body
78
**
79
** 'OffsBody' is the offset in the current body. It is only valid while
80
** coding.
81
*/
82
#define MAX_FUNC_EXPR_NESTING 1024
83
84
85
Stat OffsBody;
86
87
Stat OffsBodyStack[MAX_FUNC_EXPR_NESTING];
88
UInt OffsBodyCount = 0;
89
90
UInt LoopNesting = 0;
91
UInt LoopStack[MAX_FUNC_EXPR_NESTING];
92
UInt LoopStackCount = 0;
93
94
static inline void PushOffsBody( void ) {
95
assert(TLS(OffsBodyCount) <= MAX_FUNC_EXPR_NESTING-1);
96
TLS(OffsBodyStack)[TLS(OffsBodyCount)++] = TLS(OffsBody);
97
}
98
99
static inline void PopOffsBody( void ) {
100
assert(TLS(OffsBodyCount));
101
TLS(OffsBody) = TLS(OffsBodyStack)[--TLS(OffsBodyCount)];
102
}
103
104
static inline void PushLoopNesting( void ) {
105
assert(TLS(LoopStackCount) <= MAX_FUNC_EXPR_NESTING-1);
106
TLS(LoopStack)[TLS(LoopStackCount)++] = TLS(LoopNesting);
107
}
108
109
static inline void PopLoopNesting( void ) {
110
assert(TLS(LoopStackCount));
111
TLS(LoopNesting) = TLS(LoopStack)[--TLS(LoopStackCount)];
112
}
113
114
static inline void setup_gapname(TypInputFile* i)
115
{
116
UInt len;
117
if(!i->gapname) {
118
C_NEW_STRING_DYN(i->gapname, i->name);
119
len = LEN_PLIST( FilenameCache );
120
GROW_PLIST( FilenameCache, len+1 );
121
SET_LEN_PLIST( FilenameCache, len+1 );
122
SET_ELM_PLIST( FilenameCache, len+1, i->gapname );
123
CHANGED_BAG( FilenameCache );
124
i->gapnameid = len+1;
125
}
126
}
127
128
Obj FILENAME_STAT(Stat stat)
129
{
130
Obj filename;
131
UInt filenameid = FILENAMEID_STAT(stat);
132
if (filenameid == 0)
133
filename = NEW_STRING(0);
134
else
135
filename = ELM_PLIST(FilenameCache, filenameid);
136
return filename;
137
}
138
139
140
/****************************************************************************
141
**
142
** Fill in filename and line of a statement, checking we do not overflow
143
** the space we have for storing information
144
*/
145
Stat fillFilenameLine(Int fileid, Int line, Int size, Int type)
146
{
147
Stat stat;
148
if(fileid < 0 || fileid >= (1 << 16))
149
{
150
fileid = (1 << 16) - 1;
151
RegisterProfilingFileOverflowOccured();
152
}
153
if(line < 0 || line >= (1 << 16))
154
{
155
line = (1 << 16) - 1;
156
RegisterProfilingLineOverflowOccured();
157
}
158
159
stat = ((Stat)fileid << 48) + ((Stat)line << 32) +
160
((Stat)size << 8) + (Stat)type;
161
162
return stat;
163
}
164
165
/****************************************************************************
166
**
167
*F NewStat( <type>, <size> ) . . . . . . . . . . . allocate a new statement
168
**
169
** 'NewStat' allocates a new statement memory block of type <type> and
170
** <size> bytes. 'NewStat' returns the identifier of the new statement.
171
**
172
** NewStat( <type>, <size>, <line> ) allows the line number of the statement
173
** to also be specified (else the current line when NewStat is called is
174
** used).
175
*/
176
Stat NewStatWithLine (
177
UInt type,
178
UInt size,
179
UInt line)
180
{
181
Stat stat; /* result */
182
183
/* this is where the new statement goes */
184
stat = TLS(OffsBody) + FIRST_STAT_CURR_FUNC;
185
186
/* increase the offset */
187
TLS(OffsBody) = stat + ((size+sizeof(Stat)-1) / sizeof(Stat)) * sizeof(Stat);
188
189
/* make certain that the current body bag is large enough */
190
if ( SIZE_BAG(BODY_FUNC(CURR_FUNC)) == 0 ) {
191
ResizeBag( BODY_FUNC(CURR_FUNC), TLS(OffsBody) + NUMBER_HEADER_ITEMS_BODY*sizeof(Obj) );
192
TLS(PtrBody) = (Stat*)PTR_BAG( BODY_FUNC(CURR_FUNC) );
193
}
194
while ( SIZE_BAG(BODY_FUNC(CURR_FUNC)) < TLS(OffsBody) + NUMBER_HEADER_ITEMS_BODY*sizeof(Obj) ) {
195
ResizeBag( BODY_FUNC(CURR_FUNC), 2*SIZE_BAG(BODY_FUNC(CURR_FUNC)) );
196
TLS(PtrBody) = (Stat*)PTR_BAG( BODY_FUNC(CURR_FUNC) );
197
}
198
setup_gapname(TLS(Input));
199
200
/* enter type and size */
201
ADDR_STAT(stat)[-1] = fillFilenameLine(TLS(Input)->gapnameid, line, size, type);
202
RegisterStatWithProfiling(stat);
203
/* return the new statement */
204
return stat;
205
}
206
207
Stat NewStat (
208
UInt type,
209
UInt size)
210
{
211
return NewStatWithLine(type, size, TLS(Input)->number);
212
}
213
214
215
/****************************************************************************
216
**
217
*F NewExpr( <type>, <size> ) . . . . . . . . . . . allocate a new expression
218
**
219
** 'NewExpr' allocates a new expression memory block of the type <type> and
220
** <size> bytes. 'NewExpr' returns the identifier of the new expression.
221
*/
222
Expr NewExpr (
223
UInt type,
224
UInt size )
225
{
226
Expr expr; /* result */
227
228
/* this is where the new expression goes */
229
expr = TLS(OffsBody) + FIRST_STAT_CURR_FUNC;
230
231
/* increase the offset */
232
TLS(OffsBody) = expr + ((size+sizeof(Expr)-1) / sizeof(Expr)) * sizeof(Expr);
233
234
/* make certain that the current body bag is large enough */
235
if ( SIZE_BAG(BODY_FUNC(CURR_FUNC)) == 0 ) {
236
ResizeBag( BODY_FUNC(CURR_FUNC), TLS(OffsBody) );
237
TLS(PtrBody) = (Stat*)PTR_BAG( BODY_FUNC(CURR_FUNC) );
238
}
239
while ( SIZE_BAG(BODY_FUNC(CURR_FUNC)) < TLS(OffsBody) ) {
240
ResizeBag( BODY_FUNC(CURR_FUNC), 2*SIZE_BAG(BODY_FUNC(CURR_FUNC)) );
241
TLS(PtrBody) = (Stat*)PTR_BAG( BODY_FUNC(CURR_FUNC) );
242
}
243
244
/* enter type and size */
245
ADDR_EXPR(expr)[-1] = fillFilenameLine(TLS(Input)->gapnameid,
246
TLS(Input)->number, size, type);
247
RegisterStatWithProfiling(expr);
248
/* return the new expression */
249
return expr;
250
}
251
252
253
/****************************************************************************
254
**
255
*V CodeResult . . . . . . . . . . . . . . . . . . . . . . result of coding
256
**
257
** 'CodeResult' is the result of the coding, i.e., the function that was
258
** coded.
259
*/
260
Obj CodeResult;
261
262
263
/****************************************************************************
264
**
265
*V StackStat . . . . . . . . . . . . . . . . . . . . . . . statements stack
266
*V CountStat . . . . . . . . . . . . . . . number of statements on the stack
267
*F PushStat( <stat> ) . . . . . . . . . . . . push statement onto the stack
268
*F PopStat() . . . . . . . . . . . . . . . . . pop statement from the stack
269
**
270
** 'StackStat' is the stack of statements that have been coded.
271
**
272
** 'CountStat' is the number of statements currently on the statements
273
** stack.
274
**
275
** 'PushStat' pushes the statement <stat> onto the statements stack. The
276
** stack is automatically resized if necessary.
277
**
278
** 'PopStat' returns the top statement from the statements stack and pops
279
** it. It is an error if the stack is empty.
280
*/
281
Bag StackStat;
282
283
Int CountStat;
284
285
void PushStat (
286
Stat stat )
287
{
288
/* there must be a stack, it must not be underfull or overfull */
289
assert( TLS(StackStat) != 0 );
290
assert( 0 <= TLS(CountStat) );
291
assert( TLS(CountStat) <= SIZE_BAG(TLS(StackStat))/sizeof(Stat) );
292
assert( stat != 0 );
293
294
/* count up and put the statement onto the stack */
295
if ( TLS(CountStat) == SIZE_BAG(TLS(StackStat))/sizeof(Stat) ) {
296
ResizeBag( TLS(StackStat), 2*TLS(CountStat)*sizeof(Stat) );
297
}
298
((Stat*)PTR_BAG(TLS(StackStat)))[TLS(CountStat)] = stat;
299
TLS(CountStat)++;
300
}
301
302
Stat PopStat ( void )
303
{
304
Stat stat;
305
306
/* there must be a stack, it must not be underfull/empty or overfull */
307
assert( TLS(StackStat) != 0 );
308
assert( 1 <= TLS(CountStat) );
309
assert( TLS(CountStat) <= SIZE_BAG(TLS(StackStat))/sizeof(Stat) );
310
311
/* get the top statement from the stack, and count down */
312
TLS(CountStat)--;
313
stat = ((Stat*)PTR_BAG(TLS(StackStat)))[TLS(CountStat)];
314
315
/* return the popped statement */
316
return stat;
317
}
318
319
Stat PopSeqStat (
320
UInt nr )
321
{
322
Stat body; /* sequence, result */
323
Stat stat; /* single statement */
324
UInt i; /* loop variable */
325
326
if (nr == 0 ) {
327
body = NewStat(T_EMPTY, 0);
328
}
329
/* special case for a single statement */
330
else if ( nr == 1 ) {
331
body = PopStat();
332
}
333
334
/* general case */
335
else {
336
337
/* allocate the sequence */
338
if ( 2 <= nr && nr <= 7 ) {
339
body = NewStat( T_SEQ_STAT+(nr-1), nr * sizeof(Stat) );
340
}
341
else {
342
body = NewStat( T_SEQ_STAT, nr * sizeof(Stat) );
343
}
344
345
/* enter the statements into the sequence */
346
for ( i = nr; 1 <= i; i-- ) {
347
stat = PopStat();
348
ADDR_STAT(body)[i-1] = stat;
349
}
350
}
351
352
/* return the sequence */
353
return body;
354
}
355
356
357
/****************************************************************************
358
**
359
*V StackExpr . . . . . . . . . . . . . . . . . . . . . . . expressions stack
360
*V CountExpr . . . . . . . . . . . . . . number of expressions on the stack
361
*F PushExpr( <expr> ) . . . . . . . . . . . push expression onto the stack
362
*F PopExpr() . . . . . . . . . . . . . . . . pop expression from the stack
363
**
364
** 'StackExpr' is the stack of expressions that have been coded.
365
**
366
** 'CountExpr' is the number of expressions currently on the expressions
367
** stack.
368
**
369
** 'PushExpr' pushes the expression <expr> onto the expressions stack. The
370
** stack is automatically resized if necessary.
371
**
372
** 'PopExpr' returns the top expressions from the expressions stack and pops
373
** it. It is an error if the stack is empty.
374
*/
375
Bag StackExpr;
376
377
Int CountExpr;
378
379
void PushExpr (
380
Expr expr )
381
{
382
/* there must be a stack, it must not be underfull or overfull */
383
assert( TLS(StackExpr) != 0 );
384
assert( 0 <= TLS(CountExpr) );
385
assert( TLS(CountExpr) <= SIZE_BAG(TLS(StackExpr))/sizeof(Expr) );
386
assert( expr != 0 );
387
388
/* count up and put the expression onto the stack */
389
if ( TLS(CountExpr) == SIZE_BAG(TLS(StackExpr))/sizeof(Expr) ) {
390
ResizeBag( TLS(StackExpr), 2*TLS(CountExpr)*sizeof(Expr) );
391
}
392
((Expr*)PTR_BAG(TLS(StackExpr)))[TLS(CountExpr)] = expr;
393
TLS(CountExpr)++;
394
}
395
396
Expr PopExpr ( void )
397
{
398
Expr expr;
399
400
/* there must be a stack, it must not be underfull/empty or overfull */
401
assert( TLS(StackExpr) != 0 );
402
assert( 1 <= TLS(CountExpr) );
403
assert( TLS(CountExpr) <= SIZE_BAG(TLS(StackExpr))/sizeof(Expr) );
404
405
/* get the top expression from the stack, and count down */
406
TLS(CountExpr)--;
407
expr = ((Expr*)PTR_BAG(TLS(StackExpr)))[TLS(CountExpr)];
408
409
/* return the popped expression */
410
return expr;
411
}
412
413
414
/****************************************************************************
415
**
416
*F PushUnaryOp( <type> ) . . . . . . . . . . . . . . . . push unary operator
417
**
418
** 'PushUnaryOp' pushes a unary operator expression onto the expression
419
** stack. <type> is the type of the operator (currently only 'T_NOT').
420
*/
421
void PushUnaryOp (
422
UInt type )
423
{
424
Expr unop; /* unary operator, result */
425
Expr op; /* operand */
426
427
/* allocate the unary operator */
428
unop = NewExpr( type, sizeof(Expr) );
429
430
/* enter the operand */
431
op = PopExpr();
432
ADDR_EXPR(unop)[0] = op;
433
434
/* push the unary operator */
435
PushExpr( unop );
436
}
437
438
439
/****************************************************************************
440
**
441
*F PushBinaryOp( <type> ) . . . . . . . . . . . . . . push binary operator
442
**
443
** 'PushBinaryOp' pushes a binary operator expression onto the expression
444
** stack. <type> is the type of the operator.
445
*/
446
void PushBinaryOp (
447
UInt type )
448
{
449
Expr binop; /* binary operator, result */
450
Expr opL; /* left operand */
451
Expr opR; /* right operand */
452
453
/* allocate the binary operator */
454
binop = NewExpr( type, 2*sizeof(Expr) );
455
456
/* enter the right operand */
457
opR = PopExpr();
458
ADDR_EXPR(binop)[1] = opR;
459
460
/* enter the left operand */
461
opL = PopExpr();
462
ADDR_EXPR(binop)[0] = opL;
463
464
/* push the binary operator */
465
PushExpr( binop );
466
}
467
468
469
/****************************************************************************
470
**
471
472
*F * * * * * * * * * * * * * coder functions * * * * * * * * * * * * * * * *
473
*/
474
475
/****************************************************************************
476
**
477
*F CodeFuncCallOptionsBegin() . . . . . . . . . . . . . code options, begin
478
*F CodeFuncCallOptionsBeginElmName(<rnam>). . . code options, begin element
479
*F CodeFuncCallOptionsBeginElmExpr() . .. . . . .code options, begin element
480
*F CodeFuncCallOptionsEndElm() . . .. . . . . . . code options, end element
481
*F CodeFuncCallOptionsEndElmEmpty() .. . . . . . .code options, end element
482
*F CodeFuncCallOptionsEnd(<nr>) . . . . . . . . . . . . . code options, end
483
**
484
** The net effect of all of these is to leave a record expression on the stack
485
** containing the options record. It will be picked up by
486
** CodeFuncCallEnd()
487
**
488
*/
489
void CodeFuncCallOptionsBegin ( void )
490
{
491
}
492
493
void CodeFuncCallOptionsBeginElmName (
494
UInt rnam )
495
{
496
/* push the record name as integer expressions */
497
PushExpr( INTEXPR_INT( rnam ) );
498
}
499
500
void CodeFuncCallOptionsBeginElmExpr ( void )
501
{
502
/* The expression is on the stack where we want it */
503
}
504
505
void CodeFuncCallOptionsEndElm ( void )
506
{
507
}
508
509
void CodeFuncCallOptionsEndElmEmpty ( void )
510
{
511
/* The default value is true */
512
PushExpr( NewExpr( T_TRUE_EXPR, 0L ) );
513
}
514
515
void CodeFuncCallOptionsEnd ( UInt nr )
516
{
517
Expr record; /* record, result */
518
Expr entry; /* entry */
519
Expr rnam; /* position of an entry */
520
UInt i; /* loop variable */
521
522
/* allocate the record expression */
523
record = NewExpr( T_REC_EXPR, nr * 2 * sizeof(Expr) );
524
525
526
/* enter the entries */
527
for ( i = nr; 1 <= i; i-- ) {
528
entry = PopExpr();
529
rnam = PopExpr();
530
ADDR_EXPR(record)[2*(i-1)] = rnam;
531
ADDR_EXPR(record)[2*(i-1)+1] = entry;
532
}
533
534
/* push the record */
535
PushExpr( record );
536
537
}
538
539
540
/****************************************************************************
541
**
542
543
*F CodeBegin() . . . . . . . . . . . . . . . . . . . . . . . start the coder
544
*F CodeEnd( <error> ) . . . . . . . . . . . . . . . . . . . stop the coder
545
**
546
** 'CodeBegin' starts the coder. It is called from the immediate
547
** interpreter when he encounters a construct that it cannot immediately
548
** interpret.
549
**
550
** 'CodeEnd' stops the coder. It is called from the immediate interpreter
551
** when he is done with the construct that it cannot immediately interpret.
552
** If <error> is non-zero, a syntax error was detected by the reader, and
553
** the coder should only clean up.
554
**
555
** ...only function expressions inbetween...
556
*/
557
Bag CodeLVars;
558
559
void CodeBegin ( void )
560
{
561
/* the stacks must be empty */
562
assert( TLS(CountStat) == 0 );
563
assert( TLS(CountExpr) == 0 );
564
565
/* remember the current frame */
566
TLS(CodeLVars) = TLS(CurrLVars);
567
568
/* clear the code result bag */
569
TLS(CodeResult) = 0;
570
}
571
572
UInt CodeEnd (
573
UInt error )
574
{
575
/* if everything went fine */
576
if ( ! error ) {
577
578
/* the stacks must be empty */
579
assert( TLS(CountStat) == 0 );
580
assert( TLS(CountExpr) == 0 );
581
582
/* we must be back to 'TLS(CurrLVars)' */
583
assert( TLS(CurrLVars) == TLS(CodeLVars) );
584
585
/* 'CodeFuncExprEnd' left the function already in 'TLS(CodeResult)' */
586
}
587
588
/* otherwise clean up the mess */
589
else {
590
591
/* empty the stacks */
592
TLS(CountStat) = 0;
593
TLS(CountExpr) = 0;
594
595
/* go back to the correct frame */
596
SWITCH_TO_OLD_LVARS( TLS(CodeLVars) );
597
}
598
599
/* return value is ignored */
600
return 0;
601
}
602
603
604
/****************************************************************************
605
**
606
*F CodeFuncCallBegin() . . . . . . . . . . . . . . code function call, begin
607
*F CodeFuncCallEnd( <funccall>, <options>, <nr> ) code function call, end
608
**
609
** 'CodeFuncCallBegin' is an action to code a function call. It is called
610
** by the reader when it encounters the parenthesis '(', i.e., *after* the
611
** function expression is read.
612
**
613
** 'CodeFuncCallEnd' is an action to code a function call. It is called by
614
** the reader when it encounters the parenthesis ')', i.e., *after* the
615
** argument expressions are read. <funccall> is 1 if this is a function
616
** call, and 0 if this is a procedure call. <nr> is the number of
617
** arguments. <options> is 1 if options were present after the ':' in which
618
** case the options have been read already.
619
*/
620
void CodeFuncCallBegin ( void )
621
{
622
}
623
624
void CodeFuncCallEnd (
625
UInt funccall,
626
UInt options,
627
UInt nr )
628
{
629
Expr call; /* function call, result */
630
Expr func; /* function expression */
631
Expr arg; /* one argument expression */
632
UInt i; /* loop variable */
633
Expr opts = 0; /* record literal for the options */
634
Expr wrapper; /* wrapper for calls with options */
635
636
/* allocate the function call */
637
if ( funccall && nr <= 6 ) {
638
call = NewExpr( T_FUNCCALL_0ARGS+nr, SIZE_NARG_CALL(nr) );
639
}
640
else if ( funccall /* && 6 < nr */ ) {
641
call = NewExpr( T_FUNCCALL_XARGS, SIZE_NARG_CALL(nr) );
642
}
643
else if ( /* ! funccall && */ nr <=6 ) {
644
call = NewExpr( T_PROCCALL_0ARGS+nr, SIZE_NARG_CALL(nr) );
645
}
646
else /* if ( ! funccall && 6 < nr ) */ {
647
call = NewExpr( T_PROCCALL_XARGS, SIZE_NARG_CALL(nr) );
648
}
649
650
/* get the options record if any */
651
if (options)
652
opts = PopExpr();
653
654
/* enter the argument expressions */
655
for ( i = nr; 1 <= i; i-- ) {
656
arg = PopExpr();
657
ARGI_CALL(call,i) = arg;
658
}
659
660
/* enter the function expression */
661
func = PopExpr();
662
FUNC_CALL(call) = func;
663
664
/* wrap up the call with the options */
665
if (options)
666
{
667
wrapper = NewExpr( funccall ? T_FUNCCALL_OPTS : T_PROCCALL_OPTS,
668
2*sizeof(Expr));
669
ADDR_EXPR(wrapper)[0] = opts;
670
ADDR_EXPR(wrapper)[1] = call;
671
call = wrapper;
672
}
673
674
/* push the function call */
675
if ( funccall ) {
676
PushExpr( call );
677
}
678
else {
679
PushStat( call );
680
}
681
}
682
683
684
/****************************************************************************
685
**
686
*F CodeFuncExprBegin( <narg>, <nloc>, <nams> ) . . code function expr, begin
687
*F CodeFuncExprEnd( <nr>, <mapsto> ) . . . . code function expression, end
688
**
689
** 'CodeFuncExprBegin' is an action to code a function expression. It is
690
** called when the reader encounters the beginning of a function expression.
691
** <narg> is the number of arguments (-1 if the function takes a variable
692
** number of arguments), <nloc> is the number of locals, <nams> is a list of
693
** local variable names.
694
**
695
** 'CodeFuncExprEnd' is an action to code a function expression. It is
696
** called when the reader encounters the end of a function expression. <nr>
697
** is the number of statements in the body of the function.
698
*/
699
void CodeFuncExprBegin (
700
Int narg,
701
Int nloc,
702
Obj nams,
703
Int startLine)
704
{
705
Obj fexp; /* function expression bag */
706
Obj fexs; /* function expressions list */
707
Bag body; /* function body */
708
Bag old; /* old frame */
709
Stat stat1; /* first statement in body */
710
711
/* remember the current offset */
712
PushOffsBody();
713
714
/* and the loop nesting depth */
715
PushLoopNesting();
716
717
/* create a function expression */
718
fexp = NewBag( T_FUNCTION, SIZE_FUNC );
719
NARG_FUNC( fexp ) = narg;
720
NLOC_FUNC( fexp ) = nloc;
721
NAMS_FUNC( fexp ) = nams;
722
CHANGED_BAG( fexp );
723
724
/* give it a functions expressions list */
725
fexs = NEW_PLIST( T_PLIST, 0 );
726
SET_LEN_PLIST( fexs, 0 );
727
FEXS_FUNC( fexp ) = fexs;
728
CHANGED_BAG( fexp );
729
730
/* give it a body */
731
body = NewBag( T_BODY, 1024*sizeof(Stat) );
732
BODY_FUNC( fexp ) = body;
733
CHANGED_BAG( fexp );
734
735
/* record where we are reading from */
736
setup_gapname(TLS(Input));
737
FILENAME_BODY(body) = TLS(Input)->gapname;
738
STARTLINE_BODY(body) = INTOBJ_INT(startLine);
739
/* Pr("Coding begin at %s:%d ",(Int)(TLS(Input)->name),TLS(Input)->number);
740
Pr(" Body id %d\n",(Int)(body),0L); */
741
TLS(OffsBody) = 0;
742
TLS(LoopNesting) = 0;
743
744
/* give it an environment */
745
ENVI_FUNC( fexp ) = TLS(CurrLVars);
746
CHANGED_BAG( fexp );
747
748
/* switch to this function */
749
SWITCH_TO_NEW_LVARS( fexp, (narg >0 ? narg : -narg), nloc, old );
750
(void) old; /* please picky compilers. */
751
752
/* allocate the top level statement sequence */
753
stat1 = NewStat( T_SEQ_STAT, 8*sizeof(Stat) );
754
assert( stat1 == FIRST_STAT_CURR_FUNC );
755
}
756
757
void CodeFuncExprEnd (
758
UInt nr,
759
UInt mapsto )
760
{
761
Expr expr; /* function expression, result */
762
Stat stat1; /* single statement of body */
763
Obj fexp; /* function expression bag */
764
Obj fexs; /* funct. expr. list of outer func */
765
UInt len; /* length of func. expr. list */
766
UInt i; /* loop variable */
767
768
/* get the function expression */
769
fexp = CURR_FUNC;
770
assert(!LoopNesting);
771
772
/* get the body of the function */
773
/* push an addition return-void-statement if neccessary */
774
/* the function interpreters depend on each function ``returning'' */
775
if ( nr == 0 ) {
776
CodeReturnVoid();
777
nr++;
778
}
779
else {
780
stat1 = PopStat();
781
PushStat( stat1 );
782
if ( TNUM_STAT(stat1) != T_RETURN_VOID
783
&& TNUM_STAT(stat1) != T_RETURN_OBJ )
784
{
785
CodeReturnVoid();
786
nr++;
787
}
788
}
789
790
/* if the body is a long sequence, pack the other statements */
791
if ( 7 < nr ) {
792
stat1 = PopSeqStat( nr-6 );
793
PushStat( stat1 );
794
nr = 7;
795
}
796
797
/* stuff the first statements into the first statement sequence */
798
/* Making sure to preserve the line number and file name */
799
ADDR_STAT(FIRST_STAT_CURR_FUNC)[-1]
800
= ((Stat)FILENAMEID_STAT(FIRST_STAT_CURR_FUNC) << 48) +
801
((Stat)LINE_STAT(FIRST_STAT_CURR_FUNC) << 32) +
802
((nr*sizeof(Stat)) << 8) + T_SEQ_STAT+nr-1;
803
for ( i = 1; i <= nr; i++ ) {
804
stat1 = PopStat();
805
ADDR_STAT(FIRST_STAT_CURR_FUNC)[nr-i] = stat1;
806
}
807
808
/* make the body smaller */
809
ResizeBag( BODY_FUNC(fexp), TLS(OffsBody)+NUMBER_HEADER_ITEMS_BODY*sizeof(Obj) );
810
ENDLINE_BODY(BODY_FUNC(fexp)) = INTOBJ_INT(TLS(Input)->number);
811
/* Pr(" finished coding %d at line %d\n",(Int)(BODY_FUNC(fexp)), TLS(Input)->number); */
812
813
/* switch back to the previous function */
814
SWITCH_TO_OLD_LVARS( ENVI_FUNC(fexp) );
815
816
/* restore loop nesting info */
817
PopLoopNesting();
818
819
/* restore the remembered offset */
820
PopOffsBody();
821
822
/* if this was inside another function definition, make the expression */
823
/* and store it in the function expression list of the outer function */
824
if ( TLS(CurrLVars) != TLS(CodeLVars) ) {
825
fexs = FEXS_FUNC( CURR_FUNC );
826
len = LEN_PLIST( fexs );
827
GROW_PLIST( fexs, len+1 );
828
SET_LEN_PLIST( fexs, len+1 );
829
SET_ELM_PLIST( fexs, len+1, fexp );
830
CHANGED_BAG( fexs );
831
expr = NewExpr( T_FUNC_EXPR, sizeof(Expr) );
832
ADDR_EXPR(expr)[0] = (Expr)(len+1);
833
PushExpr( expr );
834
}
835
836
/* otherwise, make the function and store it in 'TLS(CodeResult)' */
837
else {
838
TLS(CodeResult) = MakeFunction( fexp );
839
}
840
841
}
842
843
844
/****************************************************************************
845
**
846
*F CodeIfBegin() . . . . . . . . . . . code if-statement, begin of statement
847
*F CodeIfElif() . . . . . . . . . . code if-statement, begin of elif-branch
848
*F CodeIfElse() . . . . . . . . . . code if-statement, begin of else-branch
849
*F CodeIfBeginBody() . . . . . . . . . . . code if-statement, begin of body
850
*F CodeIfEndBody( <nr> ) . . . . . . . . . . code if-statement, end of body
851
*F CodeIfEnd( <nr> ) . . . . . . . . . . code if-statement, end of statement
852
**
853
** 'CodeIfBegin' is an action to code an if-statement. It is called when
854
** the reader encounters the 'if', i.e., *before* the condition is read.
855
**
856
** 'CodeIfElif' is an action to code an if-statement. It is called when the
857
** reader encounters an 'elif', i.e., *before* the condition is read.
858
**
859
** 'CodeIfElse' is an action to code an if-statement. It is called when the
860
** reader encounters an 'else'.
861
**
862
** 'CodeIfBeginBody' is an action to code an if-statement. It is called
863
** when the reader encounters the beginning of the statement body of an
864
** 'if', 'elif', or 'else' branch, i.e., *after* the condition is read.
865
**
866
** 'CodeIfEndBody' is an action to code an if-statement. It is called when
867
** the reader encounters the end of the statements body of an 'if', 'elif',
868
** or 'else' branch. <nr> is the number of statements in the body.
869
**
870
** 'CodeIfEnd' is an action to code an if-statement. It is called when the
871
** reader encounters the end of the statement. <nr> is the number of 'if',
872
** 'elif', or 'else' branches.
873
*/
874
void CodeIfBegin ( void )
875
{
876
}
877
878
void CodeIfElif ( void )
879
{
880
}
881
882
void CodeIfElse ( void )
883
{
884
CodeTrueExpr();
885
}
886
887
void CodeIfBeginBody ( void )
888
{
889
}
890
891
void CodeIfEndBody (
892
UInt nr )
893
{
894
/* collect the statements in a statement sequence if necessary */
895
PushStat( PopSeqStat( nr ) );
896
}
897
898
void CodeIfEnd (
899
UInt nr )
900
{
901
Stat stat; /* if-statement, result */
902
Expr cond; /* condition of a branch */
903
Stat body; /* body of a branch */
904
UInt hase; /* has else branch */
905
UInt i; /* loop variable */
906
907
/* peek at the last condition */
908
body = PopStat();
909
cond = PopExpr();
910
hase = (TNUM_EXPR(cond) == T_TRUE_EXPR);
911
PushExpr( cond );
912
PushStat( body );
913
914
/* allocate the if-statement */
915
if ( nr == 1 ) {
916
stat = NewStat( T_IF, nr * (sizeof(Expr)+sizeof(Stat)) );
917
}
918
else if ( nr == 2 && hase ) {
919
stat = NewStat( T_IF_ELSE, nr * (sizeof(Expr)+sizeof(Stat)) );
920
}
921
else if ( ! hase ) {
922
stat = NewStat( T_IF_ELIF, nr * (sizeof(Expr)+sizeof(Stat)) );
923
}
924
else {
925
stat = NewStat( T_IF_ELIF_ELSE, nr * (sizeof(Expr)+sizeof(Stat)) );
926
}
927
928
/* enter the branches */
929
for ( i = nr; 1 <= i; i-- ) {
930
body = PopStat();
931
cond = PopExpr();
932
ADDR_STAT(stat)[2*(i-1)] = cond;
933
ADDR_STAT(stat)[2*(i-1)+1] = body;
934
}
935
936
/* push the if-statement */
937
PushStat( stat );
938
}
939
940
941
/****************************************************************************
942
**
943
*F CodeForBegin() . . . . . . . . . code for-statement, begin of statement
944
*F CodeForIn() . . . . . . . . . . . . . . . . code for-statement, 'in' read
945
*F CodeForBeginBody() . . . . . . . . . . code for-statement, begin of body
946
*F CodeForEndBody( <nr> ) . . . . . . . . . code for-statement, end of body
947
*F CodeForEnd() . . . . . . . . . . . code for-statement, end of statement
948
**
949
** 'CodeForBegin' is an action to code a for-statement. It is called when
950
** the reader encounters the 'for', i.e., *before* the variable is read.
951
**
952
** 'CodeForIn' is an action to code a for-statement. It is called when the
953
** reader encounters the 'in', i.e., *after* the variable is read, but
954
** *before* the list expression is read.
955
**
956
** 'CodeForBeginBody' is an action to code a for-statement. It is called
957
** when the reader encounters the beginning of the statement body, i.e.,
958
** *after* the list expression is read.
959
**
960
** 'CodeForEndBody' is an action to code a for-statement. It is called when
961
** the reader encounters the end of the statement body. <nr> is the number
962
** of statements in the body.
963
**
964
** 'CodeForEnd' is an action to code a for-statement. It is called when the
965
** reader encounters the end of the statement, i.e., immediately after
966
** 'CodeForEndBody'.
967
*/
968
void CodeForBegin ( void )
969
{
970
}
971
972
void CodeForIn ( void )
973
{
974
Expr var = PopExpr();
975
if (TNUM_EXPR(var) == T_REF_GVAR)
976
{
977
PushGlobalForLoopVariable((UInt)ADDR_EXPR(var)[0]);
978
}
979
PushExpr(var);
980
}
981
982
void CodeForBeginBody ( void )
983
{
984
TLS(LoopNesting)++;
985
}
986
987
void CodeForEndBody (
988
UInt nr )
989
{
990
Stat stat; /* for-statement, result */
991
UInt type; /* type of for-statement */
992
Expr var; /* variable */
993
Expr list; /* list */
994
Stat stat1; /* single statement of body */
995
UInt i; /* loop variable */
996
997
/* fix up the case of no statements */
998
if ( 0 == nr ) {
999
PushStat( NewStat( T_EMPTY, 0) );
1000
nr = 1;
1001
}
1002
1003
/* collect the statements into a statement sequence if necessary */
1004
if ( 3 < nr ) {
1005
PushStat( PopSeqStat( nr ) );
1006
nr = 1;
1007
}
1008
1009
/* get the list expression */
1010
list = PopExpr();
1011
1012
/* get the variable reference */
1013
var = PopExpr();
1014
1015
if (TNUM_EXPR(var) == T_REF_GVAR)
1016
PopGlobalForLoopVariable();
1017
1018
/* select the type of the for-statement */
1019
if ( TNUM_EXPR(list) == T_RANGE_EXPR && SIZE_EXPR(list) == 2*sizeof(Expr)
1020
&& TNUM_EXPR(var) == T_REFLVAR ) {
1021
type = T_FOR_RANGE + (nr-1);
1022
}
1023
else {
1024
type = T_FOR + (nr-1);
1025
}
1026
1027
/* allocate the for-statement */
1028
stat = NewStat( type, 2*sizeof(Expr) + nr * sizeof(Stat) );
1029
1030
/* enter the body statements */
1031
for ( i = nr; 1 <= i; i-- ) {
1032
stat1 = PopStat();
1033
ADDR_STAT(stat)[i+1] = stat1;
1034
}
1035
1036
/* enter the list expression */
1037
ADDR_STAT(stat)[1] = list;
1038
1039
/* enter the variable reference */
1040
ADDR_STAT(stat)[0] = var;
1041
1042
/* push the for-statement */
1043
PushStat( stat );
1044
1045
/* decrement loop nesting count */
1046
TLS(LoopNesting)--;
1047
}
1048
1049
void CodeForEnd ( void )
1050
{
1051
}
1052
1053
1054
/****************************************************************************
1055
**
1056
*F CodeAtomicBegin() . . . . . . . code atomic-statement, begin of statement
1057
*F CodeAtomicBeginBody() . . . . . . . . code atomic-statement, begin of body
1058
*F CodeAtomicEndBody( <nr> ) . . . . . . . code atomic-statement, end of body
1059
*F CodeAtomicEnd() . . . . . . . . . code atomic-statement, end of statement
1060
**
1061
** 'CodeAtomicBegin' is an action to code a atomic-statement. It is called
1062
** when the reader encounters the 'atomic', i.e., *before* the condition is
1063
** read.
1064
**
1065
** 'CodeAtomicBeginBody' is an action to code a atomic-statement. It is
1066
** called when the reader encounters the beginning of the statement body,
1067
** i.e., *after* the condition is read.
1068
**
1069
** 'CodeAtomicEndBody' is an action to code a atomic-statement. It is called
1070
** when the reader encounters the end of the statement body. <nr> is the
1071
** number of statements in the body.
1072
**
1073
** 'CodeAtomicEnd' is an action to code a atomic-statement. It is called when
1074
** the reader encounters the end of the statement, i.e., immediate after
1075
** 'CodeAtomicEndBody'.
1076
**
1077
** These functions are just placeholders for the future HPC-GAP code.
1078
*/
1079
1080
void CodeAtomicBegin ( void )
1081
{
1082
}
1083
1084
void CodeAtomicBeginBody ( UInt nrexprs )
1085
{
1086
PushExpr(INTEXPR_INT(nrexprs));
1087
return;
1088
}
1089
1090
void CodeAtomicEndBody (
1091
UInt nrstats )
1092
{
1093
Stat stat; /* atomic-statement, result */
1094
Stat stat1; /* single statement of body */
1095
UInt i; /* loop variable */
1096
UInt nrexprs;
1097
Expr e,qual;
1098
1099
1100
/* fix up the case of no statements */
1101
if ( 0 == nrstats ) {
1102
PushStat( NewStat( T_EMPTY, 0) );
1103
nrstats = 1;
1104
}
1105
1106
/* collect the statements into a statement sequence */
1107
if ( 1 < nrstats ) {
1108
stat1 = PopSeqStat( nrstats );
1109
} else {
1110
stat1 = PopStat();
1111
}
1112
nrexprs = INT_INTEXPR(PopExpr());
1113
1114
/* allocate the atomic-statement */
1115
stat = NewStat( T_ATOMIC, sizeof(Stat) + nrexprs*2*sizeof(Stat) );
1116
1117
1118
/* enter the statement sequence */
1119
ADDR_STAT(stat)[0] = stat1;
1120
1121
1122
/* enter the expressions */
1123
for ( i = 2*nrexprs; 1 <= i; i -= 2 ) {
1124
e = PopExpr();
1125
qual = PopExpr();
1126
ADDR_STAT(stat)[i] = e;
1127
ADDR_STAT(stat)[i-1] = qual;
1128
}
1129
1130
1131
/* push the atomic-statement */
1132
PushStat( stat );
1133
}
1134
1135
void CodeAtomicEnd ( void )
1136
{
1137
}
1138
1139
/****************************************************************************
1140
**
1141
*F CodeQualifiedExprBegin() . . . code readonly/readwrite expression start
1142
*F CodeQualifiedExprEnd() . . . . . code readonly/readwrite expression end
1143
**
1144
** These functions code the beginning and end of the readonly/readwrite
1145
** qualified expressions of an atomic statement.
1146
*/
1147
1148
void CodeQualifiedExprBegin(UInt qual)
1149
{
1150
PushExpr(INTEXPR_INT(qual));
1151
}
1152
1153
void CodeQualifiedExprEnd()
1154
{
1155
}
1156
1157
1158
1159
1160
/****************************************************************************
1161
**
1162
*F CodeWhileBegin() . . . . . . . code while-statement, begin of statement
1163
*F CodeWhileBeginBody() . . . . . . . . code while-statement, begin of body
1164
*F CodeWhileEndBody( <nr> ) . . . . . . . code while-statement, end of body
1165
*F CodeWhileEnd() . . . . . . . . . code while-statement, end of statement
1166
**
1167
** 'CodeWhileBegin' is an action to code a while-statement. It is called
1168
** when the reader encounters the 'while', i.e., *before* the condition is
1169
** read.
1170
**
1171
** 'CodeWhileBeginBody' is an action to code a while-statement. It is
1172
** called when the reader encounters the beginning of the statement body,
1173
** i.e., *after* the condition is read.
1174
**
1175
** 'CodeWhileEndBody' is an action to code a while-statement. It is called
1176
** when the reader encounters the end of the statement body. <nr> is the
1177
** number of statements in the body.
1178
**
1179
** 'CodeWhileEnd' is an action to code a while-statement. It is called when
1180
** the reader encounters the end of the statement, i.e., immediate after
1181
** 'CodeWhileEndBody'.
1182
*/
1183
void CodeWhileBegin ( void )
1184
{
1185
}
1186
1187
void CodeWhileBeginBody ( void )
1188
{
1189
TLS(LoopNesting)++;
1190
}
1191
1192
void CodeWhileEndBody (
1193
UInt nr )
1194
{
1195
Stat stat; /* while-statement, result */
1196
Expr cond; /* condition */
1197
Stat stat1; /* single statement of body */
1198
UInt i; /* loop variable */
1199
1200
1201
/* fix up the case of no statements */
1202
if ( 0 == nr ) {
1203
PushStat( NewStat( T_EMPTY, 0) );
1204
nr = 1;
1205
}
1206
1207
/* collect the statements into a statement sequence if necessary */
1208
if ( 3 < nr ) {
1209
PushStat( PopSeqStat( nr ) );
1210
nr = 1;
1211
}
1212
1213
/* allocate the while-statement */
1214
stat = NewStat( T_WHILE + (nr-1), sizeof(Expr) + nr * sizeof(Stat) );
1215
1216
/* enter the statements */
1217
for ( i = nr; 1 <= i; i-- ) {
1218
stat1 = PopStat();
1219
ADDR_STAT(stat)[i] = stat1;
1220
}
1221
1222
/* enter the condition */
1223
cond = PopExpr();
1224
ADDR_STAT(stat)[0] = cond;
1225
1226
/* decrmement loop nesting */
1227
TLS(LoopNesting)--;
1228
1229
/* push the while-statement */
1230
PushStat( stat );
1231
}
1232
1233
void CodeWhileEnd ( void )
1234
{
1235
}
1236
1237
1238
/****************************************************************************
1239
**
1240
*F CodeRepeatBegin() . . . . . . . code repeat-statement, begin of statement
1241
*F CodeRepeatBeginBody() . . . . . . . code repeat-statement, begin of body
1242
*F CodeRepeatEndBody( <nr> ) . . . . . . code repeat-statement, end of body
1243
*F CodeRepeatEnd() . . . . . . . . . code repeat-statement, end of statement
1244
**
1245
** 'CodeRepeatBegin' is an action to code a repeat-statement. It is called
1246
** when the reader encounters the 'repeat'.
1247
**
1248
** 'CodeRepeatBeginBody' is an action to code a repeat-statement. It is
1249
** called when the reader encounters the beginning of the statement body,
1250
** i.e., immediately after 'CodeRepeatBegin'.
1251
**
1252
** 'CodeRepeatEndBody' is an action to code a repeat-statement. It is
1253
** called when the reader encounters the end of the statement body, i.e.,
1254
** *before* the condition is read. <nr> is the number of statements in the
1255
** body.
1256
**
1257
** 'CodeRepeatEnd' is an action to code a repeat-statement. It is called
1258
** when the reader encounters the end of the statement, i.e., *after* the
1259
** condition is read.
1260
*/
1261
void CodeRepeatBegin ( void )
1262
{
1263
}
1264
1265
void CodeRepeatBeginBody ( void )
1266
{
1267
TLS(LoopNesting)++;
1268
}
1269
1270
void CodeRepeatEndBody (
1271
UInt nr )
1272
{
1273
/* leave the number of statements in the body on the expression stack */
1274
PushExpr( INTEXPR_INT(nr) );
1275
TLS(LoopNesting)--;
1276
}
1277
1278
void CodeRepeatEnd ( void )
1279
{
1280
Stat stat; /* repeat-statement, result */
1281
UInt nr; /* number of statements in body */
1282
Expr cond; /* condition */
1283
Stat stat1; /* single statement of body */
1284
Expr tmp; /* temporary */
1285
UInt i; /* loop variable */
1286
1287
/* get the condition */
1288
cond = PopExpr();
1289
1290
/* get the number of statements in the body */
1291
/* 'CodeUntil' left this number on the expression stack (hack) */
1292
tmp = PopExpr();
1293
nr = INT_INTEXPR( tmp );
1294
1295
/* fix up the case of no statements */
1296
if ( 0 == nr ) {
1297
PushStat( NewStat( T_EMPTY, 0) );
1298
nr = 1;
1299
}
1300
/* collect the statements into a statement sequence if necessary */
1301
if ( 3 < nr ) {
1302
PushStat( PopSeqStat( nr ) );
1303
nr = 1;
1304
}
1305
1306
/* allocate the repeat-statement */
1307
stat = NewStat( T_REPEAT + (nr-1), sizeof(Expr) + nr * sizeof(Stat) );
1308
1309
/* enter the condition */
1310
ADDR_STAT(stat)[0] = cond;
1311
1312
/* enter the statements */
1313
for ( i = nr; 1 <= i; i-- ) {
1314
stat1 = PopStat();
1315
ADDR_STAT(stat)[i] = stat1;
1316
}
1317
1318
/* push the repeat-statement */
1319
PushStat( stat );
1320
}
1321
1322
1323
/****************************************************************************
1324
**
1325
*F CodeBreak() . . . . . . . . . . . . . . . . . . . . code break-statement
1326
**
1327
** 'CodeBreak' is the action to code a break-statement. It is called when
1328
** the reader encounters a 'break;'.
1329
*/
1330
void CodeBreak ( void )
1331
{
1332
Stat stat; /* break-statement, result */
1333
1334
if (!TLS(LoopNesting))
1335
SyntaxError("break statement not enclosed in a loop");
1336
1337
/* allocate the break-statement */
1338
stat = NewStat( T_BREAK, 0 * sizeof(Expr) );
1339
1340
/* push the break-statement */
1341
PushStat( stat );
1342
}
1343
1344
/****************************************************************************
1345
**
1346
*F CodeContinue() . . . . . . . . . . . . . . . . . . . . code continue-statement
1347
**
1348
** 'CodeContinue' is the action to code a continue-statement. It is called when
1349
** the reader encounters a 'continue;'.
1350
*/
1351
void CodeContinue ( void )
1352
{
1353
Stat stat; /* continue-statement, result */
1354
1355
if (!TLS(LoopNesting))
1356
SyntaxError("continue statement not enclosed in a loop");
1357
1358
/* allocate the continue-statement */
1359
stat = NewStat( T_CONTINUE, 0 * sizeof(Expr) );
1360
1361
/* push the continue-statement */
1362
PushStat( stat );
1363
}
1364
1365
1366
/****************************************************************************
1367
**
1368
*F CodeReturnObj() . . . . . . . . . . . . . . . code return-value-statement
1369
**
1370
** 'CodeReturnObj' is the action to code a return-value-statement. It is
1371
** called when the reader encounters a 'return <expr>;', but *after* reading
1372
** the expression <expr>.
1373
*/
1374
void CodeReturnObj ( void )
1375
{
1376
Stat stat; /* return-statement, result */
1377
Expr expr; /* expression */
1378
1379
/* allocate the return-statement */
1380
stat = NewStat( T_RETURN_OBJ, sizeof(Expr) );
1381
1382
/* enter the expression */
1383
expr = PopExpr();
1384
ADDR_STAT(stat)[0] = expr;
1385
1386
/* push the return-statement */
1387
PushStat( stat );
1388
}
1389
1390
1391
/****************************************************************************
1392
**
1393
*F CodeReturnVoid() . . . . . . . . . . . . . . code return-void-statement
1394
**
1395
** 'CodeReturnVoid' is the action to code a return-void-statement. It is
1396
** called when the reader encounters a 'return;'.
1397
*/
1398
void CodeReturnVoid ( void )
1399
{
1400
Stat stat; /* return-statement, result */
1401
1402
/* allocate the return-statement */
1403
stat = NewStat( T_RETURN_VOID, 0 * sizeof(Expr) );
1404
1405
/* push the return-statement */
1406
PushStat( stat );
1407
}
1408
1409
1410
/****************************************************************************
1411
**
1412
*F CodeOr() . . . . . . . . . . . . . . . . . . . . . . code or-expression
1413
*F CodeAnd() . . . . . . . . . . . . . . . . . . . . . . code and-expression
1414
*F CodeNot() . . . . . . . . . . . . . . . . . . . . . . code not-expression
1415
*F CodeEq() . . . . . . . . . . . . . . . . . . . . . . . code =-expression
1416
*F CodeNe() . . . . . . . . . . . . . . . . . . . . . . code <>-expression
1417
*F CodeLt() . . . . . . . . . . . . . . . . . . . . . . . code <-expression
1418
*F CodeGe() . . . . . . . . . . . . . . . . . . . . . . code >=-expression
1419
*F CodeGt() . . . . . . . . . . . . . . . . . . . . . . . code >-expression
1420
*F CodeLe() . . . . . . . . . . . . . . . . . . . . . . code <=-expression
1421
*F CodeIn() . . . . . . . . . . . . . . . . . . . . . . code in-expression
1422
*F CodeSum() . . . . . . . . . . . . . . . . . . . . . . . code +-expression
1423
*F CodeAInv() . . . . . . . . . . . . . . . . . . . code unary --expression
1424
*F CodeDiff() . . . . . . . . . . . . . . . . . . . . . . code --expression
1425
*F CodeProd() . . . . . . . . . . . . . . . . . . . . . . code *-expression
1426
*F CodeInv() . . . . . . . . . . . . . . . . . . . . . . code ^-1-expression
1427
*F CodeQuo() . . . . . . . . . . . . . . . . . . . . . . . code /-expression
1428
*F CodeMod() . . . . . . . . . . . . . . . . . . . . . . code mod-expression
1429
*F CodePow() . . . . . . . . . . . . . . . . . . . . . . . code ^-expression
1430
**
1431
** 'CodeOr', 'CodeAnd', 'CodeNot', 'CodeEq', 'CodeNe', 'CodeGt', 'CodeGe',
1432
** 'CodeIn', 'CodeSum', 'CodeDiff', 'CodeProd', 'CodeQuo', 'CodeMod', and
1433
** 'CodePow' are the actions to code the respective operator expressions.
1434
** They are called by the reader *after* *both* operands are read.
1435
*/
1436
void CodeOrL ( void )
1437
{
1438
}
1439
1440
void CodeOr ( void )
1441
{
1442
PushBinaryOp( T_OR );
1443
}
1444
1445
void CodeAndL ( void )
1446
{
1447
}
1448
1449
void CodeAnd ( void )
1450
{
1451
PushBinaryOp( T_AND );
1452
}
1453
1454
void CodeNot ( void )
1455
{
1456
PushUnaryOp( T_NOT );
1457
}
1458
1459
void CodeEq ( void )
1460
{
1461
PushBinaryOp( T_EQ );
1462
}
1463
1464
void CodeNe ( void )
1465
{
1466
PushBinaryOp( T_NE );
1467
}
1468
1469
void CodeLt ( void )
1470
{
1471
PushBinaryOp( T_LT );
1472
}
1473
1474
void CodeGe ( void )
1475
{
1476
PushBinaryOp( T_GE );
1477
}
1478
1479
void CodeGt ( void )
1480
{
1481
PushBinaryOp( T_GT );
1482
}
1483
1484
void CodeLe ( void )
1485
{
1486
PushBinaryOp( T_LE );
1487
}
1488
1489
void CodeIn ( void )
1490
{
1491
PushBinaryOp( T_IN );
1492
}
1493
1494
void CodeSum ( void )
1495
{
1496
PushBinaryOp( T_SUM );
1497
}
1498
1499
void CodeAInv ( void )
1500
{
1501
Expr expr;
1502
Int i;
1503
1504
expr = PopExpr();
1505
if ( IS_INTEXPR(expr) && INT_INTEXPR(expr) != -(1L<<NR_SMALL_INT_BITS) ) {
1506
i = INT_INTEXPR(expr);
1507
PushExpr( INTEXPR_INT( -i ) );
1508
}
1509
else {
1510
PushExpr( expr );
1511
PushUnaryOp( T_AINV );
1512
}
1513
}
1514
1515
void CodeDiff ( void )
1516
{
1517
PushBinaryOp( T_DIFF );
1518
}
1519
1520
void CodeProd ( void )
1521
{
1522
PushBinaryOp( T_PROD );
1523
}
1524
1525
void CodeInv ( void )
1526
{
1527
PushUnaryOp( T_INV );
1528
}
1529
1530
void CodeQuo ( void )
1531
{
1532
PushBinaryOp( T_QUO );
1533
}
1534
1535
void CodeMod ( void )
1536
{
1537
PushBinaryOp( T_MOD );
1538
}
1539
1540
void CodePow ( void )
1541
{
1542
PushBinaryOp( T_POW );
1543
}
1544
1545
1546
/****************************************************************************
1547
**
1548
*F CodeIntExpr( <str> ) . . . . . . . . . . code literal integer expression
1549
**
1550
** 'CodeIntExpr' is the action to code a literal integer expression. <str>
1551
** is the integer as a (null terminated) C character string.
1552
*/
1553
void CodeIntExpr (
1554
Char * str )
1555
{
1556
Expr expr; /* expression, result */
1557
Obj val; /* value = <upp> * <pow> + <low> */
1558
Obj upp; /* upper part */
1559
Int pow; /* power */
1560
Int low; /* lower part */
1561
Int sign; /* is the integer negative */
1562
UInt i; /* loop variable */
1563
1564
/* get the signs, if any */
1565
sign = 1;
1566
i = 0;
1567
while ( str[i] == '-' ) {
1568
sign = - sign;
1569
i++;
1570
}
1571
1572
/* collect the digits in groups of 8 */
1573
low = 0;
1574
pow = 1;
1575
upp = INTOBJ_INT(0);
1576
while ( str[i] != '\0' ) {
1577
low = 10 * low + str[i] - '0';
1578
pow = 10 * pow;
1579
if ( pow == 100000000L ) {
1580
upp = SumInt( ProdInt( upp, INTOBJ_INT(pow) ),
1581
INTOBJ_INT(sign*low) );
1582
pow = 1;
1583
low = 0;
1584
}
1585
i++;
1586
}
1587
1588
/* compose the integer value (set <val> first to silence 'lint') */
1589
val = 0;
1590
if ( upp == INTOBJ_INT(0) ) {
1591
val = INTOBJ_INT(sign*low);
1592
}
1593
else if ( pow == 1 ) {
1594
val = upp;
1595
}
1596
else {
1597
val = SumInt( ProdInt( upp, INTOBJ_INT(pow) ),
1598
INTOBJ_INT(sign*low) );
1599
}
1600
1601
/* if it is small enough code it immediately */
1602
if ( IS_INTOBJ(val) ) {
1603
expr = INTEXPR_INT( INT_INTOBJ(val) );
1604
}
1605
1606
/* otherwise stuff the value into the values list */
1607
else {
1608
expr = NewExpr( T_INT_EXPR, sizeof(UInt) + SIZE_OBJ(val) );
1609
((UInt *)ADDR_EXPR(expr))[0] = (UInt)TNUM_OBJ(val);
1610
memcpy((void *)((UInt *)ADDR_EXPR(expr)+1), (void *)ADDR_OBJ(val), (size_t)SIZE_OBJ(val));
1611
}
1612
1613
/* push the expression */
1614
PushExpr( expr );
1615
}
1616
1617
/****************************************************************************
1618
**
1619
*F CodeLongIntExpr( <str> ) . . . code literal long integer expression
1620
**
1621
** 'CodeIntExpr' is the action to code a long literal integer
1622
** expression whose digits are stored in a string GAP object.
1623
*/
1624
void CodeLongIntExpr (
1625
Obj string )
1626
{
1627
Expr expr; /* expression, result */
1628
Obj val; /* value = <upp> * <pow> + <low> */
1629
Obj upp; /* upper part */
1630
Int pow; /* power */
1631
Int low; /* lower part */
1632
Int sign; /* is the integer negative */
1633
UInt i; /* loop variable */
1634
UChar * str;
1635
1636
/* get the signs, if any */
1637
str = CHARS_STRING(string);
1638
sign = 1;
1639
i = 0;
1640
while ( str[i] == '-' ) {
1641
sign = - sign;
1642
i++;
1643
}
1644
1645
/* collect the digits in groups of 8 */
1646
low = 0;
1647
pow = 1;
1648
upp = INTOBJ_INT(0);
1649
while ( str[i] != '\0' ) {
1650
low = 10 * low + str[i] - '0';
1651
pow = 10 * pow;
1652
if ( pow == 100000000L ) {
1653
upp = SumInt( ProdInt( upp, INTOBJ_INT(pow) ),
1654
INTOBJ_INT(sign*low) );
1655
str = CHARS_STRING(string);
1656
pow = 1;
1657
low = 0;
1658
}
1659
i++;
1660
}
1661
1662
/* compose the integer value (set <val> first to silence 'lint') */
1663
val = 0;
1664
if ( upp == INTOBJ_INT(0) ) {
1665
val = INTOBJ_INT(sign*low);
1666
}
1667
else if ( pow == 1 ) {
1668
val = upp;
1669
}
1670
else {
1671
val = SumInt( ProdInt( upp, INTOBJ_INT(pow) ),
1672
INTOBJ_INT(sign*low) );
1673
}
1674
1675
/* if it is small enough code it immediately */
1676
if ( IS_INTOBJ(val) ) {
1677
expr = INTEXPR_INT( INT_INTOBJ(val) );
1678
}
1679
1680
/* otherwise stuff the value into the values list */
1681
/* Need to fix this up for GMP integers */
1682
else {
1683
expr = NewExpr( T_INT_EXPR, sizeof(UInt) + SIZE_OBJ(val) );
1684
((UInt *)ADDR_EXPR(expr))[0] = (UInt)TNUM_OBJ(val);
1685
memcpy((void *)((UInt *)ADDR_EXPR(expr)+1), (void *)ADDR_OBJ(val), (size_t)SIZE_OBJ(val));
1686
}
1687
1688
/* push the expression */
1689
PushExpr( expr );
1690
}
1691
1692
/****************************************************************************
1693
**
1694
*F CodeTrueExpr() . . . . . . . . . . . . . . code literal true expression
1695
**
1696
** 'CodeTrueExpr' is the action to code a literal true expression.
1697
*/
1698
void CodeTrueExpr ( void )
1699
{
1700
PushExpr( NewExpr( T_TRUE_EXPR, 0L ) );
1701
}
1702
1703
1704
/****************************************************************************
1705
**
1706
*F CodeFalseExpr() . . . . . . . . . . . . . . code literal false expression
1707
**
1708
** 'CodeFalseExpr' is the action to code a literal false expression.
1709
*/
1710
void CodeFalseExpr ( void )
1711
{
1712
PushExpr( NewExpr( T_FALSE_EXPR, 0L ) );
1713
}
1714
1715
1716
/****************************************************************************
1717
**
1718
*F CodeCharExpr( <chr> ) . . . . . . . . code a literal character expression
1719
**
1720
** 'CodeCharExpr' is the action to code a literal character expression.
1721
** <chr> is the C character.
1722
*/
1723
void CodeCharExpr (
1724
Char chr )
1725
{
1726
Expr litr; /* literal expression, result */
1727
1728
/* allocate the character expression */
1729
litr = NewExpr( T_CHAR_EXPR, sizeof(UChar) );
1730
((UChar*)ADDR_EXPR(litr))[0] = chr;
1731
1732
/* push the literal expression */
1733
PushExpr( litr );
1734
}
1735
1736
1737
/****************************************************************************
1738
**
1739
*F CodePermCycle( <nrx>, <nrc> ) . . . . code literal permutation expression
1740
*F CodePerm( <nrc> ) . . . . . . . . . . code literal permutation expression
1741
**
1742
** 'CodePermCycle' is an action to code a literal permutation expression.
1743
** It is called when one cycles is read completely. <nrc> is the number of
1744
** elements in that cycle. <nrx> is the number of that cycles (i.e., 1 for
1745
** the first cycle, 2 for the second, and so on).
1746
**
1747
** 'CodePerm' is an action to code a literal permutation expression. It is
1748
** called when the permutation is read completely. <nrc> is the number of
1749
** cycles.
1750
*/
1751
void CodePermCycle (
1752
UInt nrx,
1753
UInt nrc )
1754
{
1755
Expr cycle; /* cycle, result */
1756
Expr entry; /* entry of cycle */
1757
UInt j; /* loop variable */
1758
1759
/* allocate the new cycle */
1760
cycle = NewExpr( T_PERM_CYCLE, nrx * sizeof(Expr) );
1761
1762
/* enter the entries */
1763
for ( j = nrx; 1 <= j; j-- ) {
1764
entry = PopExpr();
1765
ADDR_EXPR(cycle)[j-1] = entry;
1766
}
1767
1768
/* push the cycle */
1769
PushExpr( cycle );
1770
}
1771
1772
void CodePerm (
1773
UInt nrc )
1774
{
1775
Expr perm; /* permutation, result */
1776
Expr cycle; /* cycle of permutation */
1777
UInt i; /* loop variable */
1778
1779
/* allocate the new permutation */
1780
perm = NewExpr( T_PERM_EXPR, nrc * sizeof(Expr) );
1781
1782
/* enter the cycles */
1783
for ( i = nrc; 1 <= i; i-- ) {
1784
cycle = PopExpr();
1785
ADDR_EXPR(perm)[i-1] = cycle;
1786
}
1787
1788
/* push the permutation */
1789
PushExpr( perm );
1790
1791
}
1792
1793
1794
/****************************************************************************
1795
**
1796
*F CodeListExprBegin( <top> ) . . . . . . . . . code list expression, begin
1797
*F CodeListExprBeginElm( <pos> ) . . . . code list expression, begin element
1798
*F CodeListExprEndElm() . . . . . . . .. code list expression, end element
1799
*F CodeListExprEnd( <nr>, <range>, <top>, <tilde> ) . . code list expr, end
1800
*/
1801
void CodeListExprBegin (
1802
UInt top )
1803
{
1804
}
1805
1806
void CodeListExprBeginElm (
1807
UInt pos )
1808
{
1809
/* push the literal integer value */
1810
PushExpr( INTEXPR_INT(pos) );
1811
}
1812
1813
void CodeListExprEndElm ( void )
1814
{
1815
}
1816
1817
void CodeListExprEnd (
1818
UInt nr,
1819
UInt range,
1820
UInt top,
1821
UInt tilde )
1822
{
1823
Expr list; /* list, result */
1824
Expr entry; /* entry */
1825
Expr pos; /* position of an entry */
1826
UInt i; /* loop variable */
1827
1828
/* peek at the last position (which is the largest) */
1829
if ( nr != 0 ) {
1830
entry = PopExpr();
1831
pos = PopExpr();
1832
PushExpr( pos );
1833
PushExpr( entry );
1834
}
1835
else {
1836
pos = INTEXPR_INT(0);
1837
}
1838
1839
/* allocate the list expression */
1840
if ( ! range && ! (top && tilde) ) {
1841
list = NewExpr( T_LIST_EXPR, INT_INTEXPR(pos) * sizeof(Expr) );
1842
}
1843
else if ( ! range && (top && tilde) ) {
1844
list = NewExpr( T_LIST_TILD_EXPR, INT_INTEXPR(pos) * sizeof(Expr) );
1845
}
1846
else /* if ( range && ! (top && tilde) ) */ {
1847
list = NewExpr( T_RANGE_EXPR, INT_INTEXPR(pos) * sizeof(Expr) );
1848
}
1849
1850
/* enter the entries */
1851
for ( i = nr; 1 <= i; i-- ) {
1852
entry = PopExpr();
1853
pos = PopExpr();
1854
ADDR_EXPR(list)[ INT_INTEXPR(pos)-1 ] = entry;
1855
}
1856
1857
/* push the list */
1858
PushExpr( list );
1859
}
1860
1861
1862
/****************************************************************************
1863
**
1864
*F CodeStringExpr( <str> ) . . . . . . . . code literal string expression
1865
*/
1866
void CodeStringExpr (
1867
Obj str )
1868
{
1869
Expr string; /* string, result */
1870
1871
/* allocate the string expression */
1872
string = NewExpr( T_STRING_EXPR, SIZEBAG_STRINGLEN(GET_LEN_STRING(str)) );
1873
1874
/* copy the string */
1875
memcpy( (void *)ADDR_EXPR(string), ADDR_OBJ(str),
1876
SIZEBAG_STRINGLEN(GET_LEN_STRING(str)) );
1877
1878
/* push the string */
1879
PushExpr( string );
1880
}
1881
1882
/****************************************************************************
1883
**
1884
*F CodeFloatExpr( <str> ) . . . . . . . . code literal float expression
1885
*/
1886
#define FLOAT_0_INDEX 1
1887
#define FLOAT_1_INDEX 2
1888
#define MAX_FLOAT_INDEX ((1L<<NR_SMALL_INT_BITS)-2)
1889
1890
static UInt GVAR_SAVED_FLOAT_INDEX;
1891
static UInt NextFloatExprNumber = 3;
1892
1893
static UInt NextEagerFloatLiteralNumber = 1;
1894
1895
static Obj EAGER_FLOAT_LITERAL_CACHE = 0;
1896
static Obj CONVERT_FLOAT_LITERAL_EAGER;
1897
1898
1899
static UInt getNextFloatExprNumber( void ) {
1900
UInt next;
1901
HashLock(&NextFloatExprNumber);
1902
if (NextFloatExprNumber > MAX_FLOAT_INDEX)
1903
next = 0;
1904
else {
1905
next = NextFloatExprNumber++;
1906
}
1907
HashUnlock(&NextFloatExprNumber);
1908
return next;
1909
}
1910
1911
static UInt CheckForCommonFloat(Char *str) {
1912
/* skip leading zeros */
1913
while (*str == '0')
1914
str++;
1915
if (*str == '.')
1916
/* might be zero literal */
1917
{
1918
/* skip point */
1919
str++;
1920
/* skip more zeroes */
1921
while (*str == '0')
1922
str++;
1923
/* if we've got to end of string we've got zero. */
1924
if (!IsDigit(*str))
1925
return FLOAT_0_INDEX;
1926
}
1927
if (*str++ !='1')
1928
return 0;
1929
/* might be one literal */
1930
if (*str++ != '.')
1931
return 0;
1932
/* skip zeros */
1933
while (*str == '0')
1934
str++;
1935
if (*str == '\0')
1936
return FLOAT_1_INDEX;
1937
if (IsDigit(*str))
1938
return 0;
1939
/* must now be an exponent character */
1940
assert(IsAlpha(*str));
1941
/* skip it */
1942
str++;
1943
/*skip + and - in exponent */
1944
if (*str == '+' || *str == '-')
1945
str++;
1946
/* skip leading zeros in the exponent */
1947
while (*str == '0')
1948
str++;
1949
/* if there's anything but leading zeros this isn't
1950
a one literal */
1951
if (*str == '\0')
1952
return FLOAT_1_INDEX;
1953
else
1954
return 0;
1955
}
1956
1957
static void CodeLazyFloatExpr( Char *str, UInt len) {
1958
UInt ix;
1959
1960
/* Lazy case, store the string for conversion at run time */
1961
Expr fl = NewExpr( T_FLOAT_EXPR_LAZY, 2*sizeof(UInt) +len+1 );
1962
/* copy the string */
1963
memcpy( (void *)((char *)ADDR_EXPR(fl)+2*sizeof(UInt)), (void *)str,
1964
len+1 );
1965
1966
*(UInt *)ADDR_EXPR(fl) = len;
1967
ix = CheckForCommonFloat(str);
1968
if (!ix)
1969
ix = getNextFloatExprNumber();
1970
((UInt *)ADDR_EXPR(fl))[1] = ix;
1971
1972
/* push the expression */
1973
PushExpr( fl );
1974
}
1975
1976
static void CodeEagerFloatExpr( Obj str, Char mark ) {
1977
/* Eager case, do the conversion now */
1978
UInt l = GET_LEN_STRING(str);
1979
Expr fl = NewExpr( T_FLOAT_EXPR_EAGER, sizeof(UInt)* 3 + l + 1);
1980
Obj v = CALL_2ARGS(CONVERT_FLOAT_LITERAL_EAGER, str, ObjsChar[(Int)mark]);
1981
assert(EAGER_FLOAT_LITERAL_CACHE);
1982
assert(IS_PLIST(EAGER_FLOAT_LITERAL_CACHE));
1983
GROW_PLIST(EAGER_FLOAT_LITERAL_CACHE, NextEagerFloatLiteralNumber);
1984
SET_ELM_PLIST(EAGER_FLOAT_LITERAL_CACHE, NextEagerFloatLiteralNumber, v);
1985
CHANGED_BAG(EAGER_FLOAT_LITERAL_CACHE);
1986
SET_LEN_PLIST(EAGER_FLOAT_LITERAL_CACHE, NextEagerFloatLiteralNumber);
1987
ADDR_EXPR(fl)[0] = NextEagerFloatLiteralNumber;
1988
ADDR_EXPR(fl)[1] = l;
1989
ADDR_EXPR(fl)[2] = (UInt)mark;
1990
memcpy((void*)(ADDR_EXPR(fl)+3), (void *)CHARS_STRING(str), l+1);
1991
NextEagerFloatLiteralNumber++;
1992
PushExpr(fl);
1993
}
1994
1995
void CodeFloatExpr (
1996
Char * str )
1997
{
1998
1999
UInt l = strlen(str);
2000
UInt l1 = l;
2001
Char mark = '\0'; /* initialize to please compilers */
2002
if (str[l-1] == '_' )
2003
{
2004
l1 = l-1;
2005
mark = '\0';
2006
}
2007
else if (str[l-2] == '_')
2008
{
2009
l1 = l-2;
2010
mark = str[l-1];
2011
}
2012
if (l1 < l)
2013
{
2014
Obj s;
2015
C_NEW_STRING(s, l1, str);
2016
CodeEagerFloatExpr(s,mark);
2017
} else {
2018
CodeLazyFloatExpr(str, l);
2019
}
2020
}
2021
2022
/****************************************************************************
2023
**
2024
*F CodeLongFloatExpr( <str> ) . . . . . . .code long literal float expression
2025
*/
2026
2027
void CodeLongFloatExpr (
2028
Obj str )
2029
{
2030
Char mark = '\0'; /* initialize to please compilers */
2031
2032
/* allocate the float expression */
2033
UInt l = GET_LEN_STRING(str);
2034
UInt l1 = l;
2035
if (CHARS_STRING(str)[l-1] == '_') {
2036
l1 = l-1;
2037
mark = '\0';
2038
} else if (CHARS_STRING(str)[l-2] == '_') {
2039
l1 = l-2;
2040
mark = CHARS_STRING(str)[l-1];
2041
}
2042
if (l1 < l) {
2043
CHARS_STRING(str)[l1] = '\0';
2044
SET_LEN_STRING(str,l1);
2045
CodeEagerFloatExpr(str, mark);
2046
} else {
2047
CodeLazyFloatExpr((Char *)CHARS_STRING(str), l);
2048
}
2049
2050
}
2051
2052
2053
/****************************************************************************
2054
**
2055
*F CodeRecExprBegin( <top> ) . . . . . . . . . . . . code record expr, begin
2056
*F CodeRecExprBeginElmName( <rnam> ) . . . . code record expr, begin element
2057
*F CodeRecExprBeginElmExpr() . . . . . . . . code record expr, begin element
2058
*F CodeRecExprEndElmExpr() . . . . . . . . . . code record expr, end element
2059
*F CodeRecExprEnd( <nr>, <top>, <tilde> ) . . . . . . code record expr, end
2060
*/
2061
void CodeRecExprBegin (
2062
UInt top )
2063
{
2064
}
2065
2066
void CodeRecExprBeginElmName (
2067
UInt rnam )
2068
{
2069
/* push the record name as integer expressions */
2070
PushExpr( INTEXPR_INT( rnam ) );
2071
}
2072
2073
void CodeRecExprBeginElmExpr ( void )
2074
{
2075
Expr expr;
2076
2077
/* convert an integer expression to a record name */
2078
expr = PopExpr();
2079
if ( IS_INTEXPR(expr) ) {
2080
PushExpr( INTEXPR_INT( RNamIntg( INT_INTEXPR(expr) ) ) );
2081
}
2082
else {
2083
PushExpr( expr );
2084
}
2085
}
2086
2087
void CodeRecExprEndElm ( void )
2088
{
2089
}
2090
2091
void CodeRecExprEnd (
2092
UInt nr,
2093
UInt top,
2094
UInt tilde )
2095
{
2096
Expr record; /* record, result */
2097
Expr entry; /* entry */
2098
Expr rnam; /* position of an entry */
2099
UInt i; /* loop variable */
2100
2101
/* allocate the record expression */
2102
if ( ! (top && tilde) ) {
2103
record = NewExpr( T_REC_EXPR, nr * 2 * sizeof(Expr) );
2104
}
2105
else /* if ( (top && tilde) ) */ {
2106
record = NewExpr( T_REC_TILD_EXPR, nr * 2 * sizeof(Expr) );
2107
}
2108
2109
/* enter the entries */
2110
for ( i = nr; 1 <= i; i-- ) {
2111
entry = PopExpr();
2112
rnam = PopExpr();
2113
ADDR_EXPR(record)[2*(i-1)] = rnam;
2114
ADDR_EXPR(record)[2*(i-1)+1] = entry;
2115
}
2116
2117
/* push the record */
2118
PushExpr( record );
2119
}
2120
2121
2122
/****************************************************************************
2123
**
2124
*F CodeAssLVar( <lvar> ) . . . . . . . . . . . . . code assignment to local
2125
**
2126
** 'CodeAssLVar' is the action to code an assignment to the local variable
2127
** <lvar> (given by its index). It is called by the reader *after* the
2128
** right hand side expression is read.
2129
**
2130
** An assignment to a local variable is represented by a bag with two
2131
** subexpressions. The *first* is the local variable, the *second* is the
2132
** right hand side expression.
2133
*/
2134
void CodeAssLVar (
2135
UInt lvar )
2136
{
2137
Stat ass; /* assignment, result */
2138
Expr rhsx; /* right hand side expression */
2139
2140
/* allocate the assignment */
2141
if ( lvar <= 16 ) {
2142
ass = NewStat( T_ASS_LVAR + lvar, 2 * sizeof(Stat) );
2143
}
2144
else {
2145
ass = NewStat( T_ASS_LVAR, 2 * sizeof(Stat) );
2146
}
2147
2148
/* enter the right hand side expression */
2149
rhsx = PopExpr();
2150
ADDR_STAT(ass)[1] = (Stat)rhsx;
2151
2152
/* enter the local variable */
2153
ADDR_STAT(ass)[0] = (Stat)lvar;
2154
2155
/* push the assignment */
2156
PushStat( ass );
2157
}
2158
2159
2160
/****************************************************************************
2161
**
2162
*F CodeUnbLVar( <lvar> ) . . . . . . . . . . . code unbind a local variable
2163
*/
2164
void CodeUnbLVar (
2165
UInt lvar )
2166
{
2167
Stat ass; /* unbind, result */
2168
2169
/* allocate the unbind */
2170
ass = NewStat( T_UNB_LVAR, sizeof(Stat) );
2171
2172
/* enter the local variable */
2173
ADDR_STAT(ass)[0] = (Stat)lvar;
2174
2175
/* push the unbind */
2176
PushStat( ass );
2177
}
2178
2179
2180
/****************************************************************************
2181
**
2182
*F CodeRefLVar( <lvar> ) . . . . . . . . . . . . . . code reference to local
2183
**
2184
** 'CodeRefLVar' is the action to code a reference to the local variable
2185
** <lvar> (given by its index). It is called by the reader when it
2186
** encounters a local variable.
2187
**
2188
** A reference to a local variable is represented immediately (see
2189
** 'REFLVAR_LVAR').
2190
*/
2191
void CodeRefLVar (
2192
UInt lvar )
2193
{
2194
Expr ref; /* reference, result */
2195
2196
/* make the reference */
2197
ref = REFLVAR_LVAR(lvar);
2198
2199
/* push the reference */
2200
PushExpr( ref );
2201
}
2202
2203
2204
/****************************************************************************
2205
**
2206
*F CodeIsbLVar( <lvar> ) . . . . . . . . . . code bound local variable check
2207
*/
2208
void CodeIsbLVar (
2209
UInt lvar )
2210
{
2211
Expr ref; /* isbound, result */
2212
2213
/* allocate the isbound */
2214
ref = NewExpr( T_ISB_LVAR, sizeof(Expr) );
2215
2216
/* enter the local variable */
2217
ADDR_EXPR(ref)[0] = (Expr)lvar;
2218
2219
/* push the isbound */
2220
PushExpr( ref );
2221
}
2222
2223
2224
/****************************************************************************
2225
**
2226
*F CodeAssHVar( <hvar> ) . . . . . . . . . . . . . code assignment to higher
2227
**
2228
** 'CodeAssHVar' is the action to code an assignment to the higher variable
2229
** <hvar> (given by its level and index). It is called by the reader
2230
** *after* the right hand side expression is read.
2231
**
2232
** An assignment to a higher variable is represented by a statement bag with
2233
** two subexpressions. The *first* is the higher variable, the *second* is
2234
** the right hand side expression.
2235
*/
2236
void CodeAssHVar (
2237
UInt hvar )
2238
{
2239
Stat ass; /* assignment, result */
2240
Expr rhsx; /* right hand side expression */
2241
2242
/* allocate the assignment */
2243
ass = NewStat( T_ASS_HVAR, 2 * sizeof(Stat) );
2244
2245
/* enter the right hand side expression */
2246
rhsx = PopExpr();
2247
ADDR_STAT(ass)[1] = (Stat)rhsx;
2248
2249
/* enter the higher variable */
2250
ADDR_STAT(ass)[0] = (Stat)hvar;
2251
2252
/* push the assignment */
2253
PushStat( ass );
2254
}
2255
2256
2257
/****************************************************************************
2258
**
2259
*F CodeUnbHVar( <hvar> ) . . . . . . . . . . . . . . . code unbind of higher
2260
*/
2261
void CodeUnbHVar (
2262
UInt hvar )
2263
{
2264
Stat ass; /* unbind, result */
2265
2266
/* allocate the unbind */
2267
ass = NewStat( T_UNB_HVAR, sizeof(Stat) );
2268
2269
/* enter the higher variable */
2270
ADDR_STAT(ass)[0] = (Stat)hvar;
2271
2272
/* push the unbind */
2273
PushStat( ass );
2274
}
2275
2276
2277
/****************************************************************************
2278
**
2279
*F CodeRefHVar( <hvar> ) . . . . . . . . . . . . . code reference to higher
2280
**
2281
** 'CodeRefHVar' is the action to code a reference to the higher variable
2282
** <hvar> (given by its level and index). It is called by the reader when
2283
** it encounters a higher variable.
2284
**
2285
** A reference to a higher variable is represented by an expression bag with
2286
** one subexpression. This is the higher variable.
2287
*/
2288
void CodeRefHVar (
2289
UInt hvar )
2290
{
2291
Expr ref; /* reference, result */
2292
2293
/* allocate the reference */
2294
ref = NewExpr( T_REF_HVAR, sizeof(Expr) );
2295
2296
/* enter the higher variable */
2297
ADDR_EXPR(ref)[0] = (Expr)hvar;
2298
2299
/* push the reference */
2300
PushExpr( ref );
2301
}
2302
2303
2304
/****************************************************************************
2305
**
2306
*F CodeIsbHVar( <hvar> ) . . . . . . . . . . . . . . code bound higher check
2307
*/
2308
void CodeIsbHVar (
2309
UInt hvar )
2310
{
2311
Expr ref; /* isbound, result */
2312
2313
/* allocate the isbound */
2314
ref = NewExpr( T_ISB_HVAR, sizeof(Expr) );
2315
2316
/* enter the higher variable */
2317
ADDR_EXPR(ref)[0] = (Expr)hvar;
2318
2319
/* push the isbound */
2320
PushExpr( ref );
2321
}
2322
2323
2324
/****************************************************************************
2325
**
2326
*F CodeAssGVar( <gvar> ) . . . . . . . . . . . . . code assignment to global
2327
**
2328
** 'CodeAssGVar' is the action to code an assignment to the global variable
2329
** <gvar>. It is called by the reader *after* the right hand side
2330
** expression is read.
2331
**
2332
** An assignment to a global variable is represented by a statement bag with
2333
** two subexpressions. The *first* is the global variable, the *second* is
2334
** the right hand side expression.
2335
*/
2336
void CodeAssGVar (
2337
UInt gvar )
2338
{
2339
Stat ass; /* assignment, result */
2340
Expr rhsx; /* right hand side expression */
2341
2342
/* allocate the assignment */
2343
ass = NewStat( T_ASS_GVAR, 2 * sizeof(Stat) );
2344
2345
/* enter the right hand side expression */
2346
rhsx = PopExpr();
2347
ADDR_STAT(ass)[1] = (Stat)rhsx;
2348
2349
/* enter the global variable */
2350
ADDR_STAT(ass)[0] = (Stat)gvar;
2351
2352
/* push the assignment */
2353
PushStat( ass );
2354
}
2355
2356
2357
/****************************************************************************
2358
**
2359
*F CodeUnbGVar( <gvar> ) . . . . . . . . . . . . . . . code unbind of global
2360
*/
2361
void CodeUnbGVar (
2362
UInt gvar )
2363
{
2364
Stat ass; /* unbind, result */
2365
2366
/* allocate the unbind */
2367
ass = NewStat( T_UNB_GVAR, sizeof(Stat) );
2368
2369
/* enter the global variable */
2370
ADDR_STAT(ass)[0] = (Stat)gvar;
2371
2372
/* push the unbind */
2373
PushStat( ass );
2374
}
2375
2376
2377
/****************************************************************************
2378
**
2379
*F CodeRefGVar( <gvar> ) . . . . . . . . . . . . . code reference to global
2380
**
2381
** 'CodeRefGVar' is the action to code a reference to the global variable
2382
** <gvar>. It is called by the reader when it encounters a global variable.
2383
**
2384
** A reference to a global variable is represented by an expression bag with
2385
** one subexpression. This is the global variable.
2386
*/
2387
void CodeRefGVar (
2388
UInt gvar )
2389
{
2390
Expr ref; /* reference, result */
2391
2392
/* allocate the reference */
2393
ref = NewExpr( T_REF_GVAR, sizeof(Expr) );
2394
2395
/* enter the global variable */
2396
ADDR_EXPR(ref)[0] = (Expr)gvar;
2397
2398
/* push the reference */
2399
PushExpr( ref );
2400
}
2401
2402
2403
/****************************************************************************
2404
**
2405
*F CodeIsbGVar( <gvar> ) . . . . . . . . . . . . . . code bound global check
2406
*/
2407
void CodeIsbGVar (
2408
UInt gvar )
2409
{
2410
Expr ref; /* isbound, result */
2411
2412
/* allocate the isbound */
2413
ref = NewExpr( T_ISB_GVAR, sizeof(Expr) );
2414
2415
/* enter the global variable */
2416
ADDR_EXPR(ref)[0] = (Expr)gvar;
2417
2418
/* push the isbound */
2419
PushExpr( ref );
2420
}
2421
2422
2423
/****************************************************************************
2424
**
2425
*F CodeAssList() . . . . . . . . . . . . . . . . . code assignment to a list
2426
*F CodeAsssList() . . . . . . . . . . . code multiple assignment to a list
2427
*F CodeAssListLevel( <level> ) . . . . . . code assignment to several lists
2428
*F CodeAsssListLevel( <level> ) . code multiple assignment to several lists
2429
*/
2430
void CodeAssListUniv (
2431
Stat ass,
2432
Int narg)
2433
{
2434
Expr list; /* list expression */
2435
Expr pos; /* position expression */
2436
Expr rhsx; /* right hand side expression */
2437
Int i;
2438
2439
/* enter the right hand side expression */
2440
rhsx = PopExpr();
2441
ADDR_STAT(ass)[narg+1] = (Stat)rhsx;
2442
2443
/* enter the position expression */
2444
for (i = narg; i > 0; i--) {
2445
pos = PopExpr();
2446
ADDR_STAT(ass)[i] = (Stat)pos;
2447
}
2448
2449
/* enter the list expression */
2450
list = PopExpr();
2451
ADDR_STAT(ass)[0] = (Stat)list;
2452
2453
/* push the assignment */
2454
PushStat( ass );
2455
}
2456
2457
void CodeAssList ( Int narg )
2458
{
2459
Stat ass; /* assignment, result */
2460
2461
/* allocate the assignment */
2462
switch (narg) {
2463
case 1:
2464
ass = NewStat( T_ASS_LIST, 3 * sizeof(Stat) );
2465
break;
2466
2467
case 2:
2468
ass = NewStat(T_ASS2_LIST, 4* sizeof(Stat));
2469
break;
2470
default:
2471
ass = NewStat(T_ASSX_LIST, (narg + 2)*sizeof(Stat));
2472
}
2473
2474
/* let 'CodeAssListUniv' do the rest */
2475
CodeAssListUniv( ass, narg );
2476
}
2477
2478
void CodeAsssList ( void )
2479
{
2480
Stat ass; /* assignment, result */
2481
2482
/* allocate the assignment */
2483
ass = NewStat( T_ASSS_LIST, 3 * sizeof(Stat) );
2484
2485
/* let 'CodeAssListUniv' do the rest */
2486
CodeAssListUniv( ass, 1 );
2487
}
2488
2489
void CodeAssListLevel ( Int narg,
2490
UInt level )
2491
{
2492
Stat ass; /* assignment, result */
2493
2494
/* allocate the assignment and enter the level */
2495
ass = NewStat( T_ASS_LIST_LEV, (narg +3) * sizeof(Stat) );
2496
ADDR_STAT(ass)[narg+2] = (Stat)level;
2497
2498
/* let 'CodeAssListUniv' do the rest */
2499
CodeAssListUniv( ass, narg );
2500
}
2501
2502
void CodeAsssListLevel (
2503
UInt level )
2504
{
2505
Stat ass; /* assignment, result */
2506
2507
/* allocate the assignment and enter the level */
2508
ass = NewStat( T_ASSS_LIST_LEV, 4 * sizeof(Stat) );
2509
ADDR_STAT(ass)[3] = (Stat)level;
2510
2511
/* let 'CodeAssListUniv' do the rest */
2512
CodeAssListUniv( ass, 1 );
2513
}
2514
2515
2516
/****************************************************************************
2517
**
2518
*F CodeUnbList() . . . . . . . . . . . . . . . code unbind of list position
2519
*/
2520
void CodeUnbList ( Int narg )
2521
{
2522
Expr list; /* list expression */
2523
Expr pos; /* position expression */
2524
Stat ass; /* unbind, result */
2525
Int i;
2526
2527
/* allocate the unbind */
2528
ass = NewStat( T_UNB_LIST, (narg+1) * sizeof(Stat) );
2529
2530
/* enter the position expressions */
2531
for (i = narg; i > 0; i--) {
2532
pos = PopExpr();
2533
ADDR_STAT(ass)[i] = (Stat)pos;
2534
}
2535
2536
/* enter the list expression */
2537
list = PopExpr();
2538
ADDR_STAT(ass)[0] = (Stat)list;
2539
2540
/* push the unbind */
2541
PushStat( ass );
2542
}
2543
2544
2545
/****************************************************************************
2546
**
2547
*F CodeElmList() . . . . . . . . . . . . . . . . . code selection of a list
2548
*F CodeElmsList() . . . . . . . . . . . . code multiple selection of a list
2549
*F CodeElmListLevel( <level> ) . . . . . . . code selection of several lists
2550
*F CodeElmsListLevel( <level> ) . code multiple selection of several lists
2551
*/
2552
void CodeElmListUniv (
2553
Expr ref,
2554
Int narg)
2555
{
2556
Expr list; /* list expression */
2557
Expr pos; /* position expression */
2558
Int i;
2559
2560
/* enter the position expression */
2561
2562
for (i = narg; i > 0; i--) {
2563
pos = PopExpr();
2564
ADDR_EXPR(ref)[i] = pos;
2565
}
2566
2567
/* enter the list expression */
2568
list = PopExpr();
2569
ADDR_EXPR(ref)[0] = list;
2570
2571
/* push the reference */
2572
PushExpr( ref );
2573
}
2574
2575
void CodeElmList ( Int narg )
2576
{
2577
Expr ref; /* reference, result */
2578
2579
/* allocate the reference */
2580
if (narg == 1)
2581
ref = NewExpr( T_ELM_LIST, 2 * sizeof(Expr) );
2582
else if (narg == 2)
2583
ref = NewExpr( T_ELM2_LIST, 3 * sizeof(Expr) );
2584
else
2585
ref = NewExpr( T_ELMX_LIST, (narg + 1) *sizeof(Expr));
2586
2587
/* let 'CodeElmListUniv' to the rest */
2588
CodeElmListUniv( ref, narg );
2589
2590
}
2591
2592
void CodeElmsList ( void )
2593
{
2594
Expr ref; /* reference, result */
2595
2596
/* allocate the reference */
2597
ref = NewExpr( T_ELMS_LIST, 2 * sizeof(Expr) );
2598
2599
/* let 'CodeElmListUniv' to the rest */
2600
CodeElmListUniv( ref, 1 );
2601
}
2602
2603
void CodeElmListLevel ( Int narg,
2604
UInt level )
2605
{
2606
Expr ref; /* reference, result */
2607
2608
ref = NewExpr( T_ELM_LIST_LEV, (narg+2)*sizeof(Expr));
2609
ADDR_EXPR(ref)[narg+1] = (Stat)level;
2610
2611
2612
/* let 'CodeElmListUniv' do the rest */
2613
CodeElmListUniv( ref, narg );
2614
}
2615
2616
void CodeElmsListLevel (
2617
UInt level )
2618
{
2619
Expr ref; /* reference, result */
2620
2621
/* allocate the reference and enter the level */
2622
ref = NewExpr( T_ELMS_LIST_LEV, 3 * sizeof(Expr) );
2623
ADDR_EXPR(ref)[2] = (Stat)level;
2624
2625
/* let 'CodeElmListUniv' do the rest */
2626
CodeElmListUniv( ref, 1 );
2627
}
2628
2629
2630
/****************************************************************************
2631
**
2632
*F CodeIsbList() . . . . . . . . . . . . . . code bound list position check
2633
*/
2634
void CodeIsbList ( Int narg )
2635
{
2636
Expr ref; /* isbound, result */
2637
Expr list; /* list expression */
2638
Expr pos; /* position expression */
2639
Int i;
2640
2641
/* allocate the isbound */
2642
ref = NewExpr( T_ISB_LIST, (narg + 1) * sizeof(Expr) );
2643
2644
/* enter the position expression */
2645
for (i = narg; i > 0; i--) {
2646
pos = PopExpr();
2647
ADDR_EXPR(ref)[i] = pos;
2648
}
2649
2650
/* enter the list expression */
2651
list = PopExpr();
2652
ADDR_EXPR(ref)[0] = list;
2653
2654
/* push the isbound */
2655
PushExpr( ref );
2656
}
2657
2658
2659
/****************************************************************************
2660
**
2661
*F CodeAssRecName( <rnam> ) . . . . . . . . . . code assignment to a record
2662
*F CodeAssRecExpr() . . . . . . . . . . . . . . code assignment to a record
2663
*/
2664
void CodeAssRecName (
2665
UInt rnam )
2666
{
2667
Stat stat; /* assignment, result */
2668
Expr rec; /* record expression */
2669
Expr rhsx; /* right hand side expression */
2670
2671
/* allocate the assignment */
2672
stat = NewStat( T_ASS_REC_NAME, 3 * sizeof(Stat) );
2673
2674
/* enter the right hand side expression */
2675
rhsx = PopExpr();
2676
ADDR_STAT(stat)[2] = (Stat)rhsx;
2677
2678
/* enter the name */
2679
ADDR_STAT(stat)[1] = (Stat)rnam;
2680
2681
/* enter the record expression */
2682
rec = PopExpr();
2683
ADDR_STAT(stat)[0] = (Stat)rec;
2684
2685
/* push the assignment */
2686
PushStat( stat );
2687
}
2688
2689
void CodeAssRecExpr ( void )
2690
{
2691
Stat stat; /* assignment, result */
2692
Expr rec; /* record expression */
2693
Expr rnam; /* name expression */
2694
Expr rhsx; /* right hand side expression */
2695
2696
/* allocate the assignment */
2697
stat = NewStat( T_ASS_REC_EXPR, 3 * sizeof(Stat) );
2698
2699
/* enter the right hand side expression */
2700
rhsx = PopExpr();
2701
ADDR_STAT(stat)[2] = (Stat)rhsx;
2702
2703
/* enter the name expression */
2704
rnam = PopExpr();
2705
ADDR_STAT(stat)[1] = (Stat)rnam;
2706
2707
/* enter the record expression */
2708
rec = PopExpr();
2709
ADDR_STAT(stat)[0] = (Stat)rec;
2710
2711
/* push the assignment */
2712
PushStat( stat );
2713
}
2714
2715
void CodeUnbRecName (
2716
UInt rnam )
2717
{
2718
Stat stat; /* unbind, result */
2719
Expr rec; /* record expression */
2720
2721
/* allocate the unbind */
2722
stat = NewStat( T_UNB_REC_NAME, 2 * sizeof(Stat) );
2723
2724
/* enter the name */
2725
ADDR_STAT(stat)[1] = (Stat)rnam;
2726
2727
/* enter the record expression */
2728
rec = PopExpr();
2729
ADDR_STAT(stat)[0] = (Stat)rec;
2730
2731
/* push the unbind */
2732
PushStat( stat );
2733
}
2734
2735
void CodeUnbRecExpr ( void )
2736
{
2737
Stat stat; /* unbind, result */
2738
Expr rec; /* record expression */
2739
Expr rnam; /* name expression */
2740
2741
/* allocate the unbind */
2742
stat = NewStat( T_UNB_REC_EXPR, 2 * sizeof(Stat) );
2743
2744
/* enter the name expression */
2745
rnam = PopExpr();
2746
ADDR_STAT(stat)[1] = (Stat)rnam;
2747
2748
/* enter the record expression */
2749
rec = PopExpr();
2750
ADDR_STAT(stat)[0] = (Stat)rec;
2751
2752
/* push the unbind */
2753
PushStat( stat );
2754
}
2755
2756
2757
/****************************************************************************
2758
**
2759
*F CodeElmRecName( <rnam> ) . . . . . . . . . . code selection of a record
2760
*F CodeElmRecExpr() . . . . . . . . . . . . . . code selection of a record
2761
*/
2762
void CodeElmRecName (
2763
UInt rnam )
2764
{
2765
Expr expr; /* reference, result */
2766
Expr rec; /* record expresion */
2767
2768
/* allocate the reference */
2769
expr = NewExpr( T_ELM_REC_NAME, 2 * sizeof(Expr) );
2770
2771
/* enter the name */
2772
ADDR_EXPR(expr)[1] = (Expr)rnam;
2773
2774
/* enter the record expression */
2775
rec = PopExpr();
2776
ADDR_EXPR(expr)[0] = rec;
2777
2778
/* push the reference */
2779
PushExpr( expr );
2780
}
2781
2782
void CodeElmRecExpr ( void )
2783
{
2784
Expr expr; /* reference, result */
2785
Expr rnam; /* name expression */
2786
Expr rec; /* record expresion */
2787
2788
/* allocate the reference */
2789
expr = NewExpr( T_ELM_REC_EXPR, 2 * sizeof(Expr) );
2790
2791
/* enter the expression */
2792
rnam = PopExpr();
2793
ADDR_EXPR(expr)[1] = rnam;
2794
2795
/* enter the record expression */
2796
rec = PopExpr();
2797
ADDR_EXPR(expr)[0] = rec;
2798
2799
/* push the reference */
2800
PushExpr( expr );
2801
}
2802
2803
2804
/****************************************************************************
2805
**
2806
*F CodeIsbRecName( <rnam> ) . . . . . . . . . . . code bound rec name check
2807
*/
2808
void CodeIsbRecName (
2809
UInt rnam )
2810
{
2811
Expr expr; /* isbound, result */
2812
Expr rec; /* record expresion */
2813
2814
/* allocate the isbound */
2815
expr = NewExpr( T_ISB_REC_NAME, 2 * sizeof(Expr) );
2816
2817
/* enter the name */
2818
ADDR_EXPR(expr)[1] = (Expr)rnam;
2819
2820
/* enter the record expression */
2821
rec = PopExpr();
2822
ADDR_EXPR(expr)[0] = rec;
2823
2824
/* push the isbound */
2825
PushExpr( expr );
2826
}
2827
2828
2829
/****************************************************************************
2830
**
2831
*F CodeIsbRecExpr() . . . . . . . . . . . . . . . code bound rec expr check
2832
*/
2833
void CodeIsbRecExpr ( void )
2834
{
2835
Expr expr; /* reference, result */
2836
Expr rnam; /* name expression */
2837
Expr rec; /* record expresion */
2838
2839
/* allocate the isbound */
2840
expr = NewExpr( T_ISB_REC_EXPR, 2 * sizeof(Expr) );
2841
2842
/* enter the expression */
2843
rnam = PopExpr();
2844
ADDR_EXPR(expr)[1] = rnam;
2845
2846
/* enter the record expression */
2847
rec = PopExpr();
2848
ADDR_EXPR(expr)[0] = rec;
2849
2850
/* push the isbound */
2851
PushExpr( expr );
2852
}
2853
2854
2855
/****************************************************************************
2856
**
2857
*F CodeAssPosObj() . . . . . . . . . . . . . . . . code assignment to a list
2858
*F CodeAsssPosObj() . . . . . . . . . . code multiple assignment to a list
2859
*F CodeAssPosObjLevel( <level> ) . . . . . code assignment to several lists
2860
*F CodeAsssPosObjLevel( <level> ) code multiple assignment to several lists
2861
*/
2862
void CodeAssPosObjUniv (
2863
Stat ass )
2864
{
2865
Expr list; /* list expression */
2866
Expr pos; /* position expression */
2867
Expr rhsx; /* right hand side expression */
2868
2869
/* enter the right hand side expression */
2870
rhsx = PopExpr();
2871
ADDR_STAT(ass)[2] = (Stat)rhsx;
2872
2873
/* enter the position expression */
2874
pos = PopExpr();
2875
ADDR_STAT(ass)[1] = (Stat)pos;
2876
2877
/* enter the list expression */
2878
list = PopExpr();
2879
ADDR_STAT(ass)[0] = (Stat)list;
2880
2881
/* push the assignment */
2882
PushStat( ass );
2883
}
2884
2885
void CodeAssPosObj ( void )
2886
{
2887
Stat ass; /* assignment, result */
2888
2889
/* allocate the assignment */
2890
ass = NewStat( T_ASS_POSOBJ, 3 * sizeof(Stat) );
2891
2892
/* let 'CodeAssPosObjUniv' do the rest */
2893
CodeAssPosObjUniv( ass );
2894
}
2895
2896
void CodeAsssPosObj ( void )
2897
{
2898
Stat ass; /* assignment, result */
2899
2900
/* allocate the assignment */
2901
ass = NewStat( T_ASSS_POSOBJ, 3 * sizeof(Stat) );
2902
2903
/* let 'CodeAssPosObjUniv' do the rest */
2904
CodeAssPosObjUniv( ass );
2905
}
2906
2907
void CodeAssPosObjLevel (
2908
UInt level )
2909
{
2910
Stat ass; /* assignment, result */
2911
2912
/* allocate the assignment and enter the level */
2913
ass = NewStat( T_ASS_POSOBJ_LEV, 4 * sizeof(Stat) );
2914
ADDR_STAT(ass)[3] = (Stat)level;
2915
2916
/* let 'CodeAssPosObjUniv' do the rest */
2917
CodeAssPosObjUniv( ass );
2918
}
2919
2920
void CodeAsssPosObjLevel (
2921
UInt level )
2922
{
2923
Stat ass; /* assignment, result */
2924
2925
/* allocate the assignment and enter the level */
2926
ass = NewStat( T_ASSS_POSOBJ_LEV, 4 * sizeof(Stat) );
2927
ADDR_STAT(ass)[3] = (Stat)level;
2928
2929
/* let 'CodeAssPosObjUniv' do the rest */
2930
CodeAssPosObjUniv( ass );
2931
}
2932
2933
2934
/****************************************************************************
2935
**
2936
*F CodeUnbPosObj() . . . . . . . . . . . . . . . . . code unbind pos object
2937
*/
2938
void CodeUnbPosObj ( void )
2939
{
2940
Expr list; /* list expression */
2941
Expr pos; /* position expression */
2942
Stat ass; /* unbind, result */
2943
2944
/* allocate the unbind */
2945
ass = NewStat( T_UNB_POSOBJ, 2 * sizeof(Stat) );
2946
2947
/* enter the position expression */
2948
pos = PopExpr();
2949
ADDR_STAT(ass)[1] = (Stat)pos;
2950
2951
/* enter the list expression */
2952
list = PopExpr();
2953
ADDR_STAT(ass)[0] = (Stat)list;
2954
2955
/* push the unbind */
2956
PushStat( ass );
2957
}
2958
2959
2960
/****************************************************************************
2961
**
2962
*F CodeElmPosObj() . . . . . . . . . . . . . . . . code selection of a list
2963
*F CodeElmsPosObj() . . . . . . . . . . . code multiple selection of a list
2964
*F CodeElmPosObjLevel( <level> ) . . . . . . code selection of several lists
2965
*F CodeElmsPosObjLevel( <level> ) code multiple selection of several lists
2966
*/
2967
void CodeElmPosObjUniv (
2968
Expr ref )
2969
{
2970
Expr list; /* list expression */
2971
Expr pos; /* position expression */
2972
2973
/* enter the position expression */
2974
pos = PopExpr();
2975
ADDR_EXPR(ref)[1] = pos;
2976
2977
/* enter the list expression */
2978
list = PopExpr();
2979
ADDR_EXPR(ref)[0] = list;
2980
2981
/* push the reference */
2982
PushExpr( ref );
2983
}
2984
2985
void CodeElmPosObj ( void )
2986
{
2987
Expr ref; /* reference, result */
2988
2989
/* allocate the reference */
2990
ref = NewExpr( T_ELM_POSOBJ, 2 * sizeof(Expr) );
2991
2992
/* let 'CodeElmPosObjUniv' to the rest */
2993
CodeElmPosObjUniv( ref );
2994
}
2995
2996
void CodeElmsPosObj ( void )
2997
{
2998
Expr ref; /* reference, result */
2999
3000
/* allocate the reference */
3001
ref = NewExpr( T_ELMS_POSOBJ, 2 * sizeof(Expr) );
3002
3003
/* let 'CodeElmPosObjUniv' to the rest */
3004
CodeElmPosObjUniv( ref );
3005
}
3006
3007
void CodeElmPosObjLevel (
3008
UInt level )
3009
{
3010
Expr ref; /* reference, result */
3011
3012
/* allocate the reference and enter the level */
3013
ref = NewExpr( T_ELM_POSOBJ_LEV, 3 * sizeof(Expr) );
3014
ADDR_EXPR(ref)[2] = (Stat)level;
3015
3016
/* let 'CodeElmPosObjUniv' do the rest */
3017
CodeElmPosObjUniv( ref );
3018
}
3019
3020
void CodeElmsPosObjLevel (
3021
UInt level )
3022
{
3023
Expr ref; /* reference, result */
3024
3025
/* allocate the reference and enter the level */
3026
ref = NewExpr( T_ELMS_POSOBJ_LEV, 3 * sizeof(Expr) );
3027
ADDR_EXPR(ref)[2] = (Stat)level;
3028
3029
/* let 'CodeElmPosObjUniv' do the rest */
3030
CodeElmPosObjUniv( ref );
3031
}
3032
3033
3034
/****************************************************************************
3035
**
3036
*F CodeIsbPosObj() . . . . . . . . . . . . . . . code bound pos object check
3037
*/
3038
void CodeIsbPosObj ( void )
3039
{
3040
Expr ref; /* isbound, result */
3041
Expr list; /* list expression */
3042
Expr pos; /* position expression */
3043
3044
/* allocate the isbound */
3045
ref = NewExpr( T_ISB_POSOBJ, 2 * sizeof(Expr) );
3046
3047
/* enter the position expression */
3048
pos = PopExpr();
3049
ADDR_EXPR(ref)[1] = pos;
3050
3051
/* enter the list expression */
3052
list = PopExpr();
3053
ADDR_EXPR(ref)[0] = list;
3054
3055
/* push the isbound */
3056
PushExpr( ref );
3057
}
3058
3059
3060
/****************************************************************************
3061
**
3062
*F CodeAssComObjName( <rnam> ) . . . . . . . . . code assignment to a record
3063
*F CodeAssComObjExpr() . . . . . . . . . . . . . code assignment to a record
3064
*/
3065
void CodeAssComObjName (
3066
UInt rnam )
3067
{
3068
Stat stat; /* assignment, result */
3069
Expr rec; /* record expression */
3070
Expr rhsx; /* right hand side expression */
3071
3072
/* allocate the assignment */
3073
stat = NewStat( T_ASS_COMOBJ_NAME, 3 * sizeof(Stat) );
3074
3075
/* enter the right hand side expression */
3076
rhsx = PopExpr();
3077
ADDR_STAT(stat)[2] = (Stat)rhsx;
3078
3079
/* enter the name */
3080
ADDR_STAT(stat)[1] = (Stat)rnam;
3081
3082
/* enter the record expression */
3083
rec = PopExpr();
3084
ADDR_STAT(stat)[0] = (Stat)rec;
3085
3086
/* push the assignment */
3087
PushStat( stat );
3088
}
3089
3090
void CodeAssComObjExpr ( void )
3091
{
3092
Stat stat; /* assignment, result */
3093
Expr rec; /* record expression */
3094
Expr rnam; /* name expression */
3095
Expr rhsx; /* right hand side expression */
3096
3097
/* allocate the assignment */
3098
stat = NewStat( T_ASS_COMOBJ_EXPR, 3 * sizeof(Stat) );
3099
3100
/* enter the right hand side expression */
3101
rhsx = PopExpr();
3102
ADDR_STAT(stat)[2] = (Stat)rhsx;
3103
3104
/* enter the name expression */
3105
rnam = PopExpr();
3106
ADDR_STAT(stat)[1] = (Stat)rnam;
3107
3108
/* enter the record expression */
3109
rec = PopExpr();
3110
ADDR_STAT(stat)[0] = (Stat)rec;
3111
3112
/* push the assignment */
3113
PushStat( stat );
3114
}
3115
3116
void CodeUnbComObjName (
3117
UInt rnam )
3118
{
3119
Stat stat; /* unbind, result */
3120
Expr rec; /* record expression */
3121
3122
/* allocate the unbind */
3123
stat = NewStat( T_UNB_COMOBJ_NAME, 2 * sizeof(Stat) );
3124
3125
/* enter the name */
3126
ADDR_STAT(stat)[1] = (Stat)rnam;
3127
3128
/* enter the record expression */
3129
rec = PopExpr();
3130
ADDR_STAT(stat)[0] = (Stat)rec;
3131
3132
/* push the unbind */
3133
PushStat( stat );
3134
}
3135
3136
void CodeUnbComObjExpr ( void )
3137
{
3138
Stat stat; /* unbind, result */
3139
Expr rec; /* record expression */
3140
Expr rnam; /* name expression */
3141
3142
/* allocate the unbind */
3143
stat = NewStat( T_UNB_COMOBJ_EXPR, 2 * sizeof(Stat) );
3144
3145
/* enter the name expression */
3146
rnam = PopExpr();
3147
ADDR_STAT(stat)[1] = (Stat)rnam;
3148
3149
/* enter the record expression */
3150
rec = PopExpr();
3151
ADDR_STAT(stat)[0] = (Stat)rec;
3152
3153
/* push the unbind */
3154
PushStat( stat );
3155
}
3156
3157
3158
/****************************************************************************
3159
**
3160
*F CodeElmComObjName( <rnam> ) . . . . . . . . . code selection of a record
3161
*F CodeElmComObjExpr() . . . . . . . . . . . . . code selection of a record
3162
*/
3163
void CodeElmComObjName (
3164
UInt rnam )
3165
{
3166
Expr expr; /* reference, result */
3167
Expr rec; /* record expresion */
3168
3169
/* allocate the reference */
3170
expr = NewExpr( T_ELM_COMOBJ_NAME, 2 * sizeof(Expr) );
3171
3172
/* enter the name */
3173
ADDR_EXPR(expr)[1] = (Expr)rnam;
3174
3175
/* enter the record expression */
3176
rec = PopExpr();
3177
ADDR_EXPR(expr)[0] = rec;
3178
3179
/* push the reference */
3180
PushExpr( expr );
3181
}
3182
3183
void CodeElmComObjExpr ( void )
3184
{
3185
Expr expr; /* reference, result */
3186
Expr rnam; /* name expression */
3187
Expr rec; /* record expresion */
3188
3189
/* allocate the reference */
3190
expr = NewExpr( T_ELM_COMOBJ_EXPR, 2 * sizeof(Expr) );
3191
3192
/* enter the expression */
3193
rnam = PopExpr();
3194
ADDR_EXPR(expr)[1] = rnam;
3195
3196
/* enter the record expression */
3197
rec = PopExpr();
3198
ADDR_EXPR(expr)[0] = rec;
3199
3200
/* push the reference */
3201
PushExpr( expr );
3202
}
3203
3204
3205
/****************************************************************************
3206
**
3207
*F CodeIsbComObjName( <rname> ) . . . . . code bound com object name check
3208
*/
3209
void CodeIsbComObjName (
3210
UInt rnam )
3211
{
3212
Expr expr; /* isbound, result */
3213
Expr rec; /* record expresion */
3214
3215
/* allocate the isbound */
3216
expr = NewExpr( T_ISB_COMOBJ_NAME, 2 * sizeof(Expr) );
3217
3218
/* enter the name */
3219
ADDR_EXPR(expr)[1] = (Expr)rnam;
3220
3221
/* enter the record expression */
3222
rec = PopExpr();
3223
ADDR_EXPR(expr)[0] = rec;
3224
3225
/* push the isbound */
3226
PushExpr( expr );
3227
}
3228
3229
/****************************************************************************
3230
**
3231
*F CodeIsbComObjExpr() . . . . . . . . . . code bound com object expr check
3232
*/
3233
void CodeIsbComObjExpr ( void )
3234
{
3235
Expr expr; /* reference, result */
3236
Expr rnam; /* name expression */
3237
Expr rec; /* record expresion */
3238
3239
/* allocate the isbound */
3240
expr = NewExpr( T_ISB_COMOBJ_EXPR, 2 * sizeof(Expr) );
3241
3242
/* enter the expression */
3243
rnam = PopExpr();
3244
ADDR_EXPR(expr)[1] = rnam;
3245
3246
/* enter the record expression */
3247
rec = PopExpr();
3248
ADDR_EXPR(expr)[0] = rec;
3249
3250
/* push the isbound */
3251
PushExpr( expr );
3252
}
3253
3254
3255
/****************************************************************************
3256
**
3257
*F CodeEmpty() . . . . code an empty statement
3258
**
3259
*/
3260
3261
extern void CodeEmpty( void )
3262
{
3263
Stat stat;
3264
stat = NewStat(T_EMPTY, 0);
3265
PushStat( stat );
3266
}
3267
3268
/****************************************************************************
3269
**
3270
*F CodeInfoBegin() . . . . . . . . . . . . . start coding of Info statement
3271
*F CodeInfoMiddle() . . . . . . . . . shift to coding printable arguments
3272
*F CodeInfoEnd( <narg> ) . . Info statement complete, <narg> things to print
3273
**
3274
** These actions deal with the Info statement, which is coded specially,
3275
** because not all of its arguments are always evaluated.
3276
**
3277
** Only CodeInfoEnd actually does anything
3278
*/
3279
void CodeInfoBegin ( void )
3280
{
3281
}
3282
3283
void CodeInfoMiddle ( void )
3284
{
3285
}
3286
3287
void CodeInfoEnd (
3288
UInt narg )
3289
{
3290
Stat stat; /* we build the statement here */
3291
Expr expr; /* expression */
3292
UInt i; /* loop variable */
3293
3294
/* allocate the new statement */
3295
stat = NewStat( T_INFO, SIZE_NARG_INFO(2+narg) );
3296
3297
/* narg only counts the printable arguments */
3298
for ( i = narg + 2; 0 < i; i-- ) {
3299
expr = PopExpr();
3300
ARGI_INFO( stat, i ) = expr;
3301
}
3302
3303
/* push the statement */
3304
PushStat( stat );
3305
}
3306
3307
3308
/****************************************************************************
3309
**
3310
*F CodeAssertBegin() . . . . . . . start interpretation of Assert statement
3311
*F CodeAsseerAfterLevel() . . called after the first argument has been read
3312
*F CodeAssertAfterCondition() called after the second argument has been read
3313
*F CodeAssertEnd2Args() . . . . called after reading the closing parenthesis
3314
*F CodeAssertEnd3Args() . . . . called after reading the closing parenthesis
3315
**
3316
** Only the End functions actually do anything
3317
*/
3318
void CodeAssertBegin ( void )
3319
{
3320
}
3321
3322
void CodeAssertAfterLevel ( void )
3323
{
3324
}
3325
3326
void CodeAssertAfterCondition ( void )
3327
{
3328
}
3329
3330
void CodeAssertEnd2Args ( void )
3331
{
3332
Stat stat; /* we build the statement here */
3333
3334
stat = NewStat( T_ASSERT_2ARGS, 2*sizeof(Expr) );
3335
3336
ADDR_STAT(stat)[1] = PopExpr(); /* condition */
3337
ADDR_STAT(stat)[0] = PopExpr(); /* level */
3338
3339
PushStat( stat );
3340
}
3341
3342
void CodeAssertEnd3Args ( void )
3343
{
3344
Stat stat; /* we build the statement here */
3345
3346
stat = NewStat( T_ASSERT_3ARGS, 3*sizeof(Expr) );
3347
3348
ADDR_STAT(stat)[2] = PopExpr(); /* message */
3349
ADDR_STAT(stat)[1] = PopExpr(); /* condition */
3350
ADDR_STAT(stat)[0] = PopExpr(); /* level */
3351
3352
PushStat( stat );
3353
}
3354
3355
/****************************************************************************
3356
**
3357
*F SaveBody( <body> ) . . . . . . . . . . . . . . . workspace saving method
3358
**
3359
** A body is made up of statements and expressions, and these are all
3360
** organised to regular boundaries based on the types Stat and Expr, which
3361
** are currently both UInt
3362
**
3363
** String literals should really be saved byte-wise, to be safe across machines
3364
** of different endianness, but this would mean parsing the bag as we save it
3365
** which it would be nice to avoid just now.
3366
*/
3367
void SaveBody ( Obj body )
3368
{
3369
UInt i;
3370
UInt *ptr;
3371
ptr = (UInt *) ADDR_OBJ(body);
3372
/* Save the new inforation in the body */
3373
for (i =0; i < NUMBER_HEADER_ITEMS_BODY; i++)
3374
SaveSubObj((Obj)(*ptr++));
3375
/* and the rest */
3376
for (; i < (SIZE_OBJ(body)+sizeof(UInt)-1)/sizeof(UInt); i++)
3377
SaveUInt(*ptr++);
3378
}
3379
3380
/****************************************************************************
3381
**
3382
*F LoadBody( <body> ) . . . . . . . . . . . . . . . workspace loading method
3383
**
3384
** A body is made up of statements and expressions, and these are all
3385
** organised to regular boundaries based on the types Stat and Expr, which
3386
** are currently both UInt
3387
**
3388
*/
3389
void LoadBody ( Obj body )
3390
{
3391
UInt i;
3392
UInt *ptr;
3393
ptr = (UInt *) ADDR_OBJ(body);
3394
for (i =0; i < NUMBER_HEADER_ITEMS_BODY; i++)
3395
*(Obj *)(ptr++) = LoadSubObj();
3396
for (; i < (SIZE_OBJ(body)+sizeof(UInt)-1)/sizeof(UInt); i++)
3397
*ptr++ = LoadUInt();
3398
}
3399
3400
3401
/****************************************************************************
3402
**
3403
*F * * * * * * * * * * * * * initialize package * * * * * * * * * * * * * * *
3404
*/
3405
3406
/****************************************************************************
3407
**
3408
*F InitKernel( <module> ) . . . . . . . . initialise kernel data structures
3409
*/
3410
static Int InitKernel (
3411
StructInitInfo * module )
3412
{
3413
/* install the marking functions for function body bags */
3414
InfoBags[ T_BODY ].name = "function body bag";
3415
InitMarkFuncBags( T_BODY, MarkThreeSubBags );
3416
3417
SaveObjFuncs[ T_BODY ] = SaveBody;
3418
LoadObjFuncs[ T_BODY ] = LoadBody;
3419
3420
/* Allocate function bodies in the public data space */
3421
MakeBagTypePublic(T_BODY);
3422
3423
/* make the result variable known to Gasman */
3424
InitGlobalBag( &CodeResult, "CodeResult" );
3425
3426
InitGlobalBag( &FilenameCache, "FilenameCache" );
3427
3428
/* allocate the statements and expressions stacks */
3429
InitGlobalBag( &TLS(StackStat), "TLS(StackStat)" );
3430
InitGlobalBag( &TLS(StackExpr), "TLS(StackExpr)" );
3431
3432
/* some functions and globals needed for float conversion */
3433
InitCopyGVar( "EAGER_FLOAT_LITERAL_CACHE", &EAGER_FLOAT_LITERAL_CACHE);
3434
InitFopyGVar( "CONVERT_FLOAT_LITERAL_EAGER", &CONVERT_FLOAT_LITERAL_EAGER);
3435
3436
/* return success */
3437
return 0;
3438
}
3439
3440
3441
/****************************************************************************
3442
**
3443
*F InitLibrary( <module> ) . . . . . . . initialise library data structures
3444
*/
3445
static Int InitLibrary (
3446
StructInitInfo * module )
3447
{
3448
UInt gv;
3449
Obj cache;
3450
/* allocate the statements and expressions stacks */
3451
TLS(StackStat) = NewBag( T_BODY, 64*sizeof(Stat) );
3452
TLS(StackExpr) = NewBag( T_BODY, 64*sizeof(Expr) );
3453
FilenameCache = NEW_PLIST(T_PLIST, 0);
3454
3455
GVAR_SAVED_FLOAT_INDEX = GVarName("SavedFloatIndex");
3456
3457
gv = GVarName("EAGER_FLOAT_LITERAL_CACHE");
3458
cache = NEW_PLIST(T_PLIST+IMMUTABLE, 1000L);
3459
SET_LEN_PLIST(cache,0);
3460
AssGVar(gv, cache);
3461
3462
/* return success */
3463
return 0;
3464
}
3465
3466
/****************************************************************************
3467
**
3468
*F PostRestore( <module> ) . . . . . . . recover
3469
*/
3470
static Int PostRestore (
3471
StructInitInfo * module )
3472
{
3473
GVAR_SAVED_FLOAT_INDEX = GVarName("SavedFloatIndex");
3474
NextFloatExprNumber = INT_INTOBJ(VAL_GVAR(GVAR_SAVED_FLOAT_INDEX));
3475
return 0;
3476
}
3477
3478
3479
/****************************************************************************
3480
**
3481
*F PreSave( <module> ) . . . . . . . clean up before saving
3482
*/
3483
static Int PreSave (
3484
StructInitInfo * module )
3485
{
3486
UInt i;
3487
3488
/* Can't save in mid-parsing */
3489
if (TLS(CountExpr) || TLS(CountStat))
3490
return 1;
3491
3492
/* push the FP cache index out into a GAP Variable */
3493
AssGVar(GVAR_SAVED_FLOAT_INDEX, INTOBJ_INT(NextFloatExprNumber));
3494
3495
/* clean any old data out of the statement and expression stacks */
3496
for (i = 0; i < SIZE_BAG(TLS(StackStat))/sizeof(UInt); i++)
3497
ADDR_OBJ(TLS(StackStat))[i] = (Obj)0;
3498
for (i = 0; i < SIZE_BAG(TLS(StackExpr))/sizeof(UInt); i++)
3499
ADDR_OBJ(TLS(StackExpr))[i] = (Obj)0;
3500
/* return success */
3501
return 0;
3502
}
3503
3504
3505
3506
/****************************************************************************
3507
**
3508
*F InitInfoCode() . . . . . . . . . . . . . . . . . table of init functions
3509
*/
3510
static StructInitInfo module = {
3511
MODULE_BUILTIN, /* type */
3512
"code", /* name */
3513
0, /* revision entry of c file */
3514
0, /* revision entry of h file */
3515
0, /* version */
3516
0, /* crc */
3517
InitKernel, /* initKernel */
3518
InitLibrary, /* initLibrary */
3519
0, /* checkInit */
3520
PreSave, /* preSave */
3521
0, /* postSave */
3522
PostRestore /* postRestore */
3523
};
3524
3525
StructInitInfo * InitInfoCode ( void )
3526
{
3527
return &module;
3528
}
3529
3530
3531
/****************************************************************************
3532
**
3533
3534
*E code.c . . . . . . . . . . . . . . . . . . . . . . . . . . . . ends here
3535
*/
3536
3537