1
/* $Header: d:/cvsroot/tads/tads3/tcprs.h,v 1.5 1999/07/11 00:46:58 MJRoberts Exp $ */
4
* Copyright (c) 1999, 2002 Michael J. Roberts. All Rights Reserved.
6
* Please see the accompanying license file, LICENSE.TXT, for information
7
* on using and copying this software.
11
tcprs.h - TADS 3 Compiler - parser
17
04/29/99 MJRoberts - Creation
33
/* ------------------------------------------------------------------------ */
37
typedef ulong tc_obj_id;
42
typedef uint tc_prop_id;
45
/* ------------------------------------------------------------------------ */
47
* scope data structure
51
/* local symbol table */
52
class CTcPrsSymtab *local_symtab;
54
/* enclosing scope's local symbol table */
55
class CTcPrsSymtab *enclosing_symtab;
57
/* number of locals allocated in scope */
61
/* ------------------------------------------------------------------------ */
63
* Code body parsing types. Each type of code body is essentially the
64
* same with minor variations, so we use a common code body parser that
65
* checks the parsing type to apply the variations.
67
enum tcprs_codebodytype
69
/* a standard function or method code body */
72
/* anonymous function */
75
/* short-form anonymous function */
76
TCPRS_CB_SHORT_ANON_FN
80
/* ------------------------------------------------------------------------ */
82
* the saved method context is always at index 1 in local variable context
83
* arrays, when we're using local variable context arrays
85
#define TCPRS_LOCAL_CTX_METHODCTX 1
88
/* ------------------------------------------------------------------------ */
98
/* initialize - call this after the code generator is set up */
102
* Set the module information. This tells us the module's name (as
103
* it's given in the makefile (.t3m) or library (.tl) file) and its
104
* sequence number (an ordinal giving its position in the list of
105
* modules making up the overall program build). We use this
106
* information in generating the sourceTextGroup object.
108
void set_module_info(const char *name, int seqno);
111
* Write an exported symbol file. An exported symbol file
112
* facilitates separate compilation by providing a listing of the
113
* symbols defined in another module. If module A depends on the
114
* symbols from module B, the user can first create an exported
115
* symbol file for module B, then can compile module A in the
116
* presence of B's symbol file, without actually loading B, and
117
* without manually entering a set of external definitions in module
120
void write_symbol_file(class CVmFile *fp, class CTcMake *make_obj);
123
* Seek to the start of the build configuration information in a symbol
124
* file. The return value is the number of bytes stored in the build
125
* configuration block; on return, the file object will have its seek
126
* offset set to the first byte of the build configuration data.
127
* Returns zero if the symbol file is invalid or does not contain any
128
* configuration data.
130
static ulong seek_sym_file_build_config_info(class CVmFile *fp);
133
* Write the global table to an object file.
135
void write_to_object_file(class CVmFile *fp);
138
* Read an object file and load it into the global symbol table. We
139
* will fill in the object and property ID translation tables
140
* provided with the translated values for the object and property
141
* symbols that we find in the object file.
143
* Returns zero on success; logs error messages and returns non-zero
144
* on error. Note that a non-zero value should be returned only
145
* when the file appears to be corrupted or an I/O error occurs;
146
* errors involving conflicting symbols, or other problems that do
147
* not prevent us from continuing to read the file in an orderly
148
* fashion, should not return failure but should simply log the
149
* error and continue; this way, we can detect any additional symbol
150
* conflicts or other errors. This routine should return failure
151
* only when it is not possible to continue reading the file.
153
int load_object_file(class CVmFile *fp,
154
const textchar_t *fname,
155
tctarg_obj_id_t *obj_xlat,
156
tctarg_prop_id_t *prop_xlat,
160
* Apply internal object/property ID fixups. This traverses the
161
* symbol table and calls each symbol's apply_internal_fixups()
162
* method. This can be called once after loading all object files.
164
void apply_internal_fixups();
167
* Read an exported symbol file. Reads the file and loads the
168
* global symbol table with the symbols in the file, with each
169
* symbol marked as external.
171
* This can be used for separate compilation. If module A depends
172
* on symbols in module B, first create a symbol file for module B,
173
* then module A can be compiled simply be pre-loading B's symbol
174
* file. Any symbol files that a module depends upon must be loaded
175
* before the module is compiled - symbol file loading must precede
178
* If any errors occur, we'll log the errors and return non-zero.
179
* We'll return zero on success.
181
int read_symbol_file(class CVmFile *fp);
183
/* get the global symbol table */
184
class CTcPrsSymtab *get_global_symtab() const { return global_symtab_; }
186
/* get the current local symbol table */
187
class CTcPrsSymtab *get_local_symtab() const { return local_symtab_; }
189
/* get the 'goto' symbol table */
190
class CTcPrsSymtab *get_goto_symtab() const { return goto_symtab_; }
192
/* set the current pragma C mode */
193
void set_pragma_c(int mode);
195
/* turn preprocess expression mode on or off */
196
void set_pp_expr_mode(int f) { pp_expr_mode_ = f; }
198
/* get the current preprocess expression mode flag */
199
int get_pp_expr_mode() const { return pp_expr_mode_; }
201
/* set/get the sourceTextGroup mode */
202
void set_source_text_group_mode(int f);
203
int get_source_text_group_mode() const { return src_group_mode_; }
205
/* get/set the syntax-only mode flag */
206
int get_syntax_only() const { return syntax_only_; }
207
void set_syntax_only(int f) { syntax_only_ = f; }
210
* Get the constructor and finalize property ID's - all constructors
211
* and finalizers have these property ID's respectively
213
tc_prop_id get_constructor_prop() const { return constructor_prop_; }
214
tc_prop_id get_finalize_prop() const { return finalize_prop_; }
216
/* get the constructor property symbol */
217
class CTcSymProp *get_constructor_sym() const { return constructor_sym_; }
219
/* get the object-call property */
220
tc_prop_id get_objcall_prop() const { return objcall_prop_; }
223
* Check for unresolved external symbols. Scans the global symbol
224
* table and logs an error for each unresolved external. Returns
225
* true if any unresolved externals exist, false if not.
227
int check_unresolved_externs();
230
* build the dictionaries - scans the global symbol table, and
231
* inserts each object symbol's dictionary words into its
232
* corresponding dictionary
234
void build_dictionaries();
236
/* build the grammar productions */
237
void build_grammar_productions();
240
* Top-level parser. Parse functions, objects, and other top-level
241
* definitions and declarations.
243
class CTPNStmProg *parse_top();
246
* Parse a required semicolon. If the semicolon is present, we'll
247
* simply skip it. If it's missing, we'll log an error and try to
248
* resynchronize. If we find something that looks like it should go
249
* at the end of an expression, we'll try to skip up to the next
250
* semicolon; otherwise, we'll simply stay put.
252
* Returns zero if the caller should proceed, non-zero if we're at
253
* end of file, in which case there's nothing more for the caller to
256
static int parse_req_sem();
259
* Skip to the next semicolon, ignoring any tokens up to that point.
260
* This can be used when the caller encounters an error that makes
261
* it impossible to process the current statement further, and wants
262
* to find the next semicolon in the hope that it will be a good
263
* place to start again with the next statement.
265
* Returns zero if the caller should proceed, non-zero if we reach
266
* the end of the file.
268
static int skip_to_sem();
271
* Parse an expression. This parses a top-level "comma" expression.
273
class CTcPrsNode *parse_expr();
276
* Parse a condition expression. This parses a top-level "comma"
277
* expression, but displays a warning if the outermost operator in
278
* the expression is an assignment, because such expressions are
279
* very frequently meant as comparisons, but the '=' operator was
280
* inadvertantly used instead of '=='.
282
class CTcPrsNode *parse_cond_expr();
285
* Parse a value expression or a double-quoted string expression
286
* (including a double-quoted string with embedded expressions). If
287
* allow_comma_expr is true, we'll parse a comma expression;
288
* otherwise, we'll parse an assignment expression. (A comma
289
* expression is broader than an assignment expression, since the
290
* comma separates assignment expressions.)
292
class CTcPrsNode *parse_expr_or_dstr(int allow_comma_expr);
295
* Parse an assignment expression - this is the next precedence
296
* level down from comma expressions. In certain contexts, a
297
* top-level comma expression is not allowed because a comma has a
298
* separate meaning (in the initializer clause of a 'for' statement,
299
* for example, or in a list element).
301
class CTcPrsNode *parse_asi_expr();
303
/* parse an 'enum' top-level statement */
304
void parse_enum(int *err);
306
/* parse a 'dictionary' top-level statement */
307
class CTPNStmTop *parse_dict(int *err);
309
/* parse a 'grammar' top-level statement */
310
class CTPNStmTop *parse_grammar(int *err, int replace, int modify);
312
/* parse and flatten a set of grammar rules */
313
class CTcPrsGramNode *flatten_gram_rule(int *err);
315
/* parse a 'grammar' OR node */
316
class CTcPrsGramNode *parse_gram_or(int *err, int level);
318
/* parse a 'grammar' CAT node */
319
class CTcPrsGramNode *parse_gram_cat(int *err, int level);
321
/* parse a 'grammar' qualifier int value */
322
int parse_gram_qual_int(int *err, const char *qual_name, int *stm_end);
324
/* skip to the end of a mal-formed grammar qualifier */
325
void parse_gram_qual_skip(int *err, int *stm_end);
328
* Parse a 'function' top-level statement. If 'is_extern' is true,
329
* the function is being defined externally, so it should have no
330
* code body defined here (just the prototype). If 'replace' is
331
* true, we're replacing an existing function.
333
* If 'func_kw_present' is true, the 'function' keyword is present
334
* and must be skipped; otherwise, the function definition elides
335
* the 'function' keyword and starts directly with the function name
338
class CTPNStmTop *parse_function(int *err, int is_extern,
339
int replace, int modify,
340
int func_kw_present);
342
/* parse an 'intrinsic' top-level statement */
343
class CTPNStmTop *parse_intrinsic(int *err);
345
/* parse an 'intrinsic class' top-level statement */
346
class CTPNStmTop *parse_intrinsic_class(int *err);
348
/* parse an 'extern' top-level statement */
349
void parse_extern(int *err);
352
* parse an object or function defintion (this is called when the
353
* first thing in a statement is a symbol; we must check what
354
* follows to determine what type of definition it is)
356
class CTPNStmTop *parse_object_or_func(int *err, int replace,
358
int *suppress_next_error);
360
/* parse a template definition statement */
361
class CTPNStmTop *parse_template_def(int *err,
362
const class CTcToken *class_tok);
364
/* add a template definition */
365
void add_template_def(class CTcSymObj *class_sym,
366
class CTcObjTemplateItem *item_head,
369
/* add inherited template definitions */
370
void add_inherited_templates(class CTcSymObj *sc_sym,
371
class CTcObjTemplateItem *item_head,
375
* expand the 'inherited' keyword in a template for the given
376
* superclass template and add the result to the template list for the
379
void expand_and_add_inherited_template(class CTcSymObj *sc_sym,
380
class CTcObjTemplateItem *items,
381
class CTcObjTemplate *sc_tpl);
384
* build a list of superclass templates, for expanding an 'inherited'
385
* token in a template definition
387
void build_super_template_list(struct inh_tpl_entry **list_head,
388
struct inh_tpl_entry **list_tail,
389
class CTcSymObj *sc_sym);
391
/* parse an 'object' statement */
392
class CTPNStmTop *parse_object_stm(int *err, int is_transient);
395
* parse an object definition that starts with a '+' string; this
396
* also parses '+ property' statements
398
class CTPNStmTop *parse_plus_object(int *err);
401
* Parse an object definition. If 'replace' is true, this
402
* definition is to replace a previous definition of the same
403
* object; if 'modify' is true, this definition is to modify a
404
* previous definition. If 'is_class' is true, the definition is
405
* for a class, otherwise it's for a static instance.
407
* If the definition uses the '+' notation to set the location,
408
* plus_cnt gives the number of '+' signs preceding the object
411
class CTPNStmTop *parse_object(int *err, int replace, int modify,
412
int is_class, int plus_cnt,
415
/* find or define an object symbol */
416
CTcSymObj *find_or_def_obj(const char *tok_txt, size_t tok_len,
417
int replace, int modify, int *is_class,
418
class CTcSymObj **mod_orig_sym,
419
class CTcSymMetaclass **meta_sym,
422
/* parse an anonymous object */
423
class CTPNStmObject *parse_anon_object(int *err, int plus_cnt,
425
struct tcprs_term_info *term_info,
429
* Parse an object body. We start parsing from the colon that
430
* introduces the class list, and parse the class list and the
431
* property list for the object.
433
* If 'is_anon' is true, this is an anonymous object. 'obj_sym'
434
* should be null in this case.
436
* If 'is_nested' is true, this is a nested object defined in-line in
437
* an object's property list. Note that is_nested implies is_anon,
438
* since nested objects are always anonymous.
440
* If this is a 'modify' definition, 'mod_orig_tok' should be set up
441
* with the synthesized symbol for the modified base object;
442
* otherwise, 'mod_orig_tok' should be null.
444
* If 'meta_sym' is non-null, we're modifying an intrinsic class.
445
* This imposes certain restrictions; in particular, we cannot modify
446
* a method defined in the native interface to the class.
448
class CTPNStmObject *parse_object_body(int *err, class CTcSymObj *obj_sym,
449
int is_class, int is_anon,
451
int is_nested, int modify,
452
class CTcSymObj *mod_orig_sym,
454
class CTcSymMetaclass *meta_sym,
455
struct tcprs_term_info *term_info,
458
/* parse an object template instance in an object body */
459
void parse_obj_template(int *err, class CTPNStmObject *obj_stm);
461
/* search a superclass list for a template match */
462
const class CTcObjTemplate
463
*find_class_template(const class CTPNSuperclass *first_sc,
464
class CTcObjTemplateInst *src,
465
size_t src_cnt, const CTPNSuperclass **def_sc,
466
int *undescribed_class);
468
/* find a match for a given template in the given list */
469
const class CTcObjTemplate
470
*find_template_match(const class CTcObjTemplate *first_tpl,
471
class CTcObjTemplateInst *src,
475
* Match a template to a given actual template parameter list. Returns
476
* true if we match, false if not. We'll fill in the actual list with
477
* the property symbols that we matched; these values are only
478
* meaningful if we return true to indicate a match.
480
int match_template(const class CTcObjTemplateItem *tpl_head,
481
class CTcObjTemplateInst *src, size_t src_cnt);
483
/* parse property definition within an object */
484
void parse_obj_prop(int *err, class CTPNStmObject *obj_stm, int replace,
485
class CTcSymMetaclass *meta_sym,
486
struct tcprs_term_info *term_info,
487
struct propset_def *propset_stack, int propset_depth,
488
int enclosing_obj_is_nested);
490
/* parse a class definition */
491
class CTPNStmTop *parse_class(int *err);
493
/* parse a 'modify' definition */
494
class CTPNStmTop *parse_modify(int *err);
496
/* parse a 'replace' definition */
497
class CTPNStmTop *parse_replace(int *err);
499
/* parse a 'property' statement */
500
void parse_property(int *err);
502
/* parse an 'export' statement */
503
void parse_export(int *err);
505
/* add an export for the given symbol; returns the new export record */
506
class CTcPrsExport *add_export(const char *sym, size_t sym_len);
508
/* add an export record to our list */
509
void add_export_to_list(class CTcPrsExport *exp);
511
/* get the head of the export list */
512
class CTcPrsExport *get_exp_head() const { return exp_head_; }
515
* Parse a function or method body, starting with the formal parameter
516
* list. If 'eq_before_brace' is set, we expect an '=' before the
517
* opening brace of the code body, and we allow the expression syntax,
518
* where an expression enclosed in parentheses can be used.
519
* 'self_valid' indicates whether or not 'self' is valid in the context
520
* of the code being compiled; for an object method, 'self' is usually
521
* valid, while for a stand-alone function it isn't.
523
class CTPNCodeBody *parse_code_body(int eq_before_brace, int is_obj_prop,
525
int *p_argc, int *p_varargs,
528
p_varargs_list_local,
529
int *has_retval, int *err,
530
class CTcPrsSymtab *local_symtab,
531
tcprs_codebodytype cb_type,
532
struct propset_def *propset_stack,
534
struct CTcCodeBodyRef *enclosing,
535
class CTcFormalTypeList **type_list);
537
/* parse a nested code body (such as an anonymous function) */
538
class CTPNCodeBody *parse_nested_code_body(
541
int *p_argc, int *p_varargs,
543
class CTcSymLocal **p_varargs_list_local,
544
int *has_retval, int *err,
545
class CTcPrsSymtab *local_symtab,
546
tcprs_codebodytype cb_type);
548
/* parse a formal parameter list */
549
void parse_formal_list(int count_only, int opt_allowed,
550
int *argc, int *opt_argc, int *varargs,
552
class CTcSymLocal **varargs_list_local,
553
int *err, int base_formal_num,
554
int for_short_anon_func,
555
class CTcFormalTypeList **type_list);
558
* Parse a compound statement. The caller must skip the opening
559
* '{'; on return, we'll have skipped the closing '}'.
560
* enclosing_symtab is the enclosing scope's symbol table, and
561
* local_symtab is the symbol table for the new scope within the
562
* compound statement; if the caller has not already allocated a new
563
* symbol table for the inner scope, it should simply pass the same
564
* value for both symbol tables.
566
* 'enclosing_switch' is the immediately enclosing switch statement,
567
* if any. This is only set when we're parsing the immediate body
568
* of a switch statement.
570
class CTPNStmComp *parse_compound(int *err, int skip_lbrace,
571
class CTPNStmSwitch *enclosing_switch,
572
int use_enclosing_scope);
574
/* parse a local variable definition */
575
class CTPNStm *parse_local(int *err);
577
/* parse a local initializer */
578
class CTcPrsNode *parse_local_initializer(class CTcSymLocal *lcl,
582
* Parse an individual statement.
584
* If 'compound_use_enclosing_scope' is true, then if the statement
585
* is a compound statement (i.e., the current token is a left
586
* brace), the compound statement will use the current scope rather
587
* than creating its own scope. Normally, a compound statement
588
* establishes its own scope, so that local variables can hide
589
* locals and parameters defined outside the braces. In certain
590
* cases, however, locals defined within the braces should share the
591
* enclosing scope: at the top level of a function or method, for
592
* example, the formal parameters and the locals within the function
593
* body go in the same scope, so the function body's compound
594
* statement doesn't create its own scope.
596
class CTPNStm *parse_stm(int *err, class CTPNStmSwitch *enclosing_switch,
597
int compound_use_enclosing_scope);
599
/* parse a 'case' label */
600
class CTPNStm *parse_case(int *err,
601
class CTPNStmSwitch *enclosing_switch);
603
/* parse a 'default' label */
604
class CTPNStm *parse_default(int *err,
605
class CTPNStmSwitch *enclosing_switch);
607
/* parse an 'if' statement */
608
class CTPNStm *parse_if(int *err);
610
/* parse a 'return' statement */
611
class CTPNStm *parse_return(int *err);
613
/* parse a 'for' statement */
614
class CTPNStm *parse_for(int *err);
616
/* parse a 'foreach' statement */
617
class CTPNStm *parse_foreach(int *err);
619
/* parse a 'break' statement */
620
class CTPNStm *parse_break(int *err);
622
/* parse a 'continue' statement */
623
class CTPNStm *parse_continue(int *err);
625
/* parse a 'while' */
626
class CTPNStm *parse_while(int *err);
628
/* parse a 'do-while' */
629
class CTPNStm *parse_do_while(int *err);
631
/* parse a 'switch' */
632
class CTPNStm *parse_switch(int *err);
635
class CTPNStm *parse_goto(int *err);
638
class CTPNStm *parse_try(int *err);
640
/* parse a 'throw' */
641
class CTPNStm *parse_throw(int *err);
644
* Create a symbol node. We'll look up the symbol in local scope.
645
* If we find the symbol in local scope, we'll return a resolved
646
* symbol node for the local scope item. If the symbol isn't
647
* defined in local scope, we'll return an unresolved symbol node,
648
* so that the symbol's resolution can be deferred until code
651
class CTcPrsNode *create_sym_node(const textchar_t *sym, size_t sym_len);
654
* Get the source file descriptor and line number for the current
655
* source line. We note this at the start of each statement, so
656
* that a statement node constructed when we finish parsing the
657
* statement can record the location of the start of the statement.
659
class CTcTokFileDesc *get_cur_desc() const { return cur_desc_; }
660
long get_cur_linenum() const { return cur_linenum_; }
663
* Get/set the current enclosing statement. An enclosing statement
664
* is a 'try' or 'label:' container. At certain times, we need to
665
* know the current enclosing statement, or one of its enclosing
666
* statements; for example, a 'break' with a label must find the
667
* label in the enclosing statement list to know where to jump to
668
* after the 'break', and must also know about all of the enclosing
669
* 'try' blocks our to that point so that it can invoke their
672
class CTPNStmEnclosing *get_enclosing_stm() const
673
{ return enclosing_stm_; }
674
class CTPNStmEnclosing *set_enclosing_stm(class CTPNStmEnclosing *stm)
676
class CTPNStmEnclosing *old_enclosing;
678
/* remember the current enclosing statement for a moment */
679
old_enclosing = enclosing_stm_;
681
/* set the new enclosing statement */
682
enclosing_stm_ = stm;
685
* return the previous enclosing statement - this allows the
686
* caller to restore the previous enclosing statement upon
687
* leaving a nested block, if that's why the caller is setting a
688
* new enclosing statement
690
return old_enclosing;
693
/* get the current code body reference object */
694
struct CTcCodeBodyRef *get_cur_code_body() const
695
{ return cur_code_body_; }
697
/* determine if 'self' is valid in the current context */
698
int is_self_valid() const { return self_valid_; }
701
* get/set the 'self' reference status - this indicates whether or not
702
* 'self' has been referenced, explicitly via the 'self'
703
* pseudo-variable or implicitly (such as via a property reference or
704
* method call), in the code body currently being parsed
706
int self_referenced() const { return self_referenced_; }
707
void set_self_referenced(int f) { self_referenced_ = f; }
710
* get/set the full method context reference status - this indicates
711
* whether or not any of the method context variables (self,
712
* targetprop, targetobj, definingobj) have been referenced, explicitly
713
* or implicitly, in the code body currently being parsed
715
int full_method_ctx_referenced() const
716
{ return full_method_ctx_referenced_; }
717
void set_full_method_ctx_referenced(int f)
718
{ full_method_ctx_referenced_ = f; }
721
* Get/set the flag indicating whether or not the local context of the
722
* outermost code body needs 'self'. The outer code body needs 'self'
723
* in the local context if any lexically nested code body requires
726
int local_ctx_needs_self() const { return local_ctx_needs_self_; }
727
void set_local_ctx_needs_self(int f) { local_ctx_needs_self_ = f; }
730
* Get/set the flag indicating whether or not the local context of the
731
* outermost code body needs the full method context stored in its
732
* local context. The outer code body needs the full context stored if
733
* any lexically nested code body requires access to any of the method
734
* context variables besides 'self' (targetprop, targetobj,
737
int local_ctx_needs_full_method_ctx() const
738
{ return local_ctx_needs_full_method_ctx_; }
739
void set_local_ctx_needs_full_method_ctx(int f)
740
{ local_ctx_needs_full_method_ctx_ = f; }
743
* Add a code label. This creates a 'goto' symbol table for the
744
* current code body if one doesn't already exist
746
class CTcSymLabel *add_code_label(const class CTcToken *tok);
749
* Set the debugger local symbol table. Returns the previous symbol
750
* table so that it can be restored if desired.
752
class CTcPrsDbgSymtab *set_debug_symtab(class CTcPrsDbgSymtab *tab)
754
class CTcPrsDbgSymtab *old_tab;
756
/* remember the original for later use */
757
old_tab = debug_symtab_;
759
/* set the new table */
762
/* return the original */
767
* given a (1-based) object file symbol index, get the symbol
769
class CTcSymbol *get_objfile_sym(uint idx)
770
{ return (idx == 0 ? 0 : obj_sym_list_[idx - 1]); }
773
* given a 1-based object file symbol index, get an object symbol;
774
* if the symbol does not refer to an object, we'll return null
776
class CTcSymObj *get_objfile_objsym(uint idx);
779
* given an object file (1-based) object file dictionary index, get
780
* the dictionary entry
782
class CTcDictEntry *get_obj_dict(uint idx)
783
{ return (idx == 0 ? 0 : obj_dict_list_[idx - 1]); }
785
/* add a dictionary object loaded from the object file */
786
void add_dict_from_obj_file(class CTcSymObj *sym);
788
/* add a symbol object loaded from the object file */
789
void add_sym_from_obj_file(uint idx, class CTcSymbol *sym);
792
* Get the next object file symbol index. Object file symbol
793
* indices are used to relate symbols stored in the object file to
794
* the corresponding symbol object in memory when the object file is
797
uint get_next_obj_file_sym_idx()
799
/* return the next index, consuming the index value */
800
return obj_file_sym_idx_++;
804
* Get the next object file dictionary index.
806
uint get_next_obj_file_dict_idx()
808
/* return the next index, consuming the index value */
809
return obj_file_dict_idx_++;
813
* add an anonymous function or other anonymous top-level statement
814
* to our list of nested top-level statements
816
void add_nested_stm(class CTPNStmTop *stm);
818
/* add an anonymous object to our list */
819
void add_anon_obj(class CTcSymObj *obj);
821
/* add a non-symbolic object ID */
822
void add_nonsym_obj(tctarg_obj_id_t id);
824
/* determine if the current code body has a local context */
825
int has_local_ctx() const { return has_local_ctx_ != 0; }
827
/* get the local context variable number */
828
int get_local_ctx_var() const { return local_ctx_var_num_; }
830
/* set up a local context */
831
void init_local_ctx();
833
/* allocate a context variable property ID */
834
tctarg_prop_id_t alloc_ctx_var_prop();
837
* allocate a context variable index - this assigns an array index
838
* for a context variable within the context object that contains
839
* the shared locals for its scope
841
int alloc_ctx_arr_idx();
843
/* allocate a local for use as a local context holder */
844
int alloc_ctx_holder_var() { return alloc_local(); }
846
/* get the maximum number of locals required in the function */
847
int get_max_local_cnt() const { return max_local_cnt_; }
850
* find a grammar production symbol, adding a new one if needed,
851
* returning the grammar production list entry for the object
853
class CTcGramProdEntry *declare_gramprod(const char *sym, size_t len);
855
/* find a grammar production list entry for a given object */
856
class CTcGramProdEntry *get_gramprod_entry(class CTcSymObj *sym);
858
/* find a grammar production symbol, adding a new one if needed */
859
class CTcSymObj *find_or_def_gramprod(const char *txt, size_t len,
860
class CTcGramProdEntry **entryp);
862
/* allocate a new enumerator ID */
863
ulong new_enum_id() { return next_enum_id_++; }
865
/* get the number of enumerator ID's allocated */
866
ulong get_enum_count() const { return next_enum_id_; }
869
* Look up a property symbol, adding it if not yet defined. If the
870
* symbol is defined as another type, we'll show an error if
871
* show_err is true, and return null.
873
CTcSymProp *look_up_prop(const class CTcToken *tok, int show_err);
875
/* get the '+' property for tracking the location graph */
876
CTcSymProp *get_plus_prop() const { return plus_prop_; }
879
* Read a length-prefixed string from a file. Copies the string into
880
* tokenizer space (which is guaranteed valid throughout compilation),
881
* and returns a pointer to the tokenizer copy. If ret_len is null,
882
* we'll return a null-terminated string; otherwise, we'll return a
883
* non-null-terminated string and set *ret_len to the length of the
886
* The string must fit in the temporary buffer to be read, but the
887
* permanent tokenizer copy is returned rather than the temp buffer.
888
* If the string doesn't fit in the temp buffer (with null
889
* termination, if null termination is requested), we'll log the given
892
static const char *read_len_prefix_str
893
(CVmFile *fp, char *tmp_buf, size_t tmp_buf_len, size_t *ret_len,
894
int err_if_too_long);
897
* Read a length-prefixed string into the given buffer, null
898
* terminating the result. If the string is too long for the buffer,
899
* we'll flag the given error code and return non-zero. If
900
* successful, we'll return zero.
902
static int read_len_prefix_str(CVmFile *fp, char *buf, size_t buf_len,
903
int err_if_too_long);
906
/* get the miscVocab property symbol */
907
tctarg_prop_id_t get_miscvocab_prop() const { return miscvocab_prop_; }
910
/* clear the anonymous function local context information */
911
void clear_local_ctx();
914
* begin a property expression, saving parser state for later
915
* restoration with finish_prop_expr
917
void begin_prop_expr(class CTcPrsPropExprSave *save_info);
920
* Finish a property expression, wrapping it in a code body if
921
* necessary to allow for an embedded anonymous function. Returns
922
* null if no wrapping is required, in which case the original
923
* expression should continue to be used, or the non-null code body
924
* wrapper if needed, in which case the original expression should be
925
* discarded in favor of the fully wrapped code body.
927
class CTPNCodeBody *finish_prop_expr(class CTcPrsPropExprSave *save_info,
928
class CTcPrsNode *expr,
930
class CTcSymProp *prop_sym);
933
* callback for symbol table enumeration for writing a symbol export
936
static void write_sym_cb(void *ctx, class CTcSymbol *sym);
938
/* callback for symbol table enumeration for writing an object file */
939
static void write_obj_cb(void *ctx, class CTcSymbol *sym);
941
/* callback for symbol table enumeration for writing cross references */
942
static void write_obj_ref_cb(void *ctx, class CTcSymbol *sym);
944
/* callback for symbol table enumeration for named grammar rules */
945
static void write_obj_gram_cb(void *ctx, class CTcSymbol *sym);
947
/* callback for symbol table enumeration for merging grammar rules */
948
static void build_grammar_cb(void *ctx, class CTcSymbol *sym);
952
* Enter a scope. Upon entering, we'll remember the current local
953
* variable data; on leaving, we'll restore the enclosing scope.
955
void enter_scope(struct tcprs_scope_t *info)
957
/* remember the current scope information */
958
info->local_symtab = local_symtab_;
959
info->enclosing_symtab = enclosing_local_symtab_;
960
info->local_cnt = local_cnt_;
963
* We haven't yet allocated a symbol table local to the new
964
* scope -- we defer this until we actually need to insert a
965
* symbol into the new scope. In order to detect when we need
966
* to create our own local symbol table, we keep track of the
967
* enclosing symbol table; when the local table is the same as
968
* the enclosing table, and we need to insert a symbol, it means
969
* that we must create a new table for the current scope.
971
enclosing_local_symtab_ = local_symtab_;
975
void leave_scope(struct tcprs_scope_t *info)
977
/* restore enclosing scope information */
978
local_symtab_ = info->local_symtab;
979
enclosing_local_symtab_ = info->enclosing_symtab;
981
/* return to the local count in the enclosing scope */
982
// $$$ we can't actually do this because variables could
983
// be allocated after this scope ends, but need lifetimes
984
// that overlap with the enclosed scope; what we actually
985
// need to do, if we wanted to optimize things, would be
986
// to allow this block of variables to be used in *disjoint*
987
// scopes, but not again in enclosing scopes. We can easily,
988
// though suboptimally, handle this by simply not allowing
989
// the variables in the enclosed scope to be re-used at all
990
// in the current code block.
991
// local_cnt_ = info->local_cnt;
995
* Create a local symbol table in the current scope, if necessary.
996
* If we've already created a local symbol table for the current
997
* scope, this has no effect.
999
void create_scope_local_symtab();
1001
/* allocate a new local variable ID */
1005
* if this exceeds the maximum depth in the block so far, note
1006
* the new maximum depth
1008
if (local_cnt_ + 1 > max_local_cnt_)
1009
max_local_cnt_ = local_cnt_ + 1;
1011
/* return the local number, and increment the counter */
1012
return local_cnt_++;
1015
/* find a dictionary symbol, adding a new one if needed */
1016
class CTcDictEntry *declare_dict(const char *sym, size_t len);
1018
/* create a new dictionary list entry */
1019
class CTcDictEntry *create_dict_entry(class CTcSymObj *sym);
1021
/* find a dictionary list entry for a given object */
1022
class CTcDictEntry *get_dict_entry(class CTcSymObj *sym);
1024
/* create a new grammar production list entry */
1025
class CTcGramProdEntry *create_gramprod_entry(class CTcSymObj *sym);
1027
/* symbol enumerator - look for unresolved external references */
1028
static void enum_sym_extref(void *ctx, class CTcSymbol *sym);
1030
/* symbol enumerator - apply internal fixups */
1031
static void enum_sym_internal_fixup(void *ctx, class CTcSymbol *sym);
1033
/* symbol enumerator - build dictionary */
1034
static void enum_sym_dict(void *ctx, class CTcSymbol *sym);
1036
/* enumeration callback - context local conversion */
1037
static void enum_for_ctx_locals(void *ctx, class CTcSymbol *sym);
1039
/* global symbol table */
1040
class CTcPrsSymtab *global_symtab_;
1042
/* the constructor property ID and symbol */
1043
tc_prop_id constructor_prop_;
1044
class CTcSymProp *constructor_sym_;
1046
/* the finalizer property ID */
1047
tc_prop_id finalize_prop_;
1049
/* object-call property ID */
1050
tc_prop_id objcall_prop_;
1052
/* grammarInfo property symbol */
1053
class CTcSymProp *graminfo_prop_;
1055
/* miscVocab property ID */
1056
tctarg_prop_id_t miscvocab_prop_;
1058
/* lexicalParent property symbol */
1059
class CTcSymProp *lexical_parent_sym_;
1061
/* sourceTextOrder property symbol */
1062
class CTcSymProp *src_order_sym_;
1064
/* sourceTextGroup property symbol */
1065
class CTcSymProp *src_group_sym_;
1067
/* sourceTextGroupName, sourceTextGroupOrder */
1068
class CTcSymProp *src_group_mod_sym_;
1069
class CTcSymProp *src_group_seq_sym_;
1073
* Source text order index. Each time we encounter an object
1074
* definition in the source code, we assign the current index value to
1075
* the object's 'sourceTextOrder' property, then we increment the
1076
* index. This provides the game program with information on the order
1077
* in which static objects appear in the source code, so that the
1078
* program can sort a collection of objects into their source file
1081
long src_order_idx_;
1084
* Source group object. If we're assigning source text group values,
1085
* we create an object for each source module to identify the module.
1087
tctarg_obj_id_t src_group_id_;
1090
* flag: in preprocessor constant expression mode; double-quoted
1091
* strings should be treated the same as single-quoted strings for
1092
* concatenation and comparisons
1094
uint pp_expr_mode_ : 1;
1097
* Is source text mode turned on? If this is true, we'll generate
1098
* sourceTextGroup properties for objects, otherwise we won't.
1100
uint src_group_mode_ : 1;
1103
* Flag: syntax-only mode. We use this mode to analyze the syntax
1104
* of the file without building the image; this is used, for
1105
* example, to build the exported symbol file for a source file. In
1106
* this mode, we'll suppress certain warnings and avoid doing work
1107
* that's not necessary for syntactic analysis; for example, we
1108
* won't show "unreachable code" errors.
1110
uint syntax_only_ : 1;
1113
* Code block parsing state
1117
* 'goto' symbol table for the current code block - there's only one
1118
* 'goto' scope for an entire code block, so this never changes over
1119
* the course of a code block
1121
class CTcPrsSymtab *goto_symtab_;
1124
* Current local symbol table. Each inner scope that defines its
1125
* own local variables has its own local symbol table, nested within
1126
* the enclosing scope's. When leaving an inner scope, this should
1127
* always be restored to the local symbol table of the enclosing
1130
class CTcPrsSymtab *local_symtab_;
1133
* Enclosing local symbol table. If this is the same as
1134
* local_symtab_, it means that the current scope has not yet
1135
* created its own local symbol table. We defer this creation until
1136
* we find we actually need a local symbol table in a scope, since
1137
* most scopes don't define any of their own local variables.
1139
class CTcPrsSymtab *enclosing_local_symtab_;
1142
* Current debugger local symbol table. When we're compiling a
1143
* debugger expression, this will provide access to the current
1144
* local scope in the debug records.
1146
class CTcPrsDbgSymtab *debug_symtab_;
1149
* Number of local variables allocated so far in current code block
1150
* -- this reflects nesting to the current innermost scope, because
1151
* variables in inner scope are allocated in the same stack frame as
1152
* the enclosing scopes. When leaving an inner scope, this should
1158
* maximum local variable depth for the current code block -- this
1159
* reflects the maximum depth, including all inner scopes so far
1164
* Enclosing statement - this is the innermost 'try' or 'label:'
1165
* enclosing the current code.
1167
class CTPNStmEnclosing *enclosing_stm_;
1169
/* file descriptor and line number at start of current statement */
1170
class CTcTokFileDesc *cur_desc_;
1173
/* currently active dictionary */
1174
class CTcDictEntry *dict_cur_;
1176
/* head and tail of dictionary list */
1177
class CTcDictEntry *dict_head_;
1178
class CTcDictEntry *dict_tail_;
1180
/* head and tail of grammar production entry list */
1181
class CTcGramProdEntry *gramprod_head_;
1182
class CTcGramProdEntry *gramprod_tail_;
1185
* array of symbols loaded from the object file - these are indexed
1186
* by the object file symbol index stored in symbol references in
1187
* the object file, allowing us to fix up references from one symbol
1188
* to another during loading
1190
class CTcSymbol **obj_sym_list_;
1193
* array of dictionary objects for the object file being loaded -
1194
* these are indexed by the dictionary index stored in symbol
1195
* references in the object file, allowing us to fix up references
1196
* from an object to its dictionary
1198
class CTcDictEntry **obj_dict_list_;
1200
/* next available object file dictionary index */
1201
uint obj_file_dict_idx_;
1203
/* next available object file symbol index */
1204
uint obj_file_sym_idx_;
1206
/* dictionary property list head */
1207
class CTcDictPropEntry *dict_prop_head_;
1210
* Head and tail of list of nested top-level statements parsed for the
1211
* current top-level statement. This list includes anonymous
1212
* functions and nested objects, since these statements must
1213
* ultimately be linked into the top-level statement queue, but can't
1214
* be linked in while they're being parsed because of their nested
1215
* location in the recursive descent. We'll throw each new nested
1216
* top-level statement into this list as we parse them, then add this
1217
* list to the top-level statement list when we're done with the
1220
class CTPNStmTop *nested_stm_head_;
1221
class CTPNStmTop *nested_stm_tail_;
1224
* Anonymous object list. This is a list of objects which are
1225
* defined without symbol names.
1227
class CTcSymObj *anon_obj_head_;
1228
class CTcSymObj *anon_obj_tail_;
1231
* Non-symbolic object list. This is a list of objects that are
1232
* defined without symbols at all.
1234
struct tcprs_nonsym_obj *nonsym_obj_head_;
1235
struct tcprs_nonsym_obj *nonsym_obj_tail_;
1238
* Object template list - this is the master list of templates for the
1239
* root object class.
1241
class CTcObjTemplate *template_head_;
1242
class CTcObjTemplate *template_tail_;
1245
* Object template instance parsing expression array. Each time we
1246
* define a new template, we'll make sure this array is long enough
1247
* for the longest defined template. We use this list when we're
1248
* parsing a template instance to keep track of the expressions in
1249
* the template instance - we can't know until we have the entire
1250
* list which template we're using, so we must keep track of the
1251
* entire list until we reach the end of the list.
1253
class CTcObjTemplateInst *template_expr_;
1254
size_t template_expr_max_;
1256
/* head and tail of exported symbol list */
1257
class CTcPrsExport *exp_head_;
1258
class CTcPrsExport *exp_tail_;
1261
* Flag: current code body has a local variable context object. If
1262
* this is set, we must generate code that sets up the context
1263
* object on entry to the code body.
1265
unsigned int has_local_ctx_ : 1;
1267
/* local variable number of the code body's local variable context */
1268
int local_ctx_var_num_;
1270
/* array of context variable property values */
1271
tctarg_prop_id_t *ctx_var_props_;
1274
size_t ctx_var_props_size_;
1276
/* number of context variable property values in the list */
1277
size_t ctx_var_props_cnt_;
1280
* number of context variable property values assigned to the
1283
size_t ctx_var_props_used_;
1285
/* next available local variable context index */
1286
int next_ctx_arr_idx_;
1288
/* reference to the current code body being parsed */
1289
CTcCodeBodyRef *cur_code_body_;
1291
/* flag: 'self' is valid in current code body */
1295
* flag: 'self' is used (explicitly or implicitly, such as via a
1296
* property reference or method call) in the current code body
1298
int self_referenced_;
1301
* Flag: method context beyond 'self' (targetprop, targetobj,
1302
* definingobj) is referenced (explicitly or implicitly, such as via
1303
* 'inherited' or 'delegated') in the current code body.
1305
int full_method_ctx_referenced_;
1308
* Flags: the local context of the outermost code body requires
1309
* 'self'/the full method context to be stored.
1311
int local_ctx_needs_self_;
1312
int local_ctx_needs_full_method_ctx_;
1314
/* next available enumerator ID */
1315
ulong next_enum_id_;
1318
* The '+' property - this is the property that defines the
1319
* containment graph for the purposes of the '+' syntax.
1321
class CTcSymProp *plus_prop_;
1324
* '+' property location stack. Each time the program defines an
1325
* object using the '+' notation to set the location, we'll update our
1326
* record here of the last object at that depth. Any time an object
1327
* is defined at depth N (i.e., using N '+' signs), its location is
1328
* set to the last object at depth N-1. An object with no '+' signs
1331
class CTPNStmObject **plus_stack_;
1332
size_t plus_stack_alloc_;
1335
* The module name and sequence number, if known. The module name is
1336
* the name as it appears on the command line, makefile (.t3m), or
1337
* library (.tl) file. The sequence number is an ordinal giving its
1338
* position in the list of modules making up the overall program build.
1339
* We use this information in generating the sourceTextGroup object.
1345
/* ------------------------------------------------------------------------ */
1347
* Statement termination information. This is used for certain nested
1348
* definition parsers, where a lack of termination in the nested
1349
* definition is to be interpreted as being actually caused by a lack of
1350
* termination of the enclosing definition.
1352
struct tcprs_term_info
1355
void init(class CTcTokFileDesc *desc, long linenum)
1357
/* remember the current location */
1361
/* no termination error yet */
1366
* source location where original terminator might have been - this is
1367
* where we decided to go into a nested definition, so if it turns out
1368
* that the definintion shouldn't have been nested after all, there
1369
* was missing termination here
1371
class CTcTokFileDesc *desc_;
1375
* flag: termination was in fact missing in the nested definition; the
1376
* nested parser sets this to relay the problem to the caller
1381
/* ------------------------------------------------------------------------ */
1383
* Object template list entry
1385
class CTcObjTemplate
1388
CTcObjTemplate(class CTcObjTemplateItem *item_head, size_t item_cnt)
1390
/* remember my item list */
1392
item_cnt_ = item_cnt;
1394
/* not in a list yet */
1398
/* head of list of template items */
1399
class CTcObjTemplateItem *items_;
1401
/* number of items in the list */
1404
/* next template in master list of templates */
1405
CTcObjTemplate *nxt_;
1409
* Object template list item
1411
class CTcObjTemplateItem
1414
CTcObjTemplateItem(class CTcSymProp *prop, tc_toktyp_t tok_type,
1415
int is_alt, int is_opt)
1417
/* remember my defining information */
1419
tok_type_ = tok_type;
1423
/* not in a list yet */
1427
/* property that the item in this position defines */
1428
class CTcSymProp *prop_;
1430
/* token type of item in this position */
1431
tc_toktyp_t tok_type_;
1433
/* next item in this template's item list */
1434
CTcObjTemplateItem *nxt_;
1436
/* flag: this item is an alternative to the previous item */
1437
unsigned int is_alt_ : 1;
1439
/* flag: this item is optional */
1440
unsigned int is_opt_ : 1;
1444
* Template item instance - we keep track of the actual parameters to a
1445
* template with these items.
1447
class CTcObjTemplateInst
1451
* expression value for the actual parameter, as either a naked
1452
* expression (expr_) or as a code body (code_body_) - only one of
1453
* expr_ or code_body_ will be valid
1455
class CTcPrsNode *expr_;
1456
class CTPNCodeBody *code_body_;
1459
* the introductory token of the parameter - if the parameter is
1460
* introduced by an operator token, this will not be part of the
1463
tc_toktyp_t def_tok_;
1465
/* the first token of the value */
1469
* The property to which to assign this actual parameter value. This
1470
* isn't filled in until we match the full list to an actual template,
1471
* since we don't know the meanings of the parameters until we match
1472
* the actuals to an existing template in memory.
1474
class CTcSymProp *prop_;
1478
/* ------------------------------------------------------------------------ */
1480
* Non-symbolic object list entry
1482
struct tcprs_nonsym_obj
1484
tcprs_nonsym_obj(tctarg_obj_id_t id)
1486
/* remember the ID */
1489
/* not in a list yet */
1493
/* ID of this object */
1494
tctarg_obj_id_t id_;
1496
/* next entry in the list */
1497
tcprs_nonsym_obj *nxt_;
1500
/* ------------------------------------------------------------------------ */
1502
* Dictionary property list entry. Each time the source code defines a
1503
* dictionary property, we'll make an entry in this list.
1505
class CTcDictPropEntry
1508
CTcDictPropEntry(class CTcSymProp *prop)
1510
/* remember the property */
1513
/* not in a list yet */
1516
/* not defined for current object yet */
1521
class CTcSymProp *prop_;
1523
/* next entry in list */
1524
CTcDictPropEntry *nxt_;
1526
/* flag: the current object definition includes this property */
1527
unsigned int defined_ : 1;
1530
/* ------------------------------------------------------------------------ */
1532
* Dictionary list entry. Each dictionary object gets an entry in this
1538
CTcDictEntry(class CTcSymObj *sym);
1540
/* get/set my object file index */
1541
uint get_obj_idx() const { return obj_idx_; }
1542
void set_obj_idx(uint idx) { obj_idx_ = idx; }
1544
/* get my object symbol */
1545
class CTcSymObj *get_sym() const { return sym_; }
1547
/* get/set the next item in the list */
1548
CTcDictEntry *get_next() const { return nxt_; }
1549
void set_next(CTcDictEntry *nxt) { nxt_ = nxt; }
1551
/* add a word to the table */
1552
void add_word(const char *txt, size_t len, int copy,
1553
tc_obj_id obj, tc_prop_id prop);
1555
/* write my symbol to the object file if I haven't already done so */
1556
void write_sym_to_obj_file(CVmFile *fp);
1558
/* get the hash table */
1559
class CVmHashTable *get_hash_table() const { return hashtab_; }
1562
/* enumeration callback - write to object file */
1563
static void enum_cb_writeobj(void *ctx, class CVmHashEntry *entry);
1565
/* associated object symbol */
1566
class CTcSymObj *sym_;
1569
* object file index (we use this to match up the dictionary objects
1570
* when we re-load the object file)
1574
/* next item in the dictionary list */
1577
/* hash table containing the word entries */
1578
class CVmHashTable *hashtab_;
1583
* entry in a dictionary list
1585
struct CTcPrsDictItem
1587
CTcPrsDictItem(tc_obj_id obj, tc_prop_id prop)
1600
/* next entry in list */
1601
CTcPrsDictItem *nxt_;
1605
* Parser dictionary hash table entry
1607
class CVmHashEntryPrsDict: public CVmHashEntryCS
1610
CVmHashEntryPrsDict(const char *txt, size_t len, int copy)
1611
: CVmHashEntryCS(txt, len, copy)
1613
/* nothing in my list yet */
1617
/* add an item to my list */
1618
void add_item(tc_obj_id obj, tc_prop_id prop);
1620
/* get the list head */
1621
struct CTcPrsDictItem *get_list() const { return list_; }
1624
/* list of object/property associations with this word */
1625
struct CTcPrsDictItem *list_;
1628
/* ------------------------------------------------------------------------ */
1630
* State save structure for parsing property expressions
1632
class CTcPrsPropExprSave
1635
unsigned int has_local_ctx_ : 1;
1636
int local_ctx_var_num_;
1637
size_t ctx_var_props_used_;
1638
int next_ctx_arr_idx_;
1639
int self_referenced_;
1640
int full_method_ctx_referenced_;
1641
int local_ctx_needs_self_;
1642
int local_ctx_needs_full_method_ctx_;
1643
struct CTcCodeBodyRef *cur_code_body_;
1646
/* ------------------------------------------------------------------------ */
1648
* Grammar production list entry
1650
class CTcGramProdEntry
1653
CTcGramProdEntry(class CTcSymObj *prod_obj);
1655
/* get my production object symbol */
1656
class CTcSymObj *get_prod_sym() const { return prod_sym_; }
1658
/* get/set the next item in the list */
1659
CTcGramProdEntry *get_next() const { return nxt_; }
1660
void set_next(CTcGramProdEntry *nxt) { nxt_ = nxt; }
1662
/* add an alternative */
1663
void add_alt(class CTcGramProdAlt *alt);
1665
/* get the alternative list head */
1666
class CTcGramProdAlt *get_alt_head() const { return alt_head_; }
1668
/* write to an object file */
1669
void write_to_obj_file(class CVmFile *fp);
1671
/* load from an object file */
1672
static void load_from_obj_file(class CVmFile *fp,
1673
const tctarg_prop_id_t *prop_xlat,
1674
const ulong *enum_xlat,
1675
class CTcSymObj *private_owner);
1677
/* move alternatives from my list to the given target list */
1678
void move_alts_to(CTcGramProdEntry *new_entry);
1680
/* get/set explicitly-declared flag */
1681
int is_declared() const { return is_declared_; }
1682
void set_declared(int f) { is_declared_ = f; }
1685
/* associated production object symbol */
1686
class CTcSymObj *prod_sym_;
1688
/* next item in the list */
1689
CTcGramProdEntry *nxt_;
1691
/* head and tail of alternative list */
1692
class CTcGramProdAlt *alt_head_;
1693
class CTcGramProdAlt *alt_tail_;
1696
* flag: this production was explicitly declared (this means that we
1697
* will consider it valid at link time even if it has no alternatives
1700
unsigned int is_declared_ : 1;
1704
* Grammar production alternative. Each grammar production has one or
1705
* more alternatives that, when matched, generate the production.
1707
class CTcGramProdAlt
1710
CTcGramProdAlt(class CTcSymObj *obj_sym, class CTcDictEntry *dict);
1712
/* get/set my score */
1713
int get_score() const { return score_; }
1714
void set_score(int score) { score_ = score; }
1716
/* get/set my badness */
1717
int get_badness() const { return badness_; }
1718
void set_badness(int badness) { badness_ = badness; }
1720
/* get my processor object symbol */
1721
class CTcSymObj *get_processor_obj() const { return obj_sym_; }
1723
/* get/set the next list element */
1724
CTcGramProdAlt *get_next() const { return nxt_; }
1725
void set_next(CTcGramProdAlt *nxt) { nxt_ = nxt; }
1727
/* add a token to my list */
1728
void add_tok(class CTcGramProdTok *tok);
1730
/* get the head of my token list */
1731
class CTcGramProdTok *get_tok_head() const { return tok_head_; }
1733
/* write to an object file */
1734
void write_to_obj_file(class CVmFile *fp);
1736
/* load from an object file */
1737
static CTcGramProdAlt *
1738
load_from_obj_file(class CVmFile *fp,
1739
const tctarg_prop_id_t *prop_xlat,
1740
const ulong *enum_xlat);
1742
/* get the dictionary in effect when the alternative was defined */
1743
class CTcDictEntry *get_dict() const { return dict_; }
1746
/* head and tail of our token list */
1747
class CTcGramProdTok *tok_head_;
1748
class CTcGramProdTok *tok_tail_;
1750
/* dictionary in effect when alternative was defined */
1751
class CTcDictEntry *dict_;
1753
/* the processor object associated with this alternative */
1754
class CTcSymObj *obj_sym_;
1756
/* next alternative in our production */
1757
CTcGramProdAlt *nxt_;
1766
/* grammar production token types */
1767
enum tcgram_tok_type
1772
/* match a production (given by the production object) */
1775
/* match a part of speech (given by the dictionary property) */
1776
TCGRAM_PART_OF_SPEECH,
1778
/* match a literal string */
1781
/* token-type match */
1784
/* free-floating end-of-string */
1787
/* match one of several parts of speech */
1788
TCGRAM_PART_OF_SPEECH_LIST
1792
* Grammar production alternative token
1794
class CTcGramProdTok
1799
/* not in a list yet */
1803
typ_ = TCGRAM_UNKNOWN;
1805
/* no property association yte */
1806
prop_assoc_ = TCTARG_INVALID_PROP;
1809
/* get/set my next element */
1810
CTcGramProdTok *get_next() const { return nxt_; }
1811
void set_next(CTcGramProdTok *nxt) { nxt_ = nxt; }
1813
/* set me to match a production object */
1814
void set_match_prod(class CTcSymObj *obj)
1816
/* remember the production object */
1821
/* set me to match a token type */
1822
void set_match_token_type(ulong enum_id)
1824
/* remember the token enum ID */
1825
typ_ = TCGRAM_TOKEN_TYPE;
1826
val_.enum_id_ = enum_id;
1829
/* set me to match a dictionary property */
1830
void set_match_part_of_speech(tctarg_prop_id_t prop)
1832
/* remember the part of speech */
1833
typ_ = TCGRAM_PART_OF_SPEECH;
1838
* set me to match a list of parts of speech; each part of speech must
1839
* be separately added via add_match_part_ele()
1841
void set_match_part_list();
1843
/* add an element to the part-of-speech match list */
1844
void add_match_part_ele(tctarg_prop_id_t prop);
1846
/* set me to match a literal string */
1847
void set_match_literal(const char *txt, size_t len)
1849
/* remember the string */
1850
typ_ = TCGRAM_LITERAL;
1851
val_.str_.txt_ = txt;
1852
val_.str_.len_ = len;
1855
/* set me to match a free-floating end-of-string */
1856
void set_match_star()
1863
tcgram_tok_type get_type() const { return typ_; }
1866
class CTcSymObj *getval_prod() const { return val_.obj_; }
1867
tctarg_prop_id_t getval_part_of_speech() const { return val_.prop_; }
1868
const char *getval_literal_txt() const { return val_.str_.txt_; }
1869
const size_t getval_literal_len() const { return val_.str_.len_; }
1870
ulong getval_token_type() const { return val_.enum_id_; }
1871
size_t getval_part_list_len() const { return val_.prop_list_.len_; }
1872
tctarg_prop_id_t getval_part_list_ele(size_t idx) const
1873
{ return val_.prop_list_.arr_[idx]; }
1876
* get/set my property association - this is the property to which
1877
* the actual match to the rule is assigned when we match the rule
1879
tctarg_prop_id_t get_prop_assoc() const { return prop_assoc_; }
1880
void set_prop_assoc(tctarg_prop_id_t prop) { prop_assoc_ = prop; }
1882
/* write to an object file */
1883
void write_to_obj_file(class CVmFile *fp);
1885
/* load from an object file */
1886
static CTcGramProdTok *
1887
load_from_obj_file(class CVmFile *fp,
1888
const tctarg_prop_id_t *prop_xlat,
1889
const ulong *enum_xlat);
1892
/* next token in my list */
1893
CTcGramProdTok *nxt_;
1895
/* my type - this specifies how this token matches */
1896
tcgram_tok_type typ_;
1898
/* match specification - varies according to my type */
1901
/* object - for matching a production */
1902
class CTcSymObj *obj_;
1904
/* property - for matching a part of speech */
1905
tctarg_prop_id_t prop_;
1907
/* token enum id - for matching a token type */
1910
/* literal string */
1917
/* list of vocabulary elements */
1920
/* number of array entries allocated */
1923
/* number of array entries actually used */
1926
/* array of entries */
1927
tctarg_prop_id_t *arr_;
1931
/* property association */
1932
tctarg_prop_id_t prop_assoc_;
1935
/* ------------------------------------------------------------------------ */
1937
* Exported symbol record
1942
/* create with the given compiler symbol */
1943
CTcPrsExport(const char *sym, size_t sym_len)
1945
/* remember my name */
1950
* we don't yet have an explicit external name, so export using
1956
/* we're not in a list yet */
1960
/* set the external name */
1961
void set_extern_name(const char *txt, size_t len)
1967
/* get the symbol name and length */
1968
const char *get_sym() const { return sym_; }
1969
size_t get_sym_len() const { return sym_len_; }
1971
/* get the external name and length */
1972
const char *get_ext_name() const { return ext_name_; }
1973
size_t get_ext_len() const { return ext_len_; }
1975
/* get/set the next entry in the list */
1976
CTcPrsExport *get_next() const { return nxt_; }
1977
void set_next(CTcPrsExport *nxt) { nxt_ = nxt; }
1979
/* write to an object file */
1980
void write_to_obj_file(class CVmFile *fp);
1982
/* read from an object file */
1983
static CTcPrsExport *read_from_obj_file(class CVmFile *fp);
1985
/* determine if my external name matches the given export's */
1986
int ext_name_matches(const CTcPrsExport *exp) const
1988
return (exp->get_ext_len() == get_ext_len()
1989
&& memcmp(exp->get_ext_name(), get_ext_name(),
1990
get_ext_len()) == 0);
1993
/* determine if my name matches the given string */
1994
int ext_name_matches(const char *txt) const
1996
return (get_ext_len() == get_strlen(txt)
1997
&& memcmp(get_ext_name(), txt, get_ext_len()) == 0);
2000
/* determine if my symbol name matches the given export's */
2001
int sym_matches(const CTcPrsExport *exp) const
2003
return (exp->get_sym_len() == get_sym_len()
2004
&& memcmp(exp->get_sym(), get_sym(), get_sym_len()) == 0);
2008
/* symbol name - this is the internal compiler symbol being exported */
2012
/* external name - this is the name visible to the VM loader */
2013
const char *ext_name_;
2021
/* ------------------------------------------------------------------------ */
2023
* Parser Symbol Table. The parser maintains a hierarchy of symbol
2024
* tables; a local symbol table can be nested inside an enclosing
2025
* scope's symbol table, and so on up to the top-level block scope,
2026
* which is enclosed by the global scope. In addition, at function
2027
* scope there's a separate table for "goto" labels.
2030
/* find_or_def actions for undefined symbols */
2031
enum tcprs_undef_action
2033
/* if undefined, add an "undefined" entry unconditionally */
2034
TCPRS_UNDEF_ADD_UNDEF,
2036
/* add a "property" entry unconditionally, but warn about it */
2037
TCPRS_UNDEF_ADD_PROP,
2039
/* add a "property" entry unconditionally, with no warning */
2040
TCPRS_UNDEF_ADD_PROP_NO_WARNING
2043
/* parser symbol table */
2047
CTcPrsSymtab(CTcPrsSymtab *parent_scope);
2050
/* allocate parser symbol tables out of the parser memory pool */
2051
void *operator new(size_t siz);
2054
* perform static initialization/termination - call once at program
2055
* startup and shutdown (respectively)
2057
static void s_init();
2058
static void s_terminate();
2060
/* get the enclosing scope's symbol table */
2061
CTcPrsSymtab *get_parent() const { return parent_; }
2063
/* find a symbol; returns null if the symbol isn't defined */
2064
class CTcSymbol *find(const textchar_t *sym, size_t len)
2065
{ return find(sym, len, 0); }
2067
class CTcSymbol *find(const textchar_t *sym)
2068
{ return find(sym, strlen(sym), 0); }
2071
* Find a symbol; returns null if the symbol isn't defined. If
2072
* symtab is not null, we'll fill it in with the actual symbol table
2073
* in which we found the symbol; this might be an enclosing symbol
2074
* table, since we search up the enclosing scope list.
2076
class CTcSymbol *find(const textchar_t *sym, size_t len,
2077
CTcPrsSymtab **symtab);
2079
/* find a symbol directly in this table, without searching parents */
2080
class CTcSymbol *find_direct(const textchar_t *sym, size_t len);
2082
/* find a symbol without changing its referenced status */
2083
class CTcSymbol *find_noref(const textchar_t *sym, size_t len,
2084
CTcPrsSymtab **symtab);
2087
* Find a symbol; if the symbol isn't defined, log an error and add
2088
* the symbol as type "undefined". Because we add a symbol entry if
2089
* the symbol isn't defined, this *always* returns a valid symbol
2092
class CTcSymbol *find_or_def_undef(const char *sym, size_t len,
2095
return find_or_def(sym, len, copy_str, TCPRS_UNDEF_ADD_UNDEF);
2099
* Find a symbol; if the symbol isn't defined, log a warning and
2100
* define the symbol as type property. Because we add an entry if
2101
* the symbol isn't defined, this *always* returns a valid symbol
2104
class CTcSymbol *find_or_def_prop(const char *sym, size_t len,
2107
return find_or_def(sym, len, copy_str, TCPRS_UNDEF_ADD_PROP);
2111
* Find a symbol; if the symbol isn't defined, define the symbol as
2112
* type property with no warning. This should be used when it is
2113
* unambiguous that a symbol is meant as a property name. Because we
2114
* add an entry if the symbol isn't defined, this *always* returns a
2115
* valid symbol object.
2117
class CTcSymbol *find_or_def_prop_explicit(const char *sym, size_t len,
2120
return find_or_def(sym, len, copy_str,
2121
TCPRS_UNDEF_ADD_PROP_NO_WARNING);
2125
* Find a symbol. If the symbol isn't defined, and a "self" object
2126
* is available, define the symbol as a property. If the symbol
2127
* isn't defined an no "self" object is available, add an
2128
* "undefined" entry for the symbol.
2130
class CTcSymbol *find_or_def_prop_implied(const char *sym, size_t len,
2131
int copy_str, int is_self_avail)
2133
return find_or_def(sym, len, copy_str,
2135
? TCPRS_UNDEF_ADD_PROP : TCPRS_UNDEF_ADD_UNDEF);
2138
/* add a formal parameter symbol */
2139
void add_formal(const textchar_t *sym, size_t len, int formal_num,
2142
/* add a local variable symbol */
2143
class CTcSymLocal *add_local(const textchar_t *sym, size_t len,
2144
int local_num, int copy_str,
2145
int init_assigned, int init_referenced);
2147
/* add a 'goto' symbol */
2148
class CTcSymLabel *add_code_label(const textchar_t *sym, size_t len,
2151
/* add an entry to the table */
2152
void add_entry(class CTcSymbol *sym);
2154
/* remove an entry */
2155
void remove_entry(class CTcSymbol *sym);
2157
/* enumerate entries in the table through a callback */
2158
void enum_entries(void (*func)(void *, class CTcSymbol *), void *ctx);
2161
* Scan the symbol table and check for unreferenced locals. Logs an
2162
* error for each unreferenced or unassigned local.
2164
void check_unreferenced_locals();
2167
* Get/set my debugging list index - this is the index of this table
2168
* in the list for this function or method. The index values start
2169
* at 1 - a value of zero indicates that the symbol table isn't part
2172
int get_list_index() const { return list_index_; }
2173
void set_list_index(int n) { list_index_ = n; }
2175
/* get/set the next entry in the linked list */
2176
CTcPrsSymtab *get_list_next() const { return list_next_; }
2177
void set_list_next(CTcPrsSymtab *nxt) { list_next_ = nxt; }
2180
/* add an entry to a global symbol table */
2181
static void add_to_global_symtab(CTcPrsSymtab *tab, CTcSymbol *entry);
2183
/* get the underlying hash table */
2184
class CVmHashTable *get_hashtab() const { return hashtab_; }
2186
/* enumeration callback - check for unreferenced locals */
2187
static void unref_local_cb(void *ctx, class CTcSymbol *sym);
2190
* find a symbol, or define a new symbol, according to the given
2191
* action mode, if the symbol is undefined
2193
class CTcSymbol *find_or_def(const textchar_t *sym, size_t len,
2194
int copy_str, tcprs_undef_action action);
2196
/* enclosing scope (parent) symbol table */
2197
CTcPrsSymtab *parent_;
2200
class CVmHashTable *hashtab_;
2203
static class CVmHashFunc *hash_func_;
2206
* Next symbol table in local scope chain. For each function or
2207
* method, we keep a simple linear list of the local scopes so that
2208
* they can be written to the debugging records. We also keep an
2209
* index value giving its position in the list, so that we can store
2210
* references to the table using the list index.
2212
CTcPrsSymtab *list_next_;
2217
/* ------------------------------------------------------------------------ */
2219
* Debugger symbol table interface. This is an abstract interface that
2220
* debuggers can implement to allow us to search for symbols that are
2221
* obtained from a compiled program's debugger records. To keep the
2222
* compiler independent of the target architecture and the debugger's
2223
* own internal structures, we define this abstract interface that the
2224
* debugger must implement.
2226
* Since this type of symbol table is provided by a debugger as a view
2227
* on the symbol information in a previously compiled program, the
2228
* parser naturally has no need to add symbols to the table; hence the
2229
* only required operations are symbol lookups.
2231
class CTcPrsDbgSymtab
2235
* Get information on a symbol. Returns true if the symbol is
2236
* found, false if not. If we find the symbol, fills in the
2237
* information structure with the appropriate data.
2239
virtual int find_symbol(const textchar_t *sym, size_t len,
2240
struct tcprsdbg_sym_info *info) = 0;
2244
* Debugger local symbol information structure
2246
struct tcprsdbg_sym_info
2249
enum tc_symtype_t sym_type;
2251
/* local/parameter number */
2254
/* context variable index - 0 if it's not a context local */
2257
/* stack frame index */
2263
/* ------------------------------------------------------------------------ */
2265
* Parse Tree storage manager.
2267
* The parse tree has some special characteristics that make it
2268
* desirable to use a special memory manager for it. First, the parse
2269
* tree consists of many small objects, so we would like to have as
2270
* little overhead per object for memory tracking as possible. Second,
2271
* parse tree objects all have a similar lifetime: we create the entire
2272
* parse tree as we scan the source, then use it to generate target
2273
* code, then discard the whole thing.
2275
* To manage memory efficiently for the parse tree, we define our own
2276
* memory manager for parse tree objects. The memory manager is very
2277
* simple, fast, and has minimal per-object overhead. We simply
2278
* maintain a list of large blocks, then suballocate requests out of the
2279
* large blocks. Each time we run out of space in a block, we allocate
2280
* a new block. We do not keep track of any extra tracking information
2281
* per node, so a node cannot be individually freed; however, the entire
2282
* block list can be freed at once, which is exactly the behavior we
2291
/* allocate storage */
2292
void *alloc(size_t siz);
2294
/* save the current pool state, for later resetting */
2295
void save_state(struct tcprsmem_state_t *state);
2298
* reset the pool to the given state - delete all objects allocated
2299
* in the pool since the state was saved
2301
void reset(const struct tcprsmem_state_t *state);
2303
/* reset to initial state */
2307
/* delete all parser memory */
2310
/* allocate a new block */
2313
/* head of list of memory blocks */
2314
struct tcprsmem_blk_t *head_;
2316
/* tail of list and current memory block */
2317
struct tcprsmem_blk_t *tail_;
2319
/* current allocation offset in last block */
2322
/* remaining space available in last block */
2327
* state-saving structure
2329
struct tcprsmem_state_t
2331
/* current tail of memory block list */
2332
struct tcprsmem_blk_t *tail;
2334
/* current allocation offset in last block */
2337
/* current remaining space in last block */
2343
* Provide an overridden operator new for allocating objects explicitly
2346
inline void *operator new(size_t siz, CTcPrsMem *pool)
2348
return pool->alloc(siz);
2352
* provide an array operator new as well
2354
inline void *operator new[](size_t siz, CTcPrsMem *pool)
2356
return pool->alloc(siz);
2361
* parse tree memory block
2363
struct tcprsmem_blk_t
2365
/* next block in the list */
2366
tcprsmem_blk_t *next_;
2369
* This block's byte array (the array extends off the end of the
2375
/* ------------------------------------------------------------------------ */
2377
* Special array list subclass that uses parser memory
2379
class CPrsArrayList: public CArrayList
2383
* override the memory management functions to use parser memory
2386
virtual void *alloc_mem(size_t siz)
2388
/* allocate from the parser pool */
2389
return G_prsmem->alloc(siz);
2392
virtual void *realloc_mem(void *p, size_t oldsiz, size_t newsiz)
2396
/* allocate a new block from the parser pool */
2397
pnew = G_prsmem->alloc(newsiz);
2399
/* copy from the old block to the new block */
2400
memcpy(pnew, p, oldsiz);
2402
/* return the new block */
2406
virtual void free_mem(void *p)
2409
* do nothing - the parser pool automatically frees everything as a
2410
* block when terminating the parser
2416
/* ------------------------------------------------------------------------ */
2418
* Expression Constant Value object. This object is used to express the
2419
* value of a constant expression.
2426
/* the type is unknown */
2431
* determine if this is a constant value - it is a constant if it
2432
* has any known value
2434
int is_const() const { return (typ_ != TC_CVT_UNK); }
2437
* set the type to unknown - this indicates that there is no valid
2438
* value, which generally means that the associated expression does
2439
* not have a constant value
2441
void set_unknown() { typ_ = TC_CVT_UNK; }
2443
/* set from another value */
2444
void set(const CTcConstVal *val)
2449
/* copy the value */
2453
/* set an integer value */
2454
void set_int(long val) { typ_ = TC_CVT_INT; val_.intval_ = val; }
2456
/* set a floating-point value */
2457
void set_float(const char *val, size_t len)
2459
typ_ = TC_CVT_FLOAT;
2460
val_.floatval_.txt_ = val;
2461
val_.floatval_.len_ = len;
2464
/* set an enumerator value */
2465
void set_enum(ulong val) { typ_ = TC_CVT_ENUM; val_.enumval_ = val; }
2467
/* set a single-quoted string value */
2468
void set_sstr(const char *val, size_t len);
2470
/* set a list value */
2471
void set_list(class CTPNList *lst);
2473
/* set an object reference value */
2474
void set_obj(ulong obj, enum tc_metaclass_t meta)
2477
val_.objval_.id_ = obj;
2478
val_.objval_.meta_ = meta;
2481
/* set a property pointer value */
2482
void set_prop(uint prop)
2485
val_.propval_ = prop;
2488
/* set a function pointer value */
2489
void set_funcptr(class CTcSymFunc *sym)
2491
typ_ = TC_CVT_FUNCPTR;
2492
val_.funcptrval_ = sym;
2495
/* set an anonymous function pointer value */
2496
void set_anon_funcptr(class CTPNCodeBody *code_body)
2498
typ_ = TC_CVT_ANONFUNCPTR;
2499
val_.codebodyval_ = code_body;
2502
/* set a nil/true value */
2503
void set_nil() { typ_ = TC_CVT_NIL; }
2504
void set_true() { typ_ = TC_CVT_TRUE; }
2507
* Set a vocabulary list placeholder. This has no actual value
2508
* during compilation; instead, this is just a placeholder. During
2509
* linking, we'll replace each of these with a list of strings
2510
* giving the actual vocabulary for the property.
2512
void set_vocab_list() { typ_ = TC_CVT_VOCAB_LIST; }
2514
/* set a nil/true value based on a boolean value */
2515
void set_bool(int val)
2517
typ_ = (val ? TC_CVT_TRUE : TC_CVT_NIL);
2521
tc_constval_type_t get_type() const { return typ_; }
2523
/* get my int value (no type checking) */
2524
long get_val_int() const { return val_.intval_; }
2526
/* get my floating point value (no type checking) */
2527
const char *get_val_float() const { return val_.floatval_.txt_; }
2528
size_t get_val_float_len() const { return val_.floatval_.len_; }
2530
/* get my enumerator value (no type checking) */
2531
ulong get_val_enum() const { return val_.enumval_; }
2533
/* get my string value (no type checking) */
2534
const char *get_val_str() const { return val_.strval_.strval_; }
2535
size_t get_val_str_len() const { return val_.strval_.strval_len_; }
2537
/* get my list value (no type checking) */
2538
class CTPNList *get_val_list() const { return val_.listval_; }
2540
/* get my object reference value (no type checking) */
2541
ulong get_val_obj() const
2542
{ return val_.objval_.id_; }
2543
enum tc_metaclass_t get_val_obj_meta() const
2544
{ return val_.objval_.meta_; }
2546
/* get my property pointer value (no type checking) */
2547
uint get_val_prop() const { return val_.propval_; }
2549
/* get my function pointer symbol value (no type checking) */
2550
class CTcSymFunc *get_val_funcptr_sym() const
2551
{ return val_.funcptrval_; }
2553
/* get my anonymous function pointer value (no type checking) */
2554
class CTPNCodeBody *get_val_anon_func_ptr() const
2555
{ return val_.codebodyval_; }
2558
* Determine if this value equals a given constant value. Returns
2559
* true if so, false if not. We'll set (*can_compare) to true if
2560
* the values are comparable, false if the comparison is not
2563
int is_equal_to(const CTcConstVal *val) const;
2566
* Convert an integer, nil, or true value to a string. Fills in the
2567
* buffer with the result of the conversion if the value wasn't
2568
* already a string. If the value is already a string, we'll simply
2569
* return a pointer to the original string without making a copy.
2570
* Returns null if the value is not convertible to a string.
2572
const char *cvt_to_str(char *buf, size_t bufl, size_t *result_len);
2575
* Get my true/nil value. Returns false if the value is nil or zero,
2576
* true if it's anything else.
2578
int get_val_bool() const
2580
return !(typ_ == TC_CVT_NIL
2581
|| (typ_ == TC_CVT_INT && get_val_int() == 0));
2586
tc_constval_type_t typ_;
2590
/* integer value (valid when typ_ == TC_CVT_INT) */
2593
/* floating-point value (valid when typ_ == TC_CVT_FLOAT) */
2601
/* enumerator value (valid when typ_ == TC_CVT_ENUM) */
2605
* String value (valid when typ_ == TC_CVT_TYPE_SSTR). We need
2606
* to know the length separately, because the underyling string
2607
* may not be null-terminated.
2611
const char *strval_;
2617
class CTPNList *listval_;
2619
/* property ID value */
2622
/* object reference value */
2626
enum tc_metaclass_t meta_;
2631
* function pointer value - we store the underlying symbol,
2632
* since function pointers are generally not resolved until late
2633
* in the compilation
2635
class CTcSymFunc *funcptrval_;
2638
* code body pointer value - we store the underlying code body
2639
* for anonymous functions
2641
class CTPNCodeBody *codebodyval_;
2646
/* ------------------------------------------------------------------------ */
2653
/* simple assignment: x = 1 */
2656
/* add to: x += 1 */
2659
/* subtract from: x -= 1 */
2662
/* multiply by: x *= 1 */
2665
/* divide by: x /= 1 */
2668
/* modulo: x %= 1 */
2671
/* bitwise-and with: x &= 1 */
2674
/* bitwise-or with: x |= 1 */
2677
/* bitwise-xor with: x ^= 1 */
2680
/* shift left: x <<= 1 */
2683
/* shift right: x >>= 1 */
2692
/* post-increment */
2695
/* post-decrement */
2700
/* ------------------------------------------------------------------------ */
2702
* Formal parameter type list. For functions with declared formal
2703
* parameter types (such as multi-methods), we use this class to keep the
2704
* list of type names in the parameter list.
2706
class CTcFormalTypeList
2711
/* no entries in our type list yet */
2714
/* assume this isn't a varargs list */
2718
~CTcFormalTypeList() { }
2720
/* create the decorated name */
2721
void decorate_name(CTcToken *decorated_name,
2722
const CTcToken *func_base_name);
2724
/* get the first parameter in the list */
2725
class CTcFormalTypeEle *get_first() const { return head_; }
2727
/* add a typed variable to the list */
2728
void add_typed_param(const CTcToken *tok);
2730
/* add an untyped variable to the list */
2731
void add_untyped_param();
2733
/* add 'n' untyped variables to the list */
2734
void add_untyped_params(int n)
2737
add_untyped_param();
2740
/* add a trailing ellispsis (varargs indicator) */
2741
void add_ellipsis() { varargs_ = TRUE; }
2744
/* add a new list element */
2745
void add(class CTcFormalTypeEle *ele);
2747
/* add/tail of parameter list */
2748
class CTcFormalTypeEle *head_, *tail_;
2750
/* is this a varargs list? */
2754
/* formal parameter type list entry */
2755
class CTcFormalTypeEle
2758
CTcFormalTypeEle() { name_ = 0; }
2759
CTcFormalTypeEle(const char *name, size_t len);
2764
/* next element in list */
2765
CTcFormalTypeEle *nxt_;
2773
/* ------------------------------------------------------------------------ */
2775
* Expression Operator Parsers. We construct a tree of these operator
2776
* parsers so that we can express the expression grammar in a relatively
2777
* compact and declarative notation.
2781
* basic operator parser
2787
* Parse an expression with this operator. Logs an error and
2788
* returns non-zero if the expression is not valid; on success,
2791
* Fills in *val with the constant value, if any, of the expression.
2792
* If the expression does not have a constant value, *val's type
2793
* will be set to TC_CVT_UNKNOWN to indicate this.
2795
* Returns a parse node if successful, or null if an error occurs
2796
* and the operator parser is unable to make a guess about what was
2799
virtual class CTcPrsNode *parse() const = 0;
2803
* generic left-associative binary operator
2805
class CTcPrsOpBin: public CTcPrsOp
2810
/* no left or right subexpression specified */
2813
/* as-yet unknown operator token */
2814
op_tok_ = TOKT_INVALID;
2817
CTcPrsOpBin(tc_toktyp_t typ)
2819
/* remember my operator token */
2823
CTcPrsOpBin(const CTcPrsOp *left, const CTcPrsOp *right, tc_toktyp_t typ)
2825
/* remember my left and right sub-operators */
2829
/* remember my operator token */
2833
/* parse the binary expression */
2834
class CTcPrsNode *parse() const;
2836
/* build a new tree out of our left-hand and right-hand subtrees */
2837
virtual class CTcPrsNode
2838
*build_tree(class CTcPrsNode *left,
2839
class CTcPrsNode *right) const = 0;
2842
* Try evaluating a constant result. If the two values can be
2843
* combined with the operator to yield a constant value result,
2844
* create a new parse node for the constant value (or update one of
2845
* the given subnodes) and return it. If we can't provide a
2846
* constant value, return null.
2848
* By default, we'll indicate that the expression does not have a
2849
* valid constant value.
2851
virtual class CTcPrsNode
2852
*eval_constant(class CTcPrsNode *left,
2853
class CTcPrsNode *right) const
2855
/* indicate that we cannot synthesize a constant value */
2859
/* get/set my token */
2860
tc_toktyp_t get_op_tok() const { return op_tok_; }
2861
void set_op_tok(tc_toktyp_t tok) { op_tok_ = tok; }
2864
/* operator that can be parsed for my left-hand side */
2865
const CTcPrsOp *left_;
2867
/* operator that can be parsed for my right-hand side */
2868
const CTcPrsOp *right_;
2870
/* my operator token */
2871
tc_toktyp_t op_tok_;
2875
* Binary Operator Group. This is a group of operators at a common
2876
* precedence level. The group has an array of binary operators that
2877
* are all at the same level of precedence; we'll evaluate the left
2878
* suboperator, then check the token in the input stream against each of
2879
* our group's operators, applying the one that matches, if one matches.
2881
class CTcPrsOpBinGroup: public CTcPrsOp
2884
CTcPrsOpBinGroup(const CTcPrsOp *left, const CTcPrsOp *right,
2885
const class CTcPrsOpBin *const *ops)
2887
/* remember my left and right suboperators */
2891
/* remember the operators in my group */
2895
/* parse the expression */
2896
class CTcPrsNode *parse() const;
2899
/* find and apply an operator to the parsed left-hand side */
2900
int find_and_apply_op(CTcPrsNode **lhs) const;
2902
/* my left and right suboperators */
2903
const CTcPrsOp *left_;
2904
const CTcPrsOp *right_;
2906
/* group of binary operators at this precedence level */
2907
const class CTcPrsOpBin *const *ops_;
2911
* Binary operator group for comparison operators. This is a similar to
2912
* other binary groups, but also includes the special "is in" and "not
2915
class CTcPrsOpBinGroupCompare: public CTcPrsOpBinGroup
2918
CTcPrsOpBinGroupCompare(const class CTcPrsOp *left,
2919
const class CTcPrsOp *right,
2920
const class CTcPrsOpBin *const *ops)
2921
: CTcPrsOpBinGroup(left, right, ops)
2925
class CTcPrsNode *parse() const;
2928
/* parse the 'in' list portion of the expression */
2929
class CTPNArglist *parse_inlist() const;
2932
/* comma operator */
2933
class CTcPrsOpComma: public CTcPrsOpBin
2936
CTcPrsOpComma(const CTcPrsOp *left, const CTcPrsOp *right)
2937
: CTcPrsOpBin(left, right, TOKT_COMMA) { }
2939
/* evaluate constant result */
2941
*eval_constant(class CTcPrsNode *left,
2942
class CTcPrsNode *right) const;
2944
/* build a new tree out of our left-hand and right-hand subtrees */
2946
*build_tree(class CTcPrsNode *left,
2947
class CTcPrsNode *right) const;
2951
class CTcPrsOpOr: public CTcPrsOpBin
2954
CTcPrsOpOr(const CTcPrsOp *left, const CTcPrsOp *right)
2955
: CTcPrsOpBin(left, right, TOKT_OROR) { }
2957
/* evaluate constant result */
2959
*eval_constant(class CTcPrsNode *left,
2960
class CTcPrsNode *right) const;
2962
/* build a new tree out of our left-hand and right-hand subtrees */
2964
*build_tree(class CTcPrsNode *left,
2965
class CTcPrsNode *right) const;
2969
class CTcPrsOpAnd: public CTcPrsOpBin
2972
CTcPrsOpAnd(const CTcPrsOp *left, const CTcPrsOp *right)
2973
: CTcPrsOpBin(left, right, TOKT_ANDAND) { }
2975
/* evaluate constant result */
2977
*eval_constant(class CTcPrsNode *left,
2978
class CTcPrsNode *right) const;
2980
/* build a new tree out of our left-hand and right-hand subtrees */
2982
*build_tree(class CTcPrsNode *left,
2983
class CTcPrsNode *right) const;
2986
/* general magnitude comparison operators */
2987
class CTcPrsOpRel: public CTcPrsOpBin
2990
CTcPrsOpRel(tc_toktyp_t typ) : CTcPrsOpBin(typ) { }
2992
/* evaluate constant result */
2994
*eval_constant(class CTcPrsNode *left,
2995
class CTcPrsNode *right) const;
2999
* Get the result true/false value, given the result of the
3000
* comparison. For example, if this is a greater-than operator,
3001
* this should return TRUE if comp > 0, FALSE otherwise.
3003
virtual int get_bool_val(int comparison_value) const = 0;
3006
/* comparison - greater than */
3007
class CTcPrsOpGt: public CTcPrsOpRel
3010
CTcPrsOpGt() : CTcPrsOpRel(TOKT_GT) { }
3012
/* get the boolean value for a comparison sense */
3013
int get_bool_val(int comp) const { return comp > 0; }
3015
/* build a new tree out of our left-hand and right-hand subtrees */
3017
*build_tree(class CTcPrsNode *left,
3018
class CTcPrsNode *right) const;
3021
/* comparison - greater than or equal to */
3022
class CTcPrsOpGe: public CTcPrsOpRel
3025
CTcPrsOpGe() : CTcPrsOpRel(TOKT_GE) { }
3027
/* get the boolean value for a comparison sense */
3028
int get_bool_val(int comp) const { return comp >= 0; }
3030
/* build a new tree out of our left-hand and right-hand subtrees */
3032
*build_tree(class CTcPrsNode *left,
3033
class CTcPrsNode *right) const;
3036
/* comparison - less than */
3037
class CTcPrsOpLt: public CTcPrsOpRel
3040
CTcPrsOpLt() : CTcPrsOpRel(TOKT_LT) { }
3042
/* get the boolean value for a comparison sense */
3043
int get_bool_val(int comp) const { return comp < 0; }
3045
/* build a new tree out of our left-hand and right-hand subtrees */
3047
*build_tree(class CTcPrsNode *left,
3048
class CTcPrsNode *right) const;
3051
/* comparison - less than or equal to */
3052
class CTcPrsOpLe: public CTcPrsOpRel
3055
CTcPrsOpLe() : CTcPrsOpRel(TOKT_LE) { }
3057
/* get the boolean value for a comparison sense */
3058
int get_bool_val(int comp) const { return comp <= 0; }
3060
/* build a new tree out of our left-hand and right-hand subtrees */
3062
*build_tree(class CTcPrsNode *left,
3063
class CTcPrsNode *right) const;
3067
* Equality/inequality comparison
3069
class CTcPrsOpEqComp: public CTcPrsOpBin
3072
CTcPrsOpEqComp(tc_toktyp_t typ) : CTcPrsOpBin(typ) { }
3074
/* evaluate constant result */
3076
*eval_constant(class CTcPrsNode *left,
3077
class CTcPrsNode *right) const;
3080
/* get the boolean value to use if the operands are equal */
3081
virtual int get_bool_val(int ops_equal) const = 0;
3086
* Equality comparison
3088
class CTcPrsOpEq: public CTcPrsOpEqComp
3091
/* start out in C mode - use '==' operator by default */
3093
: CTcPrsOpEqComp(TOKT_EQEQ) { }
3095
/* set the current equality operator */
3096
void set_eq_op(tc_toktyp_t op) { op_tok_ = op; }
3098
/* build a new tree out of our left-hand and right-hand subtrees */
3100
*build_tree(class CTcPrsNode *left,
3101
class CTcPrsNode *right) const;
3103
/* get the boolean value to use if the operands are equal */
3104
virtual int get_bool_val(int ops_equal) const { return ops_equal; }
3108
* Inequality comparison
3110
class CTcPrsOpNe: public CTcPrsOpEqComp
3113
CTcPrsOpNe() : CTcPrsOpEqComp(TOKT_NE) { }
3115
/* build a new tree out of our left-hand and right-hand subtrees */
3117
*build_tree(class CTcPrsNode *left,
3118
class CTcPrsNode *right) const;
3120
/* get the boolean value to use if the operands are equal */
3121
virtual int get_bool_val(int ops_equal) const { return !ops_equal; }
3125
* binary arithmetic operators
3127
class CTcPrsOpArith: public CTcPrsOpBin
3130
CTcPrsOpArith(tc_toktyp_t typ)
3131
: CTcPrsOpBin(typ) { }
3133
CTcPrsOpArith(const CTcPrsOp *left, const CTcPrsOp *right,
3135
: CTcPrsOpBin(left, right, typ) { }
3137
/* evaluate constant result */
3139
*eval_constant(class CTcPrsNode *left,
3140
class CTcPrsNode *right) const;
3143
/* calculate the result */
3144
virtual long calc_result(long val1, long val2) const = 0;
3148
class CTcPrsOpBOr: public CTcPrsOpArith
3151
CTcPrsOpBOr(const CTcPrsOp *left, const CTcPrsOp *right)
3152
: CTcPrsOpArith(left, right, TOKT_OR) { }
3154
/* build a new tree out of our left-hand and right-hand subtrees */
3156
*build_tree(class CTcPrsNode *left,
3157
class CTcPrsNode *right) const;
3160
/* calculate the result */
3161
virtual long calc_result(long val1, long val2) const
3162
{ return val1 | val2; }
3166
class CTcPrsOpBXor: public CTcPrsOpArith
3169
CTcPrsOpBXor(const CTcPrsOp *left, const CTcPrsOp *right)
3170
: CTcPrsOpArith(left, right, TOKT_XOR) { }
3172
/* build a new tree out of our left-hand and right-hand subtrees */
3174
*build_tree(class CTcPrsNode *left,
3175
class CTcPrsNode *right) const;
3178
/* calculate the result */
3179
virtual long calc_result(long val1, long val2) const
3180
{ return val1 ^ val2; }
3184
class CTcPrsOpBAnd: public CTcPrsOpArith
3187
CTcPrsOpBAnd(const CTcPrsOp *left, const CTcPrsOp *right)
3188
: CTcPrsOpArith(left, right, TOKT_AND) { }
3190
/* build a new tree out of our left-hand and right-hand subtrees */
3192
*build_tree(class CTcPrsNode *left,
3193
class CTcPrsNode *right) const;
3196
/* calculate the result */
3197
virtual long calc_result(long val1, long val2) const
3198
{ return val1 & val2; }
3204
class CTcPrsOpShl: public CTcPrsOpArith
3207
CTcPrsOpShl() : CTcPrsOpArith(TOKT_SHL) { }
3209
/* build a new tree out of our left-hand and right-hand subtrees */
3211
*build_tree(class CTcPrsNode *left,
3212
class CTcPrsNode *right) const;
3215
long calc_result(long a, long b) const { return a << b; }
3221
class CTcPrsOpShr: public CTcPrsOpArith
3224
CTcPrsOpShr() : CTcPrsOpArith(TOKT_SHR) { }
3226
/* build a new tree out of our left-hand and right-hand subtrees */
3228
*build_tree(class CTcPrsNode *left,
3229
class CTcPrsNode *right) const;
3232
long calc_result(long a, long b) const { return a >> b; }
3238
class CTcPrsOpMul: public CTcPrsOpArith
3241
CTcPrsOpMul() : CTcPrsOpArith(TOKT_TIMES) { }
3243
/* build a new tree out of our left-hand and right-hand subtrees */
3245
*build_tree(class CTcPrsNode *left,
3246
class CTcPrsNode *right) const;
3249
long calc_result(long a, long b) const { return a * b; }
3255
class CTcPrsOpDiv: public CTcPrsOpArith
3259
: CTcPrsOpArith(TOKT_DIV) { }
3261
CTcPrsOpDiv(tc_toktyp_t tok)
3262
: CTcPrsOpArith(tok) { }
3264
/* build a new tree out of our left-hand and right-hand subtrees */
3266
*build_tree(class CTcPrsNode *left,
3267
class CTcPrsNode *right) const;
3270
long calc_result(long a, long b) const;
3275
* mod - inherit from divide operator to pick up divide-by-zero checking
3277
class CTcPrsOpMod: public CTcPrsOpDiv
3280
CTcPrsOpMod() : CTcPrsOpDiv(TOKT_MOD) { }
3282
/* build a new tree out of our left-hand and right-hand subtrees */
3284
*build_tree(class CTcPrsNode *left,
3285
class CTcPrsNode *right) const;
3288
long calc_result(long a, long b) const;
3294
class CTcPrsOpAdd: public CTcPrsOpArith
3297
CTcPrsOpAdd() : CTcPrsOpArith(TOKT_PLUS) { }
3299
/* build a new tree out of our left-hand and right-hand subtrees */
3301
*build_tree(class CTcPrsNode *left,
3302
class CTcPrsNode *right) const;
3304
/* evaluate constant result */
3306
*eval_constant(class CTcPrsNode *left,
3307
class CTcPrsNode *right) const;
3310
long calc_result(long a, long b) const { return a + b; }
3316
class CTcPrsOpSub: public CTcPrsOpArith
3319
CTcPrsOpSub() : CTcPrsOpArith(TOKT_MINUS) { }
3321
/* build a new tree out of our left-hand and right-hand subtrees */
3323
*build_tree(class CTcPrsNode *left,
3324
class CTcPrsNode *right) const;
3326
/* evaluate constant result */
3328
*eval_constant(class CTcPrsNode *left,
3329
class CTcPrsNode *right) const;
3332
long calc_result(long a, long b) const { return a - b; }
3338
class CTcPrsOpUnary: public CTcPrsOp
3341
class CTcPrsNode *parse() const;
3344
* evaluate a constant subscript expression; returns a constant
3345
* parse node expression if the subscript can be evaluated to a
3346
* compile-time constant, or null if not
3348
static class CTcPrsNode
3349
*eval_const_subscript(class CTcPrsNode *lhs,
3350
class CTcPrsNode *subscript);
3353
* evaluate a constant NOT expression; returns a constant parse node
3354
* expression if the logical negation can be evaluated to a
3355
* compile-time constant, or null if not
3357
static class CTcPrsNode *eval_const_not(class CTcPrsNode *lhs);
3359
/* parse a double-quoted string with embedded expressions */
3360
static class CTcPrsNode *parse_dstr_embed();
3363
static class CTcPrsNode *parse_list();
3365
/* parse a primary expression */
3366
static class CTcPrsNode *parse_primary();
3369
/* parse an anonymous function */
3370
static class CTcPrsNode *parse_anon_func(int short_form);
3372
/* parse a logical NOT operator */
3373
static class CTcPrsNode *parse_not(CTcPrsNode *sub);
3375
/* parse a bitwise NOT operator */
3376
static class CTcPrsNode *parse_bnot(CTcPrsNode *sub);
3378
/* parse an address-of operator */
3379
class CTcPrsNode *parse_addr() const;
3381
/* parse an arithmetic positive operator */
3382
static class CTcPrsNode *parse_pos(CTcPrsNode *sub);
3384
/* parse an arithmetic negative operator */
3385
static class CTcPrsNode *parse_neg(CTcPrsNode *sub);
3387
/* parse a pre- or post-increment operator */
3388
static class CTcPrsNode *parse_inc(int pre, CTcPrsNode *sub);
3390
/* parse a pre- or post-decrement operator */
3391
static class CTcPrsNode *parse_dec(int pre, CTcPrsNode *sub);
3393
/* parse a 'new' operator */
3394
static class CTcPrsNode *parse_new(CTcPrsNode *sub, int is_transient);
3396
/* parse a 'delete' operator */
3397
static class CTcPrsNode *parse_delete(CTcPrsNode *sub);
3399
/* parse a postfix expression */
3400
static class CTcPrsNode *parse_postfix(int allow_member_expr,
3401
int allow_call_expr);
3403
/* parse a function or method call */
3404
static class CTcPrsNode *parse_call(CTcPrsNode *lhs);
3406
/* parse an argument list */
3407
static class CTPNArglist *parse_arg_list();
3409
/* parse a subscript */
3410
static class CTcPrsNode *parse_subscript(CTcPrsNode *lhs);
3412
/* parse a member selection ('.' operator) */
3413
static class CTcPrsNode *parse_member(CTcPrsNode *lhs);
3415
/* parse an "inherited" expression */
3416
static class CTcPrsNode *parse_inherited();
3418
/* parse a "delegated" expression */
3419
static class CTcPrsNode *parse_delegated();
3421
/* local symbol enumeration callback for anonymous function setup */
3422
static void enum_for_anon(void *ctx, class CTcSymbol *sym);
3424
/* local symbol enumeration for anon function - follow-up */
3425
static void enum_for_anon2(void *ctx, class CTcSymbol *sym);
3429
* tertiary conditional operator
3431
class CTcPrsOpIf: public CTcPrsOp
3434
class CTcPrsNode *parse() const;
3438
* Assignment operators (including the regular assignment, "="/":=",
3439
* plus all calculate-and-assign operators: "+=", "-=", etc)
3441
class CTcPrsOpAsi: public CTcPrsOp
3446
/* start out with the C-mode simple assignment operator */
3450
/* parse an assignment */
3451
class CTcPrsNode *parse() const;
3453
/* set the current simple assignment operator */
3454
void set_asi_op(tc_toktyp_t tok) { asi_op_ = tok; }
3457
/* current simple assignment operator */
3458
tc_toktyp_t asi_op_;
3461
#endif /* TCPRS_H */