123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238 |
- /*
- * (c) copyright 1987 by the Vrije Universiteit, Amsterdam, The Netherlands.
- * See the copyright notice in the ACK home directory, in the file "Copyright".
- */
- /* $Id$ */
- /* PROGRAM PARSER */
- /* The presence of typedef declarations renders it impossible to
- make a context-free grammar of C. Consequently we need
- context-sensitive parsing techniques, the simplest one being
- a subtle cooperation between the parser and the lexical scanner.
- The lexical scanner has to know whether to return IDENTIFIER
- or TYPE_IDENTIFIER for a given tag, and it obtains this information
- from the definition list, as constructed by the parser.
- The present grammar is essentially LL(2), and is processed by
- a parser generator which accepts LL(1) with tie breaking rules
- in C, of the form %if(cond) and %while(cond). To solve the LL(1)
- ambiguities, the lexical scanner does a one symbol look-ahead.
- This symbol, however, cannot always be correctly assessed, since
- the present symbol may cause a change in the definition list
- which causes the identification of the look-ahead symbol to be
- invalidated.
- The lexical scanner relies on the parser (or its routines) to
- detect this situation and then update the look-ahead symbol.
- An alternative approach would be to reassess the look-ahead symbol
- in the lexical scanner when it is promoted to dot symbol. This
- would be more beautiful but less correct, since then for a short
- while there would be a discrepancy between the look-ahead symbol
- and the definition list; I think it would nevertheless work in
- correct programs.
- A third solution would be to enter the identifier as soon as it
- is found; its storage class is then known, although its full type
- isn't. We would have to fill that in afterwards.
- At block exit the situation is even worse. Upon reading the
- closing brace, the names declared inside the function are cleared
- from the name list. This action may expose a type identifier that
- is the same as the identifier in the look-ahead symbol. This
- situation certainly invalidates the third solution, and casts
- doubts upon the second.
- */
- %lexical LLlex;
- %start C_program, program;
- %start If_expr, control_if_expression;
- {
- #include "lint.h"
- #include "nopp.h"
- #include "debug.h"
- #include <flt_arith.h>
- #include "arith.h"
- #include "LLlex.h"
- #include "idf.h"
- #include "label.h"
- #include "type.h"
- #include "declar.h"
- #include "decspecs.h"
- #include "code.h"
- #include "expr.h"
- #include "def.h"
- #ifdef LINT
- #include "l_lint.h"
- #endif /* LINT */
- #ifndef NOPP
- extern arith ifval;
- #endif /* NOPP */
- extern error();
- }
- control_if_expression
- {
- struct expr *exprX;
- }
- :
- constant_expression(&exprX)
- {
- #ifndef NOPP
- register struct expr *expr = exprX;
- if (expr->ex_flags & EX_SIZEOF)
- expr_error(expr,
- "sizeof not allowed in preprocessor");
- ifval = expr->VL_VALUE;
- free_expression(expr);
- #endif /* NOPP */
- }
- ;
- /* 3.7 */
- program:
- [%persistent external_definition]*
- { unstack_world(); }
- ;
- /* A C identifier definition is remarkable in that it formulates
- the declaration in a way different from most other languages:
- e.g., rather than defining x as a pointer-to-integer, it defines
- *x as an integer and lets the compiler deduce that x is actually
- pointer-to-integer. This has profound consequences, both for the
- structure of an identifier definition and for the compiler.
-
- A definition starts with a decl_specifiers, which contains things
- like
- typedef int
- which is implicitly repeated for every definition in the list, and
- then for each identifier a declarator is given, of the form
- *a()
- or so. The decl_specifiers is kept in a struct decspecs, to be
- used again and again, while the declarator is stored in a struct
- declarator, only to be passed to declare_idf together with the
- struct decspecs.
- With the introduction of prototypes, extra problems for the scope
- administration were introduced as well. We can have, for example,
- int x(double x);
- and
- int x(double x) { ... use(x) ... }
- In the first case, the parameter name can be forgotten, whereas in
- the second case, the parameter should have a block scope. The
- problem lies in the fact that the parameter's type is known before
- the type of the function, which causes the def structure to be on
- the end of the list. Our solution is as follows:
- 1- In case of a declaration, throw the parameter identifier away
- before the declaration of the outer x.
- 2- In case of a definition, the function begin_proc() changes the
- def list for the identifier. This means that declare_idf()
- contains an extra test in case we already saw a declaration of
- such a function, because this function is called before
- begin_proc().
- */
- external_definition
- { struct decspecs Ds;
- struct declarator Dc;
- }
- :
- { Ds = null_decspecs;
- Dc = null_declarator;
- }
- [ %if (DOT != IDENTIFIER || AHEAD == IDENTIFIER)
- decl_specifiers(&Ds)
- |
- {do_decspecs(&Ds);}
- ]
- [
- declarator(&Dc)
- {
- declare_idf(&Ds, &Dc, level);
- #ifdef LINT
- lint_ext_def(Dc.dc_idf, Ds.ds_sc);
- #endif /* LINT */
- }
- [
- function(&Ds, &Dc)
- |
- { if (! Ds.ds_sc_given && ! Ds.ds_typequal &&
- Ds.ds_notypegiven) {
- strict("declaration specifiers missing");
- }
- }
- non_function(&Ds, &Dc)
- ]
- |
- { if (! Ds.ds_sc_given && ! Ds.ds_typequal &&
- Ds.ds_notypegiven) {
- strict("declaration missing");
- }
- }
- ';'
- ]
- {remove_declarator(&Dc); flush_strings(); }
- ;
- non_function(register struct decspecs *ds; register struct declarator *dc;)
- :
- { reject_params(dc);
- }
- [
- initializer(dc->dc_idf, ds->ds_sc)
- |
- { code_declaration(dc->dc_idf, (struct expr *) 0, level, ds->ds_sc); }
- ]
- {
- #ifdef LINT
- lint_non_function_decl(ds, dc);
- #endif /* LINT */
- }
- [
- ','
- init_declarator(ds)
- ]*
- ';'
- ;
- /* 3.7.1 */
- function(struct decspecs *ds; struct declarator *dc;)
- {
- arith fbytes;
- register struct idf *idf = dc->dc_idf;
- }
- :
- {
- #ifdef LINT
- lint_start_function();
- #endif /* LINT */
- idf_initialized(idf);
- stack_level(); /* L_FORMAL1 declarations */
- declare_params(dc);
- begin_proc(ds, idf); /* sets global function info */
- stack_level(); /* L_FORMAL2 declarations */
- declare_protos(dc);
- }
- declaration*
- {
- check_formals(idf, dc); /* check style-mixtures */
- declare_formals(idf, &fbytes);
- #ifdef LINT
- lint_formals();
- #endif /* LINT */
- }
- compound_statement
- {
- end_proc(fbytes);
- #ifdef LINT
- lint_implicit_return();
- #endif /* LINT */
- unstack_level(); /* L_FORMAL2 declarations */
- #ifdef LINT
- lint_end_formals();
- #endif /* LINT */
- unstack_level(); /* L_FORMAL1 declarations */
- #ifdef LINT
- lint_end_function();
- #endif /* LINT */
- }
- ;
|