变量分析器本身很简单,它的错误处理不需要弄得太复杂,只对正反方括号做做验证,其它的丢给表达式分析器或者LR分析器去弄就行了。(下面一段话中的括号均指方括号。)
大致的构想是这样的:当需要反括号时,没碰到反括号,直接提示错误,然后装作啥也没发生一样重新看看这个终结符;而遇到除了括号以外的其它符号时,就终止识别(此时变量识别结束,返回)。实现如下:
void wrapname(consumeLBracket)(void* self, struct Token* t)
{
if(LBRACKET == t->type) {
analyserStack->push(analyserStack, newOperationAnalyser());
} else {
/* 返回 */
struct VariableNode* var = ((struct VariableAnalyser*)self)->var;
revert(analyserStack->pop(analyserStack));
struct SyntaxAnalyser* analyser = (struct SyntaxAnalyser*)
(analyserStack->peek(analyserStack));
analyser->consumeNonTerminal(analyser,
(struct AbstractSyntaxNode*)var);
analyser = (struct SyntaxAnalyser*)
(analyserStack->peek(analyserStack));
analyser->consumeToken(analyser, t);
}
}
void wrapname(consumeRBracket)(void* self, struct Token* t)
{
struct VariableAnalyser* varAna = (struct VariableAnalyser*)self;
// 先认为没有错误
varAna->consumeToken = wrapname(consumeLBracket);
// 再来验证符号
if(RBRACKET != t->type) {
/* 符号不对 */
varAna->consumeToken(varAna, t); // 继续分析
}
}
上次说了,如果用一堆printf来弄这些错误处理不太方便,所以这回来把错误提示的接口抽出来,以方便日后维护。对于语法分析,错误提示需要关心的是错误的类型和在哪一个终结符附近出的错。因此接口函数可以这样写
void syntaxError(ErrMsg, struct Token*);
实现则可以这样
void syntaxError(ErrMsg e, struct Token* t)
{
failed = 1;
if(END == t->type) {
fprintf(stderr, "Syntax error at the end of the file.\n"
" %s\n",
e);
} else {
fprintf(stderr, "Syntax error @ line: %d token: `%s'\n"
" %s\n",
t->line, t->image, e);
}
}
那么刚才那些错误提示就可以这样搞
static ErrMsg missingRBracket = "Missing close bracket.";
void wrapname(consumeLBracket)(void* self, struct Token* t)
{
if(LBRACKET == t->type) {
analyserStack->push(analyserStack, newOperationAnalyser());
} else {
/* 返回 */
struct VariableNode* var = ((struct VariableAnalyser*)self)->var;
revert(analyserStack->pop(analyserStack));
struct SyntaxAnalyser* analyser = (struct SyntaxAnalyser*)
(analyserStack->peek(analyserStack));
analyser->consumeNonTerminal(analyser,
(struct AbstractSyntaxNode*)var);
analyser = (struct SyntaxAnalyser*)
(analyserStack->peek(analyserStack));
analyser->consumeToken(analyser, t);
}
}
void wrapname(consumeRBracket)(void* self, struct Token* t)
{
struct VariableAnalyser* varAna = (struct VariableAnalyser*)self;
varAna->consumeToken = wrapname(consumeLBracket);
if(RBRACKET != t->type) {
syntaxError(missingRBracket, t); // and here
varAna->consumeToken(varAna, t);
}
}
再附上之前OperationAnalyser中错误处理的部分,请定位原来的那些输出语句,然后将其改为这些玩意儿。
/* wrapname(consumeOperator) 中 */
// ... 一些 if else 分支过后
else if (isFirstFactor(token->type)) {
struct Token fakeOp = {token->line, PLUS, NULL, "+"};
syntaxError(wantOperator, token); // 0.0
self->consumeToken(self, &fakeOp);
self->consumeToken(self, token);
} else {
struct AbstractSyntaxNode* ret;
struct Operator* topOp = (struct Operator*)
(self->opStack->pop(self->opStack));
while(LPARENT != topOp->op) {
topOp->operate(topOp, self->numStack);
topOp = (struct Operator*)(self->opStack->pop(self->opStack));
}
topOp->operate(topOp, NULL);
ret = (struct AbstractSyntaxNode*)(self->numStack->pop(self->numStack));
if(0 != self->opStack->height(self->opStack)) {
syntaxError(excessLParent, token); // :-p
}
wrapname(cleanup)(self);
struct SyntaxAnalyser* analyser = (struct SyntaxAnalyser*)
(analyserStack->peek(analyserStack));
analyser->consumeNonTerminal(analyser, ret);
analyser = (struct SyntaxAnalyser*)(analyserStack->peek(analyserStack));
analyser->consumeToken(analyser, token);
}
// ...
/* wrapname(consumeFactor) 中 */
// ... 一些 if else 分支过后
struct AbstractSyntaxNode* ret = (struct AbstractSyntaxNode*)
(self->numStack->peek(self->numStack));
if(NULL == ret && 1 == self->opStack->height(self->opStack)) {
self->numStack->pop(self->numStack);
wrapname(cleanup)(self);
struct SyntaxAnalyser* analyser = (struct SyntaxAnalyser*)
(analyserStack->peek(analyserStack));
analyser->consumeNonTerminal(analyser, ret);
analyser = (struct SyntaxAnalyser*)
(analyserStack->peek(analyserStack));
analyser->consumeToken(analyser, token);
} else {
struct Token fakeNum = {token->line, INTEGER, NULL, "0"};
syntaxError(wantFactor, token); // =,=
self->consumeToken(self, &fakeNum);
self->consumeToken(self, token);
}
// ...
本文介绍了一种简单的变量分析器的设计思路,重点在于其错误处理机制。通过验证方括号匹配来确保变量定义的正确性,并采用统一的错误提示接口以简化错误报告。
3267

被折叠的 条评论
为什么被折叠?



