10 // make-it-easier macros
11 #define LEX (&cc->lex) // struct lexer *
12 #define TOK (cc->lex.tok) // tok_t
14 static void cc_accept(struct cc
*cc
, const char *description
, ...);
15 static void cc_sync(struct cc
*cc
, ...);
16 static int get_precedence(tok_t tok
);
17 static bool cc_isglobal(struct cc
*cc
);
18 static struct stree
*cc_get_current_func(struct cc
*cc
);
19 static struct stree
*cc_parse_factor(struct cc
*cc
);
20 static struct stree
*cc_parse_expr(struct cc
*cc
);
21 static struct stree
*cc_parse_expr_nocomma(struct cc
*cc
);
22 static bool cc_parse_struct(struct cc
*cc
, struct btype
*struct_type_info
);
23 static bool cc_parse_type(struct cc
*cc
, struct btype
*type_info
);
24 static struct stree
*cc_parse_pointer_type(struct cc
*cc
, struct btype
*type_info
);
25 static struct stree
*cc_parse_parameters(struct cc
*cc
);
26 static bool type_identical(struct btype
*type1
, struct btype
*type2
);
27 static void cc_compare_functions(struct cc
*cc
, struct stree
*func1
, struct stree
*func2
);
28 static void cc_parse_decl_function(struct cc
*cc
, struct stree
**psym_node
);
29 static void cc_parse_decl_variable(struct cc
*cc
, struct stree
*sym_node
);
30 static void cc_parse_statement(struct cc
*cc
);
31 static void cc_parse_compound_stat(struct cc
*cc
);
32 static void cc_parse_defn_function(struct cc
*cc
, struct stree
*func
);
33 static bool cc_parse_decl(struct cc
*cc
, struct stree
*insert_here
);
35 // throw a 'foo expected but bar found' error
36 void cc_expect(struct cc
*cc
, const char *fmt
, ...)
40 fprintf(stderr
, "%s:%d: error: ", LEX
->tok_sloc
.name
, LEX
->tok_sloc
.line
);
41 vfprintf(stderr
, fmt
, ap
);
43 fprintf(stderr
, " expected but \"%s\" found\n", lex_get_tok_str(LEX
, TOK
, LEX
->tok_str
));
46 // throw a compile error with explicit source code location (va_list form)
47 void cc_error_loc_v(struct cc
*cc
, struct sloc
*sloc
, const char *fmt
, va_list ap
)
49 fprintf(stderr
, "%s:%d: error: ", sloc
->name
, sloc
->line
);
50 vfprintf(stderr
, fmt
, ap
);
54 // throw a compile error with explicit source code location (... form)
55 void cc_error_loc(struct cc
*cc
, struct sloc
*sloc
, const char *fmt
, ...)
59 cc_error_loc_v(cc
, sloc
, fmt
, ap
);
63 // throw a compile error at current token
64 void cc_error(struct cc
*cc
, const char *fmt
, ...)
68 cc_error_loc_v(cc
, &LEX
->tok_sloc
, fmt
, ap
);
72 // If the next token is in the given set of tokens,
73 // then accept it, otherwise throw an error.
74 // 'description' describes what is wanted. This could be
75 // a token or a non-terminal name (eg. "type" or "expression").
76 // Token set is a zero-terminated list of tokens. Eg.:
77 // > cc_accept(cc, "operator", '+', '-', TOK_SHL, 0);
78 // would throw "operator expected, but '*' found" if the next
79 // token wasn't either '+', '-' or TOK_SHL (<<)
80 static void cc_accept(struct cc
*cc
, const char *description
, ...)
84 va_start(ap
, description
);
85 while ((tok
= va_arg(ap
, int))){
92 cc_expect(cc
, "%s", description
);
95 // keep eating tokens until the current token is in the given set.
96 // The set is a zero-terminated list of tokens, eg.:
97 // > cc_sync(cc, ')', ';', 0);
98 static void cc_sync(struct cc
*cc
, ...)
104 while ((tok
= va_arg(ap
, int))){
114 int prec
; // operator precedence level (1=highest)
115 tok_t tok
; // operator token
116 } operator_table
[] = {
117 {1, '*'}, {1, '/'}, {1, '%'}, // multiplicative
118 {2, '+'}, {2, '-'}, // additive
119 {3, TOK_SHL
}, {3, TOK_SHR
}, // shiftive?
120 {4, '<'}, {4, TOK_LE
}, {4, '>'}, {4, TOK_GE
}, // comparison
121 {5, TOK_EQ
}, {5, TOK_NE
}, // equality
122 {6, '&'}, // bitwise and
123 {7, '^'}, // bitwise xor
124 {8, '|'}, // bitwise or
125 {9, TOK_LAND
}, // logical and
126 {10, TOK_LOR
}, // logical or
127 {11, '?'}, // ternary
128 {12, '='}, {12, TOK_EADD
}, {12, TOK_ESUB
}, // augmented assignment
129 {12, TOK_EMUL
}, {12, TOK_EDIV
}, {12, TOK_EMOD
},// .
130 {12, TOK_ESHL
}, {12, TOK_ESHR
}, {12, TOK_EAND
},// .
131 {12, TOK_EXOR
}, {12, TOK_EOR
}, // .
132 {13, ','}, // comma operator
135 static int get_precedence(tok_t tok
)
138 for (i
=0; i
<(sizeof operator_table
/ sizeof *operator_table
); i
++){
139 if (operator_table
[i
].tok
== tok
){
140 return operator_table
[i
].prec
;
146 // return true if parser state is in global scope
147 // (i.e. what is being passed is at global (file) scope)
148 static bool cc_isglobal(struct cc
*cc
)
150 return (cc
->scope
== cc
->stree
);
153 // return the current function node
154 static struct stree
*cc_get_current_func(struct cc
*cc
)
160 // parse a factor, except subexpressions (...),
161 // due to cast/subexpression ambiguity
162 static struct stree
*cc_parse_factor(struct cc
*cc
)
164 struct stree
*fac
= NULL
;
165 if (lex_is_ident(LEX
, TOK
)){
166 fac
= stree_create();
167 fac
->form
= STF_FACTOR
;
170 } else if (TOK
== TOK_NUMBER
){
171 fac
= stree_create();
172 fac
->form
= STF_FACTOR
;
173 fac
->tok
= TOK_NUMBER
;
174 const_parse_number(&fac
->cv
, LEX
->tok_str
);
176 } else if (TOK
== TOK_STR
){
177 fac
= stree_create();
178 fac
->form
= STF_FACTOR
;
180 fac
->cv
.type
= CBT_STRING
;
181 fac
->cv
.v
.string
= LEX
->tok_str
; // steal the string data :)
185 cc_expect(cc
, "expression");
190 static struct stree
*cc_parse_unary(struct cc
*cc
)
192 struct stree
*fac
, *un
, *prefix_first
= NULL
, *prefix_last
= NULL
;
194 // prefix unary operators
195 while (TOK
== TOK_INC
|| TOK
== TOK_DEC
|| TOK
== '+'
196 || TOK
== '-' || TOK
== '!' || TOK
== '~' || TOK
== '*'
197 || TOK
== '&' || TOK
== TOK_sizeof
){
202 // The '+' does nothing. Does anyone ever use it?!
203 fprintf(stderr
, "You're using a unary plus? Weird.\n");
207 stree_append_child(prefix_last
, un
);
215 // subexpression or cast
218 struct stree
*type_node
;
221 if (cc_parse_type(cc
, &btype
)){
223 type_node
= cc_parse_pointer_type(cc
, &btype
);
229 // excessive type information
230 stree_append_child(un
, type_node
);
232 // I could choose between one goto, or reams and reams
233 // of tangled spaghetti-loops.
234 // I preferred the goto.
236 goto link_prefix_unop
;
238 fac
= cc_parse_expr(cc
);
239 cc_accept(cc
, "\")\"", ')', 0);
242 fac
= cc_parse_factor(cc
);
245 // postfix unary operators
246 while (TOK
== TOK_INC
|| TOK
== TOK_DEC
|| TOK
== '[' ||
247 TOK
== TOK_ARROW
|| TOK
== '.' || TOK
== '('){
250 stree_append_child(un
, fac
);
252 un
->tok
= TOK_POSTINC
;
254 } else if (TOK
== TOK_DEC
){
255 un
->tok
= TOK_POSTDEC
;
257 } else if (TOK
== '['){
259 struct stree
*subscript
;
262 subscript
= cc_parse_expr(cc
);
264 stree_append_child(un
, subscript
);
265 cc_accept(cc
, "\"]\"", ']', 0);
267 } else if (TOK
== '.' || TOK
== TOK_ARROW
){
268 // struct/union member access
269 struct stree
*member_name
;
272 if (lex_is_ident(LEX
, TOK
)){
273 member_name
= stree_create();
274 member_name
->form
= STF_ATOM
;
275 member_name
->tok
= TOK
;
276 stree_append_child(un
, member_name
);
279 cc_expect(cc
, "identifier (member name)");
281 } else if (TOK
== '('){
282 struct stree
*argument
;
288 argument
= cc_parse_expr_nocomma(cc
);
290 stree_append_child(un
, argument
);
292 } while (TOK
== ',' ? (lex_next(LEX
), 1) : 0);
294 cc_accept(cc
, "\")\"", ')', 0);
300 stree_append_child(prefix_last
, fac
);
307 static struct stree
*cc_parse_expr_internal(struct cc
*cc
, int min_prec
)
309 struct stree
*lhs
, *rhs
, *op_node
, *node
, *node_parent
, *node_right
;
310 int prec
, node_prec
, op_tok
;
311 lhs
= cc_parse_unary(cc
);
314 prec
= get_precedence(TOK
);
315 while (prec
!= 0 && prec
<= min_prec
){
318 rhs
= cc_parse_unary(cc
);
322 // find where to insert it
325 while (node
&& node
->form
== STF_BINOP
){
326 node_prec
= get_precedence(node
->tok
);
327 if (prec
< node_prec
){
328 // carry on descending
329 node_right
= stree_right(node
);
341 // insert between node and node_parent
342 op_node
= stree_create();
343 op_node
->form
= STF_BINOP
;
344 op_node
->tok
= op_tok
;
346 stree_remove_child(node
);
347 stree_append_child(op_node
, node
);
348 stree_append_child(op_node
, rhs
);
349 stree_append_child(node_parent
, op_node
);
351 stree_append_child(op_node
, node
);
352 stree_append_child(op_node
, rhs
);
358 prec
= get_precedence(TOK
);
363 static struct stree
*cc_parse_expr(struct cc
*cc
)
365 return cc_parse_expr_internal(cc
, 13);
368 // same as cc_parse_expr, but don't parse the comma operator
369 // used in function calls
370 static struct stree
*cc_parse_expr_nocomma(struct cc
*cc
)
372 return cc_parse_expr_internal(cc
, 12);
375 // parse struct or union (they're syntactically identical)
376 static bool cc_parse_struct(struct cc
*cc
, struct btype
*struct_type_info
)
379 struct btype type_info
, original_type_info
;
380 struct stree
*type_node
, *sym_node
;
381 tag
= stree_create();
383 tag
->sloc
= LEX
->tok_sloc
;
385 if (lex_is_ident(LEX
, TOK
)){
386 // prev_tag = stree_find(cc->scope, STF_TAG, TOK); TODO
388 tag
->sloc
= LEX
->tok_sloc
;
394 while (TOK
!= 0 && TOK
!= '}'){
395 if (cc_parse_type(cc
, &original_type_info
)){
397 type_info
= original_type_info
;
398 type_node
= cc_parse_pointer_type(cc
, &type_info
);
399 if (!lex_is_ident(LEX
, TOK
)){
400 cc_expect(cc
, "identifier");
402 stree_destroy(type_node
);
404 return false; // XXX: LEAKS?
406 sym_node
= stree_create();
407 sym_node
->form
= STF_VARIABLE
;
408 sym_node
->btype
= type_info
;
410 sym_node
->sloc
= LEX
->tok_sloc
;
412 stree_append_child(sym_node
, type_node
);
414 stree_append_child(tag
, sym_node
);
416 // TODO: check for duplicate fields
417 } while (TOK
== ',' ? (lex_next(LEX
), true) : false);
420 cc_expect(cc
, "field or \"}\"");
422 cc_accept(cc
, "\";\"", ';', 0);
424 cc_accept(cc
, "\"}\"", '}', 0);
427 stree_append_child(cc
->scope
, tag
);
428 struct_type_info
->base_type
= BT_STRUCT
;
429 struct_type_info
->node
= tag
;
433 static bool cc_parse_type(struct cc
*cc
, struct btype
*type_info
)
435 type_info
->base_type
= 0;
436 type_info
->qualifiers
= 0;
439 type_info
->base_type
= BT_VOID
; // well, it's a type, isn't it?
440 // (HINT: the check for variables of type void is not done here)
443 type_info
->base_type
= BT_CHAR
;
446 type_info
->base_type
= BT_INT
;
449 type_info
->base_type
= BT_FLOAT
;
452 type_info
->base_type
= BT_DOUBLE
;
456 return cc_parse_struct(cc
, type_info
);
464 // Parse a pointer type: next token must be after initial type declaration
466 // ^--current token: '*'
467 // Returns a sub-stree of additional type information.
468 // THIS MUST BE PUT SOMEWHERE IN A TREE.
469 // *type_info will be modified to represent the new pointer type
470 static struct stree
*cc_parse_pointer_type(struct cc
*cc
, struct btype
*type_info
)
472 struct stree
*type_node
= NULL
, *new_type_node
;
474 // create a type node to store the excess type information
475 new_type_node
= stree_create();
476 new_type_node
->form
= STF_TYPE
;
477 new_type_node
->btype
= *type_info
;
479 stree_append_child(type_node
, new_type_node
);
481 type_node
= new_type_node
;
482 // create pointer type
483 type_info
->base_type
= BT_POINTER
;
484 type_info
->qualifiers
= 0; // TODO: parse qualifiers
485 type_info
->node
= new_type_node
;
492 // Parse function parameters
493 // void foo(int a, int b);
494 // ^-- current token: 'int'
495 // returns an STF_PARAMETERS node full of parameters, or
496 // NULL if there aren't any.
497 static struct stree
*cc_parse_parameters(struct cc
*cc
)
499 struct stree
*parameters
= NULL
;
500 if (TOK
== TOK_void
){
501 // just 'void' - no parameters
503 } else if (TOK
!= ')'){
504 parameters
= stree_create(); // create parameter list
505 parameters
->form
= STF_PARAMETERS
;
507 struct btype type_info
;
508 struct stree
*type_node
, *param_node
;
509 if (TOK
== TOK_ELLIPSIS
){
511 param_node
= stree_create();
512 param_node
->form
= STF_VARIABLE
;
513 param_node
->tok
= TOK_ELLIPSIS
;
514 if (stree_child_count(parameters
) == 0){
515 cc_error(cc
, "a named argument is required before \"...\"");
519 cc_error(cc
, "variadic function's \"...\" must be placed at the end of the parameter list");
520 cc_sync(cc
, ')', ';', 0);
523 // parse parameter's type
524 if (!cc_parse_type(cc
, &type_info
)){
525 cc_expect(cc
, "type");
527 type_node
= cc_parse_pointer_type(cc
, &type_info
);
528 // create parameter node
529 param_node
= stree_create();
530 param_node
->form
= STF_VARIABLE
;
531 param_node
->btype
= type_info
;
532 // save extra type info, if there is any
534 stree_append_child(param_node
, type_node
);
536 // does the parameter have a name yet? it may not.
537 if (lex_is_ident(LEX
, TOK
)){
538 // parameter has a name
539 param_node
->tok
= TOK
;
542 // if it doesn't, that's ok too
543 // as long as it's not a function definition;
544 // we don't know yet, though.
546 // Now, put the parameter in the list
547 stree_append_child(parameters
, param_node
);
548 } while (TOK
== ',' ? (lex_next(LEX
), true) : false);
550 cc_accept(cc
, "\")\"", ')', 0);
554 // return true if the two types are identical
555 static bool type_identical(struct btype
*type1
, struct btype
*type2
)
558 if (type1
->base_type
!= type2
->base_type
)
560 // TODO: check qualifiers?
561 if (type1
->base_type
== BT_POINTER
){
562 // compare pointed types
563 type1
= &type1
->node
->btype
;
564 type2
= &type2
->node
->btype
;
567 return true; // all checks passed
570 // compare two functions, func1 and func2, for compatibility
571 static void cc_compare_functions(struct cc
*cc
, struct stree
*func1
, struct stree
*func2
)
573 struct stree
*param_list_1
, *param_list_2
, *param_1
, *param_2
;
575 if (!type_identical(&func1
->btype
, &func2
->btype
)){
576 cc_error_loc(cc
, &func2
->sloc
, "conflicting types for \"%s\"",
577 lex_get_tok_str(LEX
, func2
->tok
, NULL
));
578 cc_error_loc(cc
, &func1
->sloc
, "previous declaration of \"%s\" was here",
579 lex_get_tok_str(LEX
, func1
->tok
, NULL
));
582 param_list_1
= stree_get_child_by_form(func1
, STF_PARAMETERS
);
583 param_list_2
= stree_get_child_by_form(func2
, STF_PARAMETERS
);
584 if (stree_child_count(param_list_1
) != stree_child_count(param_list_2
)){
585 cc_error_loc(cc
, &func2
->sloc
, "conflicting number of parameters for \"%s\"",
586 lex_get_tok_str(LEX
, func2
->tok
, NULL
));
587 cc_error_loc(cc
, &func1
->sloc
, "previous declaration of \"%s\" was here",
588 lex_get_tok_str(LEX
, func1
->tok
, NULL
));
593 while (stree_next_child(param_list_1
, ¶m_1
),
594 stree_next_child(param_list_2
, ¶m_2
),
595 (param_1
&& param_2
)){
597 if (param_1
->tok
== TOK_ELLIPSIS
|| param_2
->tok
== TOK_ELLIPSIS
){
599 if (param_1
->tok
== TOK_ELLIPSIS
&& param_2
->tok
== TOK_ELLIPSIS
){
602 cc_error_loc(cc
, &func2
->sloc
, "\"%s\" is %svariadic, unlike previous declaration",
603 lex_get_tok_str(LEX
, func2
->tok
, NULL
),
604 param_1
->tok
== TOK_ELLIPSIS
? "not " : "");
605 cc_error_loc(cc
, &func1
->sloc
, "previous declaration of \"%s\" was here",
606 lex_get_tok_str(LEX
, func1
->tok
, NULL
));
609 // compare parameter types
610 else if (!type_identical(¶m_1
->btype
, ¶m_2
->btype
)){
611 cc_error_loc(cc
, &func2
->sloc
, "conflicting types for parameter %d of \"%s\"",
612 n
, lex_get_tok_str(LEX
, func2
->tok
, NULL
));
613 cc_error_loc(cc
, &func1
->sloc
, "previous declaration of \"%s\" was here",
614 lex_get_tok_str(LEX
, func1
->tok
, NULL
));
616 // merge name information
618 param_1
->tok
= param_2
->tok
;
623 static void cc_parse_decl_function(struct cc
*cc
, struct stree
**psym_node
)
625 struct stree
*parameters
, *prev_decl
;
626 struct stree
*sym_node
= *psym_node
;
627 if (!cc_isglobal(cc
)){
628 struct stree
*current_func
;
629 current_func
= cc_get_current_func(cc
);
630 cc_error(cc
, "nested functions are not permitted: \"%s\" inside \"%s\"",
631 lex_get_tok_str(LEX
, sym_node
->tok
, NULL
),
632 current_func
? lex_get_tok_str(LEX
, current_func
->tok
, NULL
) : "???");
634 // find previous declaration of this symbol
635 prev_decl
= stree_find_local(cc
->scope
, STF_FUNCTION
, sym_node
->tok
);
636 if (!prev_decl
) prev_decl
= stree_find_local(cc
->scope
, STF_VARIABLE
, sym_node
->tok
);
638 if (prev_decl
->form
== STF_FUNCTION
){
639 // must check that declarations match later
641 cc_error_loc(cc
, &sym_node
->sloc
,
642 "\"%s\" declared as different kind of symbol",
643 lex_get_tok_str(LEX
, sym_node
->tok
, NULL
));
644 cc_error_loc(cc
, &prev_decl
->sloc
,
645 "previous declaration of \"%s\" was here",
646 lex_get_tok_str(LEX
, sym_node
->tok
, NULL
));
649 sym_node
->form
= STF_FUNCTION
;
651 lex_next(LEX
); // eat '('
652 parameters
= cc_parse_parameters(cc
);
654 stree_append_child(sym_node
, parameters
);
656 if (prev_decl
&& prev_decl
->form
== STF_FUNCTION
){
657 // make sure declarations match
658 cc_compare_functions(cc
, prev_decl
, sym_node
);
659 // either way, we don't want two copies, so delete the later one
660 stree_destroy(sym_node
);
665 static void cc_parse_decl_variable(struct cc
*cc
, struct stree
*sym_node
)
667 struct stree
*prev_defn
;
668 if (sym_node
->btype
.base_type
== BT_VOID
){
669 cc_error_loc(cc
, &sym_node
->sloc
, "cannot declare variable \"%s\" of type void: impossible without vacuum pump",
670 lex_get_tok_str(LEX
, sym_node
->tok
, NULL
));
672 prev_defn
= stree_find_local(cc
->scope
, STF_VARIABLE
, sym_node
->tok
);
674 cc_error_loc(cc
, &sym_node
->sloc
, "redefinition of \"%s\"",
675 lex_get_tok_str(LEX
, sym_node
->tok
, NULL
));
676 cc_error_loc(cc
, &prev_defn
->sloc
,
677 "previous definition of \"%s\" was here",
678 lex_get_tok_str(LEX
, sym_node
->tok
, NULL
));
680 sym_node
->form
= STF_VARIABLE
;
683 static void cc_parse_ifstat(struct cc
*cc
)
685 struct stree
*stat
, *expr
, *old_scope
;
686 stat
= stree_create();
687 stat
->form
= STF_STAT
;
689 stree_append_child(cc
->scope
, stat
);
691 cc_accept(cc
, "\"(\"", '(', 0);
692 expr
= cc_parse_expr(cc
);
693 cc_accept(cc
, "\")\"", ')', 0);
694 stree_append_child(stat
, expr
);
695 old_scope
= cc
->scope
;
697 cc_parse_statement(cc
);
698 cc
->scope
= old_scope
;
701 static void cc_parse_statement(struct cc
*cc
)
703 struct stree
*expr
, *block
, *old_scope
;
706 } else if (TOK
== '{'){
708 block
= stree_create();
709 block
->form
= STF_BLOCK
;
710 stree_append_child(cc
->scope
, block
);
711 old_scope
= cc
->scope
;
713 cc_parse_compound_stat(cc
);
714 cc
->scope
= old_scope
;
715 cc_accept(cc
, "\"}\"", '}', 0);
717 expr
= cc_parse_expr(cc
);
719 stree_append_child(cc
->scope
, expr
);
720 cc_accept(cc
, "\";\"", ';', 0);
725 static void cc_parse_compound_stat(struct cc
*cc
)
727 while (TOK
!= 0 && TOK
!= '}'){
728 if (cc_parse_decl(cc
, cc
->scope
)){
731 cc_parse_statement(cc
);
736 static void cc_parse_defn_function(struct cc
*cc
, struct stree
*func
)
738 struct stree
*old_scope
, *block
;
739 // TODO: check presence of parameter names
741 block
= stree_create();
742 block
->sloc
= LEX
->tok_sloc
;
743 block
->form
= STF_BLOCK
;
744 stree_append_child(func
, block
);
745 old_scope
= cc
->scope
;
747 cc_parse_compound_stat(cc
);
748 cc
->scope
= old_scope
;
751 // Parse a declaration/definition.
752 // Returns true if it found one, false if there's no declaration (no tokens will have been eaten).
753 // Will return true on syntax error, since tokens were eaten.
754 static bool cc_parse_decl(struct cc
*cc
, struct stree
*insert_here
)
756 struct btype type_info
, original_type_info
;
757 struct stree
*type_node
, *sym_node
= NULL
;
758 bool was_func_defn
= false;
759 if (cc_parse_type(cc
, &original_type_info
)){
761 // restore the type before the '*'s (pointer types)
762 type_info
= original_type_info
;
763 type_node
= cc_parse_pointer_type(cc
, &type_info
);
764 if (!lex_is_ident(LEX
, TOK
)){
765 cc_expect(cc
, "identifier");
767 stree_destroy(type_node
);
772 // variable declaration or definition
773 // or function declaration or definition
774 sym_node
= stree_create();
775 sym_node
->btype
= type_info
;
777 sym_node
->sloc
= LEX
->tok_sloc
;
779 // put the type info somewhere
781 stree_append_child(sym_node
, type_node
);
785 cc_parse_decl_function(cc
, &sym_node
);
787 // function definition
789 cc_parse_defn_function(cc
, sym_node
);
790 cc_accept(cc
, "\"}\"", '}', 0);
791 was_func_defn
= true;
795 cc_parse_decl_variable(cc
, sym_node
);
798 stree_append_child(insert_here
, sym_node
);
800 } while (TOK
== ',' ? (lex_next(LEX
), true) : false);
802 cc_accept(cc
, "\";\"", ';', 0);
811 void cc_parse(struct cc
*cc
)
813 cc
->stree
= cc
->scope
= stree_create();
815 if (!cc_parse_decl(cc
, cc
->scope
)){