In class we have discussed the use of a symbol table for storing properties gleaned from the declaration of named constants and variables in Clang programs, and for checking that these have been correctly declared and used if they are referred to within statements and expressions. The relevant parts of the code (which appears in full in the source files for the book rather than the book itself) are quoted below for convenience:
OneConst = (. TABLE_entries entry; int value; .) Ident<entry.name> (. entry.idclass = TABLE_consts; .) "=" number ";" (. Table->enter(entry); .) . OneVar = (. TABLE_entries entry; .) (. entry.idclass = TABLE_vars; entry.scalar = true; .) Ident<entry.name> [ UpperBound (. entry.scalar = false; .) ] (. Table->enter(entry); .) . Assignment = Variable ":=" Expression . Variable = (. TABLE_entries entry; .) Designator<classset(TABLE_vars), entry>. Designator<classset allowed, TABLE_entries &entry> = (. TABLE_alfa name; bool found; .) Ident<name> (. Table->search(name, entry, found); if (!found) SemError(202); if (!allowed.memb(entry.idclass)) SemError(206); if (entry.idclass != TABLE_vars) return; .) ( "[" (. if (entry.scalar) SemError(204); .) Expression "]" | (. if (!entry.scalar) SemError(205); .) ) . Expression = ( "+" Term | "-" Term | Term ) { AddOp Term } . Term = Factor { MulOp Factor } . Factor = (. TABLE_entries entry; .) Designator<classset(TABLE_consts, TABLE_vars), entry> | number | "(" Expression ")" . --------------------------------------------------------------------------------------------- // Interface to symbol table for Clang level 1 parser (no code generation) const int TABLE_alfalength = 15; // maximum length of identifiers typedef char TABLE_alfa[TABLE_alfalength + 1]; enum TABLE_idclasses { TABLE_consts, TABLE_vars, TABLE_progs }; struct TABLE_entries { TABLE_alfa name; // identifier TABLE_idclasses idclass; // class bool scalar; }; class TABLE { public: void enter(TABLE_entries &entry); // Adds entry to symbol table void search(char *name, TABLE_entries &entry, bool &found); // Searches table for presence of name. If found then returns entry void printtable(FILE *lst); // Prints symbol table for diagnostic purposes TABLE(REPORT *R); // Initializes symbol table };
In the similar language CS301-1, which forms the focus of the current practical, constants can be declared slightly differently, variables can be of integer or Boolean type, and the grammar for Expressions is different. How would you add attributes/actions to the corresponding parts of the grammar below to be able to exercise the same sorts of semantic constraints? Hint: This introduces the notion of "type checking" which is not present in Clang since Clang only has one type to worry about!
ConstDeclarations = "CONST" OneConst { OneConst } . OneConst = Ident "=" ( number | "TRUE" | "FALSE" ) ";" . VarDeclarations = ( "INT" | "BOOL" ) OneVar { "," OneVar } ";" . OneVar = Ident [ UpperBound ] . Assignment = Variable ":=" Expression . Variable = Designator . Designator = Ident [ "[" Expression "]" ] . Expression = AndExp { "OR" AndExp } . AndExp = RelExp { "AND" RelExp } . RelExp = AddExp [ RelOp AddExp ] . AddExp = MultExp { AddOp MultExp } . MultExp = UnaryExp { MulOp UnaryExp } . UnaryExp = Factor | AddOp UnaryExp | "NOT" UnaryExp . Factor = Designator | number | "TRUE" | "FALSE" | "(" Expression ")" .