📄 semantics.cc
字号:
////////////////////////////////////////////////////////////////////////////////// semantics.cc//// Currently, the PL/0 compiler performs the following semantic checks:// - is every identifier declared before use?// - is no identifier declared more than once in the same scope?// - is every lhs of an assignment a variable?// - is every identifier in an expression a variable or constant?// - is every called identifier a subroutine?// - is every declared identifier used somewhere? (warn only if not)//// See file attributes.h for the syntax_tree_t classes.//#include "plzero.h"#include "symtab.h"#include "attributes.h"#include <strstream>////////////////////////////////////////////////////////////////////////////////// Semantics Checking//// Traverse syntax tree, performing semantic checks, creating symbol table// entries, and inserting references to those entries into identifier leaf// nodes. If no errors have been found by the time this routine finishes,// it should be possible to generate code without additional checks.//// Open and close scopes as appropriate, so that symbol table look_up// routine works correctly. When semantic_checks is called by the driver,// the predefined and global scopes are already open.//// Each node in the syntax tree must implement the check_semantics member// function which call check_semantics of any children and also checks the// semantics of the node itself.//void syntax_tree_t::check_semantics(scope_number_t scope){ UNUSED_PARAM(scope); dump_syntax_tree(this); die_compiler("Unexpected call to syntax_tree_t::check_semantics");}void st_token_t::check_semantics(scope_number_t scope){ UNUSED_PARAM(scope);}void st_identifier_t::check_semantics(scope_number_t scope){ UNUSED_PARAM(scope); symbol_entry = symbol_look_up(attributes.text_handle); if (symbol_entry == NULL) issue_error(location, "Undefined identifier.");}void st_identifier_t::set_assigned(void){ if (symbol_entry) { // could be NULL if this was an undefined identifier, in which // case we've already generated a message symbol_entry->set_assigned(location); }}void st_identifier_t::set_used(void){ if (symbol_entry) { // could be NULL if this was an undefined identifier, in which // case we've already generated a message symbol_entry->set_used(location); }}void st_identifier_t::set_called(void){ if (symbol_entry) { // could be NULL if this was an undefined identifier, in which // case we've already generated a message symbol_entry->set_called(location); }}void st_number_t::check_semantics(scope_number_t scope){ UNUSED_PARAM(scope); istrstream ist(token_text(attributes.text_handle).c_str()); ist >> value;}////////// Return the value of this number.//int st_number_t::get_value(void) const{ return value;}void st_operator_t::check_semantics(scope_number_t scope){ UNUSED_PARAM(scope); dump_syntax_tree(this); die_compiler("Unexpected call to st_operator_t::check_semantics");}void st_unary_op_t::check_semantics(scope_number_t scope){ if (operand) operand->check_semantics(scope); st_identifier_t *ip = dynamic_cast<st_identifier_t *>(operand); // may fail (return NULL); operand could be a built-up expression if (ip) { ip->set_used(); }}void st_binary_op_t::check_semantics(scope_number_t scope){ if (left_operand) left_operand->check_semantics(scope); if (right_operand) right_operand->check_semantics(scope); st_identifier_t *ip = dynamic_cast<st_identifier_t *>(left_operand); // may fail (return NULL); operand could be a built-up expression if (ip) { ip->set_used(); } ip = dynamic_cast<st_identifier_t *>(left_operand); // may fail (return NULL); operand could be a built-up expression if (ip) { ip->set_used(); }}void st_statement_t::check_semantics(scope_number_t scope){ UNUSED_PARAM(scope); dump_syntax_tree(this); die_compiler("Unexpected call to st_statement_t::check_semantics");}void st_assignment_t::check_semantics(scope_number_t scope){ if (left_side) left_side->check_semantics(scope); if (right_side) right_side->check_semantics(scope); if (left_side) { // may be NULL if already in error left_side->set_assigned(); } st_identifier_t *ip = dynamic_cast<st_identifier_t *>(right_side); // may fail (return NULL); rhs could be a built-up expression if (ip) { ip->set_used(); } if (next_statement) next_statement->check_semantics(scope);}void st_while_t::check_semantics(scope_number_t scope){ if (condition) condition->check_semantics(scope); if (body) body->check_semantics(scope); if (next_statement) next_statement->check_semantics(scope);}void st_if_t::check_semantics(scope_number_t scope){ if (condition) condition->check_semantics(scope); if (body) body->check_semantics(scope); if (next_statement) next_statement->check_semantics(scope);}void st_call_t::check_semantics(scope_number_t scope){ if (procedure) { procedure->check_semantics(scope); procedure->set_called(); } if (next_statement) next_statement->check_semantics(scope);}void st_declaration_t::check_semantics(scope_number_t scope){ UNUSED_PARAM(scope); dump_syntax_tree(this); die_compiler("Unexpected call to st_declaration_t::check_semantics");}void st_constant_t::check_semantics(scope_number_t scope){ if (identifier) identifier->check_semantics(scope); if (value) value->check_semantics(scope); if (identifier && value) { (void) new se_constant_t(scope, identifier->get_attributes().text_handle, location, value->get_value()); // We ignore the returned pointer because the constructor // automatically adds the symbol to the symbol table. } if (next_declaration) next_declaration->check_semantics(scope);}void st_variable_t::check_semantics(scope_number_t scope){ if (identifier) { (void) new se_variable_t(scope, identifier->get_attributes().text_handle, location); // We ignore the returned pointer because the constructor // automatically adds the symbol to the symbol table. identifier->check_semantics(scope); // note that this call has to come *after* the constructor // call for se_variable_t } if (next_declaration) next_declaration->check_semantics(scope);}void st_procedure_t::check_semantics(scope_number_t scope){ scope_number_t temp_scope = new_scope(); if (identifier) { (void) new se_procedure_t(scope, identifier->get_attributes().text_handle, location, temp_scope); // We ignore the returned pointer because the constructor // automatically adds the symbol to the symbol table. } if (block) { open_scope(temp_scope); if (block) block->check_semantics(temp_scope); close_scope(); } if (identifier) identifier->check_semantics(scope); if (next_declaration) next_declaration->check_semantics(scope);}void st_block_t::check_semantics(scope_number_t scope){ symbol = NULL; if (declarations) declarations->check_semantics(scope); if (body) body->check_semantics (scope); for (symbol_entry_t *p = first_in_scope(scope); p != NULL; p = p->next()) { // Look through symbol table records for given scope, and complain // if any identifiers have not been used or variables not been set p->end_of_scope_check(); } // There really ought to be C++ iterator for the elements of a scope}// End of File
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -