-
Notifications
You must be signed in to change notification settings - Fork 0
/
tcprs.cpp
9289 lines (8040 loc) · 261 KB
/
tcprs.cpp
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
885
886
887
888
889
890
891
892
893
894
895
896
897
898
899
900
901
902
903
904
905
906
907
908
909
910
911
912
913
914
915
916
917
918
919
920
921
922
923
924
925
926
927
928
929
930
931
932
933
934
935
936
937
938
939
940
941
942
943
944
945
946
947
948
949
950
951
952
953
954
955
956
957
958
959
960
961
962
963
964
965
966
967
968
969
970
971
972
973
974
975
976
977
978
979
980
981
982
983
984
985
986
987
988
989
990
991
992
993
994
995
996
997
998
999
1000
#ifdef RCSID
static char RCSid[] =
"$Header: d:/cvsroot/tads/tads3/TCPRS.CPP,v 1.5 1999/07/11 00:46:53 MJRoberts Exp $";
#endif
/*
* Copyright (c) 1999, 2002 Michael J. Roberts. All Rights Reserved.
*
* Please see the accompanying license file, LICENSE.TXT, for information
* on using and copying this software.
*/
/*
Name
tcprs.cpp - TADS 3 Compiler Parser
Function
This parser module contains code required for any parser usage, both
for a full compiler and for a debugger.
Notes
Modified
04/30/99 MJRoberts - Creation
*/
#include <stdlib.h>
#include <string.h>
#include <stdio.h>
#include <assert.h>
#include <stdarg.h>
#include "os.h"
#include "t3std.h"
#include "tcprs.h"
#include "tctarg.h"
#include "tcgen.h"
#include "vmhash.h"
#include "tcmain.h"
#include "vmfile.h"
#include "tctok.h"
#include "vmbignum.h"
/* ------------------------------------------------------------------------ */
/*
* Expression Operator parser objects. These objects are linked
* together in a network that defines the order of precedence for
* expression operators.
*
* These objects use static storage. This is acceptable, even though
* these objects aren't all "const" qualified, because the compiler uses
* a single global parser object; since there's only the one parser,
* there only needs to be a single network of these objects.
*/
/* unary operator parser */
static CTcPrsOpUnary S_op_unary;
/* factor group */
static const CTcPrsOpMul S_op_mul;
static const CTcPrsOpDiv S_op_div;
static const CTcPrsOpMod S_op_mod;
static const CTcPrsOpBin *const
S_grp_factor[] = { &S_op_mul, &S_op_div, &S_op_mod, 0 };
static const CTcPrsOpBinGroup S_op_factor(&S_op_unary, &S_op_unary,
S_grp_factor);
/* term group */
static const CTcPrsOpAdd S_op_add;
static const CTcPrsOpSub S_op_sub;
static const CTcPrsOpBin *const S_grp_term[] = { &S_op_add, &S_op_sub, 0 };
static const CTcPrsOpBinGroup S_op_term(&S_op_factor, &S_op_factor,
S_grp_term);
/* shift group */
static const CTcPrsOpShl S_op_shl;
static const CTcPrsOpAShr S_op_ashr;
static const CTcPrsOpLShr S_op_lshr;
static const CTcPrsOpBin *const S_grp_shift[] =
{ &S_op_shl, &S_op_ashr, &S_op_lshr, 0 };
static const CTcPrsOpBinGroup S_op_shift(&S_op_term, &S_op_term,
S_grp_shift);
/* magnitude comparisons group */
static const CTcPrsOpGt S_op_gt;
static const CTcPrsOpGe S_op_ge;
static const CTcPrsOpLt S_op_lt;
static const CTcPrsOpLe S_op_le;
static const CTcPrsOpBin *const
S_grp_relcomp[] = { &S_op_gt, &S_op_ge, &S_op_lt, &S_op_le, 0 };
static const CTcPrsOpBinGroup S_op_relcomp(&S_op_shift, &S_op_shift,
S_grp_relcomp);
/*
* Equality/inequality comparison group. Note that the equality operator
* is non-const because we want the option to change the operator on the
* fly based on syntax mode - '==' in C-mode, '=' in TADS traditional mode.
* (This was a feature of tads 2, but we have since deprecated it in tads
* 3, so this ability is actually just vestigial at this point. No harm in
* keeping around the code internally for it, though, since it's pretty
* simple.)
*
* Note also that this is a special binary group - this one recognizes the
* non-keyword operators 'is in' and 'not in'.
*/
static CTcPrsOpEq S_op_eq;
static const CTcPrsOpNe S_op_ne;
static const CTcPrsOpBin *const
S_grp_eqcomp[] = { &S_op_eq, &S_op_ne, 0 };
static const CTcPrsOpBinGroupCompare
S_op_eqcomp(&S_op_relcomp, &S_op_relcomp, S_grp_eqcomp);
/* bitwise AND operator */
static const CTcPrsOpBAnd S_op_band(&S_op_eqcomp, &S_op_eqcomp);
/* bitwise XOR operator */
static const CTcPrsOpBXor S_op_bxor(&S_op_band, &S_op_band);
/* bitwise OR operator */
static const CTcPrsOpBOr S_op_bor(&S_op_bxor, &S_op_bxor);
/* logical AND operator */
static const CTcPrsOpAnd S_op_and(&S_op_bor, &S_op_bor);
/* logical OR operator */
static const CTcPrsOpOr S_op_or(&S_op_and, &S_op_and);
/* if-nil operator ?? */
static const CTcPrsOpIfnil S_op_ifnil;
/* conditional operator */
static const CTcPrsOpIf S_op_if;
/*
* assignment operator - note that this is non-const, because we must be
* able to change the operator - '=' in C-mode, and ':=' in TADS
* traditional mode
*/
static CTcPrsOpAsi S_op_asi;
/* comma operator */
static const CTcPrsOpComma S_op_comma(&S_op_asi, &S_op_asi);
/* ------------------------------------------------------------------------ */
/*
* Embedded expression token list. We capture the tokens of an embedded
* expression in a private list for a first scan, to compare against the
* list of special embedding templates. If we determine that the embedding
* is a simple expression, or that a portion of it is an expression, we'll
* push the captured tokens back into the token stream via 'unget'.
*/
class CTcEmbedTokenList
{
public:
CTcEmbedTokenList()
{
/* create the initial list entry */
wrt = head = new CTcTokenEle();
cnt = 0;
}
~CTcEmbedTokenList()
{
/* delete the token list */
while (head != 0)
{
CTcTokenEle *nxt = head->getnxt();
delete head;
head = nxt;
}
}
/* reset the list */
void reset()
{
/* set the read and write pointers to the allocated list head */
wrt = head;
cnt = 0;
}
/* get the number of tokens remaining */
int getcnt() const { return cnt; }
/* get the head elemenet */
const CTcToken *get_head() const { return head; }
/* remove the head element */
void unlink_head(CTcToken *tok)
{
if (head != 0)
{
/* copy the token to the caller's buffer */
G_tok->copytok(tok, head);
/* unlink it */
CTcTokenEle *h = head;
head = head->getnxt();
--cnt;
/* delete it */
delete h;
}
else
{
/* no token available - return EOF */
tok->settyp(TOKT_EOF);
}
}
/* add a token to the list */
void add_tok(const CTcToken *tok)
{
/* fill in the write token */
G_tok->copytok(wrt, tok);
/* if this is the last item in the list, add another */
if (wrt->getnxt() == 0)
{
CTcTokenEle *ele = new CTcTokenEle();
ele->setprv(wrt);
wrt->setnxt(ele);
}
/* advance the write pointer */
wrt = wrt->getnxt();
/* count it */
++cnt;
}
/*
* Unget the captured tokens, skipping the first n tokens and the last
* m tokens.
*/
void unget(int n = 0, int m = 0)
{
/* skip the last 'm' tokens */
CTcTokenEle *ele;
int i;
for (ele = wrt->getprv(), i = cnt ; m != 0 && ele != 0 ;
ele = ele->getprv(), --m, --i) ;
/* unget tokens until we're down to the first 'n' */
for ( ; ele != 0 && i > n ; ele = ele->getprv(), --i)
G_tok->unget(ele);
}
/* match a string of space-delimited tokens */
int match(const char *txt)
{
/* count the tokens */
int argn = 0;
const char *p;
for (p = txt ; *p != '\0' ; ++argn)
{
/* skip leading spaces */
for ( ; is_space(*p) ; ++p) ;
/* scan to the next space */
for ( ; *p != '\0' && !is_space(*p) ; ++p) ;
}
/* if we don't have enough tokens to match the input, we can't match */
if (cnt < argn)
return FALSE;
/* check the arguments against the list */
CTcTokenEle *ele;
int tokn;
for (tokn = cnt, ele = head, p = txt ; tokn != 0 && argn != 0 ;
ele = ele->getnxt(), --tokn, --argn)
{
/* get this argument */
for ( ; is_space(*p) ; ++p) ;
const char *arg = p;
/* find the end of the argument */
for ( ; *p != '\0' && !is_space(*p) ; ++p) ;
size_t len = p - arg;
/* check for special arguments */
if (arg[0] == '*')
{
/*
* '*' - this matches one or more tokens in the token list
* up to the last remaining arguments after the '*'. Skip
* arguments until the token list and remaining argument
* list are the same length.
*/
for ( ; tokn > argn ; ele = ele->getnxt(), --tokn) ;
}
else
{
/* it's a literal - check for a match */
if (!ele->text_matches(arg, len))
return FALSE;
}
}
/* if the lists ran out at the same time, it's a match */
return (tokn == 0 && argn == 0);
}
/* match a string template definition */
int match(CTcStrTemplate *tpl)
{
/* if we don't have enough tokens to match, don't bother looking */
if (cnt < tpl->cnt)
return FALSE;
/* check the arguments against the list */
CTcTokenEle *ele, *tele;
int tokn, tpln;
for (tokn = cnt, tpln = tpl->cnt, ele = head, tele = tpl->head ;
tokn != 0 && tpln != 0 ;
ele = ele->getnxt(), tele = tele->getnxt(), --tokn, --tpln)
{
/* check for special arguments */
if (tele->text_matches("*", 1))
{
/*
* '*' - this matches one or more tokens in the token list
* up to the last remaining arguments after the '*'. Skip
* arguments until the token list and remaining argument
* list are the same length.
*/
for ( ; tokn > tpln ; ele = ele->getnxt(), --tokn) ;
}
else
{
/* it's a literal - check for a match */
if (!ele->text_matches(tele->get_text(), tele->get_text_len()))
return FALSE;
}
}
/* if the lists ran out at the same time, it's a match */
return (tokn == 0 && tpln == 0);
}
/*
* Reduce our token list to include only the tokens matching the '*' in
* a template. This presumes that the template actually does match.
*/
void reduce(CTcStrTemplate *tpl)
{
/* find the first token in our list matching '*' in the template */
CTcTokenEle *src, *tele;
int rem, trem;
for (src = head, tele = tpl->head, rem = cnt, trem = tpl->cnt ;
src != 0 && tele != 0 ;
src = src->getnxt(), tele = tele->getnxt(), --rem, --trem)
{
/* stop when we reach '*' in the template */
if (tele->text_matches("*", 1))
break;
}
/* skip the '*' in the template */
trem -= 1;
/*
* The number of tokens matching '*' is the number left in our
* list, minus the number left in the token list after the '*'.
*/
rem -= trem;
cnt = rem;
/* if we had any leading fixed tokens to remove, remove them */
if (src != head)
{
CTcTokenEle *dst;
for (dst = head ; rem != 0 && src != 0 ;
src = src->getnxt(), dst = dst->getnxt(), --rem)
{
/* copy this token */
G_tok->copytok(dst, src);
}
}
/* move the write pointer to the proper position */
for (wrt = head, rem = cnt ; rem != 0 ; wrt = wrt->getnxt(), --rem) ;
}
protected:
/* head of the allocated list */
CTcTokenEle *head;
/* current write pointer */
CTcTokenEle *wrt;
/* number of tokens currently in the list */
int cnt;
};
/* ------------------------------------------------------------------------ */
/*
* Main Parser
*/
/*
* initialize the parser
*/
CTcParser::CTcParser()
{
size_t i;
/* we don't have any module information yet */
module_name_ = 0;
module_seqno_ = 0;
/* start out in normal mode */
pp_expr_mode_ = FALSE;
src_group_mode_ = FALSE;
/* create the global symbol table */
global_symtab_ = new CTcPrsSymtab(0);
/* no enclosing statement yet */
enclosing_stm_ = 0;
/* no source location yet */
cur_desc_ = 0;
cur_linenum_ = 0;
/* no dictionaries yet */
dict_cur_ = 0;
dict_head_ = dict_tail_ = 0;
/* no object file dictionary list yet */
obj_dict_list_ = 0;
obj_file_dict_idx_ = 0;
/* no dictionary properties yet */
dict_prop_head_ = 0;
/* no grammar productions yet */
gramprod_head_ = gramprod_tail_ = 0;
/* no object file symbol list yet */
obj_sym_list_ = 0;
obj_file_sym_idx_ = 0;
/* no object templates yet */
template_head_ = template_tail_ = 0;
/* allocate some initial template parsing space */
template_expr_max_ = 16;
template_expr_ = (CTcObjTemplateInst *)G_prsmem->
alloc(sizeof(template_expr_[0]) * template_expr_max_);
/* no string templates yet */
str_template_head_ = str_template_tail_ = 0;
/* no locals yet */
local_cnt_ = max_local_cnt_ = 0;
/* no local or goto symbol table yet */
local_symtab_ = 0;
enclosing_local_symtab_ = 0;
goto_symtab_ = 0;
/* no debugger local symbol table yet */
debug_symtab_ = 0;
/* not in a preprocessor constant expression */
pp_expr_mode_ = FALSE;
/* assume we're doing full compilation */
syntax_only_ = FALSE;
/* no nested top-level statements yet */
nested_stm_head_ = 0;
nested_stm_tail_ = 0;
/* no anonymous objects yet */
anon_obj_head_ = 0;
anon_obj_tail_ = 0;
/* no non-symbol objects yet */
nonsym_obj_head_ = 0;
nonsym_obj_tail_ = 0;
/* allocate an initial context variable property array */
ctx_var_props_size_ = 50;
ctx_var_props_ = (tctarg_prop_id_t *)
t3malloc(ctx_var_props_size_ * sizeof(tctarg_prop_id_t));
/* no context variable properties assigned yet */
ctx_var_props_cnt_ = 0;
ctx_var_props_used_ = 0;
/*
* no context variable indices assigned yet - start at one higher
* than the index at which we always store 'self'
*/
next_ctx_arr_idx_ = TCPRS_LOCAL_CTX_METHODCTX + 1;
/* 'self' isn't valid yet */
self_valid_ = FALSE;
/* start at enum ID 1 (let 0 serve as an invalid value) */
next_enum_id_ = 1;
/* the '+' property is not yet defined */
plus_prop_ = 0;
/* no exported symbols yet */
exp_head_ = exp_tail_ = 0;
/* allocate an initial '+' stack */
plus_stack_alloc_ = 32;
plus_stack_ = (CTPNStmObject **)
t3malloc(plus_stack_alloc_ * sizeof(*plus_stack_));
/* clear out the stack */
for (i = 0 ; i < plus_stack_alloc_ ; ++i)
plus_stack_[i] = 0;
/* there's no current code body (function/method body) yet */
cur_code_body_ = 0;
/* nothing in the local context has been referenced yet */
self_referenced_ = FALSE;
local_ctx_needs_self_ = FALSE;
full_method_ctx_referenced_ = FALSE;
local_ctx_needs_full_method_ctx_ = FALSE;
/* create the embedded expression list object */
embed_toks_ = new CTcEmbedTokenList();
}
/*
* Add a special built-in property symbol
*/
CTcSymProp *CTcParser::def_special_prop(int def, const char *name,
tc_prop_id *idp)
{
/* we haven't created or found the property yet */
CTcSymProp *propsym = 0;
/* define or look up the property, as required */
if (def)
{
/* allocate the ID */
tctarg_prop_id_t id = G_cg->new_prop_id();
/* create the symbol */
propsym = new CTcSymProp(name, strlen(name), FALSE, id);
/* mark it as referenced, since the compiler itself uses it */
propsym->mark_referenced();
/* add it to the global symbol table */
global_symtab_->add_entry(propsym);
}
else
{
/* find the entry */
CTcSymbol *sym = global_symtab_->find(name, strlen(name));
/* check to see if we found a property symbol */
if (sym != 0 && sym->get_type() == TC_SYM_PROP)
{
/* got it - use the definition we found */
propsym = (CTcSymProp *)sym;
}
else
{
/* not found - create a dummy symbol for it */
propsym = new CTcSymProp(name, strlen(name), FALSE,
TCTARG_INVALID_PROP);
}
}
/* hand the property ID back to the caller if they want it */
if (idp != 0)
*idp = (propsym != 0 ? propsym->get_prop() : TCTARG_INVALID_PROP);
/* return the symbol */
return propsym;
}
/*
* Initialize. This must be called after the code generator is set up.
*/
void CTcParser::init()
{
/* define the special properties */
cache_special_props(TRUE);
}
/*
* Define or look up the special properties. If 'def' is true, we'll
* create definitions; otherwise we'll look up the definitions in the
* existing symbol table. The former case is for normal initialization of
* a new compiler; the latter is for use in dynamic compilation, where the
* global symbol table is provided by the running program.
*/
void CTcParser::cache_special_props(int def)
{
tc_prop_id propid;
/* add a "construct" property for constructors */
constructor_sym_ = def_special_prop(def, "construct", &constructor_prop_);
/* add a "finalize" property for finalizers */
def_special_prop(def, "finalize", &finalize_prop_);
/* add some properties for grammar production match objects */
graminfo_prop_ = def_special_prop(def, "grammarInfo");
gramtag_prop_ = def_special_prop(def, "grammarTag");
/* add a "miscVocab" property for miscellaneous vocabulary words */
def_special_prop(def, "miscVocab", &propid);
miscvocab_prop_ = (tc_prop_id)propid;
/* add a "lexicalParent" property for a nested object's parent */
lexical_parent_sym_ = def_special_prop(def, "lexicalParent");
/* add a "sourceTextOrder" property */
src_order_sym_ = def_special_prop(def, "sourceTextOrder");
/* start the sourceTextOrder index at 1 */
src_order_idx_ = 1;
/* add a "sourceTextGroup" property */
src_group_sym_ = def_special_prop(def, "sourceTextGroup");
/* we haven't created the sourceTextGroup referral object yet */
src_group_id_ = TCTARG_INVALID_OBJ;
/* add a "sourceTextGroupName" property */
src_group_mod_sym_ = def_special_prop(def, "sourceTextGroupName");
/* add a "sourceTextGroupOrder" property */
src_group_seq_sym_ = def_special_prop(def, "sourceTextGroupOrder");
/* define the operator overload properties */
ov_op_add_ = def_special_prop(def, "operator +");
ov_op_sub_ = def_special_prop(def, "operator -");
ov_op_mul_ = def_special_prop(def, "operator *");
ov_op_div_ = def_special_prop(def, "operator /");
ov_op_mod_ = def_special_prop(def, "operator %");
ov_op_xor_ = def_special_prop(def, "operator ^");
ov_op_shl_ = def_special_prop(def, "operator <<");
ov_op_ashr_ = def_special_prop(def, "operator >>");
ov_op_lshr_ = def_special_prop(def, "operator >>>");
ov_op_bnot_ = def_special_prop(def, "operator ~");
ov_op_bor_ = def_special_prop(def, "operator |");
ov_op_band_ = def_special_prop(def, "operator &");
ov_op_neg_ = def_special_prop(def, "operator negate");
ov_op_idx_ = def_special_prop(def, "operator []");
ov_op_setidx_ = def_special_prop(def, "operator []=");
}
/* get the grammarTag property ID */
tc_prop_id CTcParser::get_grammarTag_prop() const
{
return gramtag_prop_ != 0
? gramtag_prop_->get_prop()
: TCTARG_INVALID_PROP;
}
/* get the grammarInfo property ID */
tc_prop_id CTcParser::get_grammarInfo_prop() const
{
return graminfo_prop_ != 0
? graminfo_prop_->get_prop()
: TCTARG_INVALID_PROP;
}
/*
* destroy the parser
*/
CTcParser::~CTcParser()
{
/*
* Note that we don't have to delete certain objects, because we
* allocated them out of the parser memory pool and will be
* automatically deleted when the pool is deleted. For example, we
* don't have to delete any symbol tables, including the global
* symbol table.
*/
/* delete the module name, if it's known */
lib_free_str(module_name_);
/* delete the object file symbol fixup list, if present */
if (obj_sym_list_ != 0)
t3free(obj_sym_list_);
/* delete the object file dictionary fixup list, if present */
if (obj_dict_list_ != 0)
t3free(obj_dict_list_);
/* delete the context variable property list */
if (ctx_var_props_ != 0)
t3free(ctx_var_props_);
/* delete the export list */
while (exp_head_ != 0)
{
CTcPrsExport *nxt;
/* remember the next entry, since we're deleting our pointer to it */
nxt = exp_head_->get_next();
/* delete this entry */
delete exp_head_;
/* move on to the next */
exp_head_ = nxt;
}
/* delete the '+' stack */
t3free(plus_stack_);
/* delete the embedding look-ahead list */
delete embed_toks_;
}
/* ------------------------------------------------------------------------ */
/*
* Set the module information
*/
void CTcParser::set_module_info(const char *name, int seqno)
{
/* if we have a name stored already, delete the old one */
lib_free_str(module_name_);
/* store the new name and sequence number */
module_name_ = lib_copy_str(name);
module_seqno_ = seqno;
}
/*
* Change the #pragma C mode. On changing this mode, we'll change the
* assignment operator and equality operator tokens. If 'mode' is true,
* we're in C mode; otherwise, we're in traditional TADS mode.
*
* #pragma C+: assignment is '=', equality is '=='
*. #pragma C-: assignment is ':=', equality is '='.
*/
void CTcParser::set_pragma_c(int mode)
{
/* set the assignment operator */
S_op_asi.set_asi_op(mode ? TOKT_EQ : TOKT_ASI);
/* set the equality comparison operator */
S_op_eq.set_eq_op(mode ? TOKT_EQEQ : TOKT_EQ);
}
/*
* Parse an expression. This parses a top-level comma expression.
*/
CTcPrsNode *CTcParser::parse_expr()
{
/* parse a comma expression */
return S_op_comma.parse();
}
/*
* Parse a condition expression. Warns if the outermost operator is a
* simple assignment.
*/
CTcPrsNode *CTcParser::parse_cond_expr()
{
CTcPrsNode *cond;
/* parse the expression */
cond = parse_expr();
/*
* if the outermost operator is a simple assignment, display an
* error
*/
if (cond != 0 && cond->is_simple_asi() && !G_prs->get_syntax_only())
G_tok->log_warning(TCERR_ASI_IN_COND);
/* return the result */
return cond;
}
/*
* Parse an assignment expression.
*/
CTcPrsNode *CTcParser::parse_asi_expr()
{
/* parse an assignment expression */
return S_op_asi.parse();
}
/*
* Parse an expression or a double-quoted string expression
*/
CTcPrsNode *CTcParser::parse_expr_or_dstr(int allow_comma_expr)
{
/*
* parse the appropriate kind of expression - if a comma expression is
* allowed, parse that, otherwise parse an assignment expression (as
* that's the next thing down the hierarchy from the comma operator)
*/
return (allow_comma_expr ? S_op_comma.parse() : S_op_asi.parse());
}
/*
* Parse a required semicolon
*/
int CTcParser::parse_req_sem()
{
const char eof_str[] = "<end of file>";
/* check to see if we found the semicolon */
if (G_tok->cur() == TOKT_SEM)
{
/* success - skip the semicolon and tell the caller to proceed */
G_tok->next();
return 0;
}
/*
* check what we have; the type of error we want to log depends on
* what we find next
*/
switch(G_tok->cur())
{
case TOKT_RPAR:
/* log the extra ')' error */
G_tok->log_error(TCERR_EXTRA_RPAR);
/*
* we're probably in an expression that ended before the user
* thought it should; skip the extraneous material up to the
* next semicolon
*/
return skip_to_sem();
case TOKT_RBRACK:
/* log the error */
G_tok->log_error(TCERR_EXTRA_RBRACK);
/* skip up to the next semicolon */
return skip_to_sem();
case TOKT_EOF:
/*
* missing semicolon at end of file - log the missing-semicolon
* error and tell the caller not to proceed, since there's
* nothing left to parse
*/
G_tok->log_error(TCERR_EXPECTED_SEMI,
(int)sizeof(eof_str)-1, eof_str);
return 1;
default:
/*
* the source is probably just missing a semicolon; log the
* error, and tell the caller to proceed from the current
* position
*/
G_tok->log_error_curtok(TCERR_EXPECTED_SEMI);
return 0;
}
}
/*
* Skip to the next semicolon
*/
int CTcParser::skip_to_sem()
{
/* keep going until we find a semicolon or some other reason to stop */
for (;;)
{
/* see what we have next */
switch(G_tok->cur())
{
case TOKT_EOF:
/* end of file - tell the caller not to proceed */
return 1;
case TOKT_SEM:
/*
* it's the semicolon at last - skip it and tell the caller
* to proceed
*/
G_tok->next();
return 0;
case TOKT_LBRACE:
case TOKT_RBRACE:
/*
* Don't skip past braces - the caller probably simply left
* out a semicolon at the end of a statement, and we've now
* reached the next block start or end. Stop here and tell
* the caller to proceed.
*/
return 0;
default:
/* skip anything else */
G_tok->next();
break;
}
}
}
/*
* Parse an operator name. Call this when the current token is 'operator'
* and an operator name is expected. We'll fill in 'tok' with the pseudo
* property name of the operator ("operator +", etc).
*/
int CTcParser::parse_op_name(CTcToken *tok, int *op_argp)
{
const char *propname;
int ok = TRUE;
int op_args = 0;
/* get the actual operator */
switch (G_tok->next())
{
case TOKT_SYM:
/* check for named operators */
if (G_tok->getcur()->text_matches("negate"))
{
propname = "operator negate";
op_args = 1;
}
else
{
/* unknown symbolic operator name */
G_tok->log_error_curtok(TCERR_BAD_OP_OVERLOAD);
ok = FALSE;
propname = "unknown_operator";
}
break;
case TOKT_PLUS:
propname = "operator +";
op_args = 2;
break;
case TOKT_MINUS:
propname = "operator -";
op_args = 2;
break;
case TOKT_TIMES:
propname = "operator *";
op_args = 2;
break;
case TOKT_DIV:
propname = "operator /";
op_args = 2;
break;
case TOKT_MOD:
propname = "operator %";
op_args = 2;
break;
case TOKT_XOR:
propname = "operator ^";
op_args = 2;
break;
case TOKT_SHL:
propname = "operator <<";
op_args = 2;
break;
case TOKT_ASHR:
propname = "operator >>";
op_args = 2;
break;
case TOKT_LSHR:
propname = "operator >>>";
op_args = 2;
break;
case TOKT_BNOT:
propname = "operator ~";
op_args = 1;
break;
case TOKT_OR:
propname = "operator |";
op_args = 2;
break;
case TOKT_AND:
propname = "operator &";
op_args = 2;
break;
case TOKT_LBRACK:
/* we need at least a ']', and a '=' can follow */