我正在写一个小的PL/0编译器用于实践。
我在编写表达式求值部分时遇到了一些问题。
下面是一个小例子:
-2 + 1
字符串
我的程序逻辑如下:
1.词法分析
根据我找到的文档,在PL/0中没有“负整数”这样的东西,因此-2
将被解析为-
和2
。该步骤的结果是:-
、2
、+
和1
1.句法分析
我在这一步中使用SLR 1,因为表达式是正确的,所以不会发生任何事情。
1.语义分析
程序将在这一步中构建一个 * 抽象语法树 *。原理很简单,一个操作符栈和一个操作数栈共同完成这一部分。但是,“负”号在我的代码中会被当作“减号”处理,我没有好的办法来处理这个问题。
下面是一段显示逻辑的代码:
struct ASTNode {
ASTNode(char op, int val, ASTNode *left = nullptr, ASTNode *right = nullptr);
char _op; // operator
int _val; // operand
shared_ptr<ASTNode> _left; // left child node
shared_ptr<ASTNode> _right; // right child node
};
void semantic_analyzer::construct_tree(vector<string> &tokens) {
stack<shared_ptr<ASTNode>> nodeStack; // operand stack
stack<char> opStack; // operator stack
// iterate tokens and construct part of the AST
for (auto &token : tokens) {
// if the token is a positive integer
if (str_opekit::is_digit(token)) {
int val = stoi(token);
nodeStack.push(make_shared<ASTNode>(' ', val)); // the children will be set as nullptr
}
// If the token is a left paren, push it into operator stack
else if (token == "(") {
opStack.push('(');
}
// If the token is a right paren, pop the operator in the operator stack and calculate result
else if (token == ")") {
// Keep popping operators in the operator stack until reach a left paren
while (opStack.top() != '(') {
// Pop two operands in the operand stack and construct them into a node
shared_ptr<ASTNode> right = nodeStack.top();
nodeStack.pop();
shared_ptr<ASTNode> left = nodeStack.top();
nodeStack.pop();
// Construct a new ASTNode with the two nodes and push into the stack
shared_ptr<ASTNode> node(new ASTNode(opStack.top(), 0, left, right));
opStack.pop();
nodeStack.push(node);
}
opStack.pop(); // pop left paren
}
// If the token is #, which stands for the end of the expression
else if (token == "#") {
break;
}
// If the token is an operator, compare its priority with the operator on the top
// of the stack
else {
char op = token[0];
// while:
// 1. the operator stack is not empty
// 2. the operator on the top of the stack is not a left paren
// 3. the priority of the operator on the top of the stack is higher
while (!opStack.empty() && opStack.top() != '(' &&
is_prior(op, opStack.top()) ) {
// Pop two operands in the stack and construct them into an ASTNode
shared_ptr<ASTNode> right = nodeStack.top();
nodeStack.pop();
shared_ptr<ASTNode> left = nodeStack.top();
nodeStack.pop();
// Construct a new ASTNode with the two nodes and push it into the
// operand stack
shared_ptr<ASTNode> node =
make_shared<ASTNode>(opStack.top(), 0, left, right);
opStack.pop();
nodeStack.push(node);
}
opStack.push(op);
}
}
// Process operators and operands in the stack and construct the tree
while (!opStack.empty()) {
shared_ptr<ASTNode> right = nodeStack.top();
nodeStack.pop();
shared_ptr<ASTNode> left = nodeStack.top();
nodeStack.pop();
shared_ptr<ASTNode> node =
make_shared<ASTNode>(opStack.top(), 0, left, right);
opStack.pop();
nodeStack.push(node);
}
this->_root = nodeStack.top();
nodeStack.pop();
}
型
由于“negative”符号会被解析为“minus”符号,不仅执行结果会出错,而且程序会在空堆栈上调用pop()
,从而导致崩溃。
如果您需要更多关于我的代码的详细信息,请通知我。欢迎任何建议。
EBNF是我以前学过的一门课程。与问题相关的部分如下:
letter ::= a|b|...|X|Y|Z
个digit ::= 0|1|...|8|9
个identifier ::= <letter>{<letter>|<digit>}
个unsigned integer ::= <digit>{<digit>}
个factor ::= <identifier>|<unsigned integer>|...
个item ::= <factor>{<multiplying operator><factor>}
个expression ::= [+|-]<item>{<adding operator><item>}
个
'|'代表'|“在正则表达式中
'{...}'代表正则表达式中的“*”
'[...]'代表“零或一”,与“?“在正则表达式中
2条答案
按热度按时间bejyjqdl1#
解析器必须记下它解析的输入的每个元素。例如,当它看到一个
expression
时,它必须告诉后面的阶段是否只有一个item
,或者是否有多个item
s,中间有adding operator
s以及哪些adding operator
s。(最有可能的是,解析通过构建语法树来实现。)同时,解析器还可以注意到它在第一个
item
之前是看到了+
,-
还是没有看到。就这么简单u91tlkcl2#
你的解析器必须构建例如表达式,由其他表达式和运算符(项)组成。
-
运算符可以同时存在于*prefix position(作为前缀运算符)在
expression
之前和*中缀位置,在两个
expression
之间。当解析器解析第一个标记
-
时,它必须检查它是否可以存在于 * 前缀位置 *,并解析它(使用运算符和表达式发出前缀AST节点)或生成错误。如果解析器在 * 中缀位置 * 检测到-
标记,它必须检查标记是否可以在中缀位置,并生成一个带有left
和right
表达式以及operator
的中缀AST节点。