/** * Copyright (c) 2000, Fidel Viegas (viegasfh@hotmail.com). * All rights reserved. * * Please read the LICENSE file for license information. * * This is class processes the semantic phase of the compiler. For this tiny compiler, it * just checks if variables were declared before use, because there is only one data type, * which is the integer data type */ package org.sablecc.pascal.semantic; import org.sablecc.pascal.analysis.*; import org.sablecc.pascal.node.*; import java.util.*; public class SemanticAnalyser extends DepthFirstAdapter { // This is were all the variables are stored so that we can later // check if the variable is not duplicate Hashtable table = new Hashtable(); // this method checks if the identifier is already in the symbol // table, and if it is, it generates an error, else it puts it in // the table public void outASingleIdentifierList(ASingleIdentifierList node) { // we store identifiers in uppercase so that we can later track // if it was previously declared. Because the language is case-insensitive // we store the identifier either in lowercase or uppercase. // the getText() method is used to retrieve the image of the token // e.g. if the token is 'hello', it retrieves the hello string. String key = node.getIdentifier().getText().toUpperCase(); // is this identifier in the symbol table? if (table.containsKey(key)) { // the identifier already exists error(0, node.getIdentifier()); // generate an error } else { // this is a new one, then // we use key, key to store the identifier // we only need the key, so that we know if the // identifier is in the symbol table. table.put(key, key); // put the identifier in the table } } // this method checks if the identifier is already in the symbol // table, and if it is, it generates an error, else it puts it in // the table. Basically it does the same as the method above. public void outAMultipleIdentifierList(AMultipleIdentifierList node) { // we store identifiers in uppercase so that we can later track // if it was previously declared. Because the language is case-insensitive // we store the identifier either in lowercase or uppercase. // the getText() method is used to retrieve the image of the token // e.g. if the token is 'hello', it retrieves the hello string. String key = node.getIdentifier().getText().toUpperCase(); // is this identifier in the symbol table? if (table.containsKey(key)) { // the identifier already exists // 0 is the error number for duplicate identifiers // we pass the identifier as an argument, so that // the error method can display the location where // the error occurred. error(0, node.getIdentifier()); // generate an error } else { // this is a new one, then // we use key, key to store the identifier // we only need the key, so that we know if the // identifier is in the symbol table. table.put(key, key); // put the identifier in the table } } // this method checks if the identifier on the left hand side of // the assignment statement has been defined. If it wasn't then it generates an error // message. Pascal does not allow a variable to be used before it was previously // defined. public void outAAssignmentStatement(AAssignmentStatement node) { // Now we see the use of the key in uppercase // for example, a variable x, we can write it in uppercase // or lowercase. In Pascal this is the same variable // we use teh key in uppercase because it was stored in the // hashtable in uppercase String key = node.getIdentifier().getText().toUpperCase(); // is this variable in the symbol table? if (!table.containsKey(key)) { // this was not declared, then // report an error with code 1 error(1, node.getIdentifier()); } } // this method does the same as the outAAssignmentStatement method, but // instead of checking the identifiers on the left hand side, it checks the // identifier on the right hand side. That is, the factor identifier. public void outAIdentifierFactor(AIdentifierFactor node) { // Now we see the use of the key in uppercase // for example, a variable x, we can write it in uppercase // or lowercase. In Pascal this is the same variable // we use teh key in uppercase because it was stored in the // hashtable in uppercase String key = node.getIdentifier().getText().toUpperCase(); // is this variable in the symbol table? if (!table.containsKey(key)) { // this was not declared, then // report an error with code 1 error(1, node.getIdentifier()); } } // here is the method to report the errors private void error(int code, TIdentifier ident) { switch(code) { case 0: System.out.println("Error: [" + ident.getLine() + "," + ident.getPos() + "] Identifier already defined."); break; case 1: System.out.println("Error: [" + ident.getLine() + "," + ident.getPos() + "] Identifier unknown."); break; } System.exit(1); // program terminated abnormally } }