java语言实现语义分析器代码实现
时间: 2023-07-14 16:13:20 浏览: 191
用java实现的语法分析器
5星 · 资源好评率100%
语义分析器是编译器的重要组成部分,它的主要作用是对语法分析器生成的语法树进行分析,检查程序是否符合语义规则,并生成中间代码。以下是一个简单的Java语言实现语义分析器的代码示例:
```
import java.util.*;
public class SemanticAnalyzer {
private SymbolTable symbolTable; // 符号表
private Stack<DataType> typeStack; // 数据类型栈
private Stack<Integer> dimStack; // 数组维度栈
public SemanticAnalyzer() {
symbolTable = new SymbolTable();
typeStack = new Stack<>();
dimStack = new Stack<>();
}
public void analyze(TreeNode root) {
traverse(root);
}
private void traverse(TreeNode node) {
if (node == null) {
return;
}
switch (node.getType()) {
case PROGRAM:
symbolTable.enterScope();
traverse(node.getChild(0)); // 遍历声明列表
traverse(node.getChild(1)); // 遍历语句块
symbolTable.exitScope();
break;
case VAR_DECL:
DataType dataType = DataType.valueOf(node.getChild(0).getToken().getType().toString());
String varName = node.getChild(1).getToken().getLexeme();
int dim = 0;
if (node.getChild(2) != null) { // 数组声明
dim = Integer.parseInt(node.getChild(2).getToken().getLexeme());
dataType = dataType.getArrayType(dim);
}
if (symbolTable.lookup(varName) != null) {
System.out.println("Semantic Error: Variable " + varName + " has been declared!");
} else {
symbolTable.insert(varName, dataType);
}
break;
case ASSIGN_STMT:
traverse(node.getChild(0)); // 遍历左值表达式
DataType leftType = typeStack.pop();
traverse(node.getChild(1)); // 遍历右值表达式
DataType rightType = typeStack.pop();
if (!leftType.equals(rightType)) {
System.out.println("Semantic Error: Type mismatch in assignment statement!");
}
break;
case ID:
String idName = node.getToken().getLexeme();
Symbol symbol = symbolTable.lookup(idName);
if (symbol == null) {
System.out.println("Semantic Error: Variable " + idName + " has not been declared!");
} else {
typeStack.push(symbol.getDataType());
dimStack.push(0);
}
break;
case ARRAY_REF:
traverse(node.getChild(0)); // 遍历数组名
DataType arrayType = typeStack.pop();
traverse(node.getChild(1)); // 遍历下标表达式
DataType indexType = typeStack.pop();
if (arrayType.getDim() <= 0) {
System.out.println("Semantic Error: " + arrayType + " is not an array!");
typeStack.push(DataType.ERROR);
} else if (!indexType.equals(DataType.INT)) {
System.out.println("Semantic Error: Index of array must be integer!");
typeStack.push(DataType.ERROR);
} else {
int dim = dimStack.pop() + 1;
if (dim >= arrayType.getDim()) {
typeStack.push(arrayType.getBaseType());
} else {
typeStack.push(arrayType.getArrayType(dim));
dimStack.push(dim);
}
}
break;
case ADD_EXPR:
case SUB_EXPR:
case MUL_EXPR:
case DIV_EXPR:
traverse(node.getChild(0)); // 遍历左操作数
DataType left = typeStack.pop();
traverse(node.getChild(1)); // 遍历右操作数
DataType right = typeStack.pop();
if (!left.equals(DataType.INT) || !right.equals(DataType.INT)) {
System.out.println("Semantic Error: Operands in arithmetic expression must be integer!");
}
typeStack.push(DataType.INT);
break;
case GT_EXPR:
case LT_EXPR:
case EQ_EXPR:
case GE_EXPR:
case LE_EXPR:
traverse(node.getChild(0)); // 遍历左操作数
DataType leftOperand = typeStack.pop();
traverse(node.getChild(1)); // 遍历右操作数
DataType rightOperand = typeStack.pop();
if (!leftOperand.equals(rightOperand)) {
System.out.println("Semantic Error: Operands in relational expression must have the same type!");
} else if (leftOperand.equals(DataType.VOID)) {
System.out.println("Semantic Error: Type void cannot be used in relational expression!");
}
typeStack.push(DataType.BOOL);
break;
case IF_STMT:
traverse(node.getChild(0)); // 遍历条件表达式
DataType conditionType = typeStack.pop();
if (!conditionType.equals(DataType.BOOL)) {
System.out.println("Semantic Error: Condition expression in if statement must be boolean!");
}
traverse(node.getChild(1)); // 遍历then语句块
if (node.getChild(2) != null) { // 遍历else语句块
traverse(node.getChild(2));
}
break;
case WHILE_STMT:
traverse(node.getChild(0)); // 遍历条件表达式
DataType whileConditionType = typeStack.pop();
if (!whileConditionType.equals(DataType.BOOL)) {
System.out.println("Semantic Error: Condition expression in while statement must be boolean!");
}
traverse(node.getChild(1)); // 遍历循环体语句块
break;
default:
for (int i = 0; i < node.getNumChildren(); i++) {
traverse(node.getChild(i));
}
break;
}
}
}
```
这个示例中,我们使用了一个`SymbolTable`类来存储符号表,使用了两个栈`typeStack`和`dimStack`来保存数据类型和数组维度。在遍历语法树时,我们根据不同的节点类型进行不同的操作。例如,在变量声明节点中,我们读取数据类型和变量名,并将它们插入符号表中。在赋值语句节点中,我们遍历左值表达式和右值表达式,并检查它们的数据类型是否相同。在数组引用节点中,我们遍历数组名和下标表达式,并检查它们的数据类型是否正确。在算术表达式和关系表达式节点中,我们遍历操作数并检查它们的数据类型是否为整型或布尔型。在条件语句和循环语句节点中,我们遍历条件表达式并检查它的数据类型是否为布尔型。最后,在程序节点中,我们遍历声明列表和语句块,并在进入和退出语句块时分别进入和退出符号表的作用域。
阅读全文