`
NeuronR
  • 浏览: 59021 次
  • 性别: Icon_minigender_1
  • 来自: 武汉
社区版块
存档分类
最新评论

[错误处理]变量分析器 / 语法分析错误提示函数接口

 
阅读更多

    变量分析器本身很简单,它的错误处理不需要弄得太复杂,只对正反方括号做做验证,其它的丢给表达式分析器或者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);
        }
// ...

 

分享到:
评论
2 楼 NeuronR 2009-03-07  
引用
嗯,但是我记得这里还有一处(位置大概就是上一个syntaxError的下方else处)

是我弄掉了
1 楼 lwwin 2009-03-07  
嗯,但是我记得这里还有一处(位置大概就是上一个syntaxError的下方else处):

if(0 != self->opStack->height(self->opStack)) {
        //    printf("ERR #1\n");
        fprintf(stderr, "Error @ line %d\n"
                            "    %s\n",
                            token->line, excessLParent);
        }

于是我自己改为:

if(0 != self->opStack->height(self->opStack)) {
        //    printf("ERR #1\n");
        syntaxErro(excessLParent, t);
        }

不知道是不是我和你的代码又对不上了^^

相关推荐

    基于java实现的语法分析器及词法分析器

    在编程语言处理领域,语法分析器和词法分析器是至关重要的组成部分,它们主要用于解析源代码,将其转化为计算机可以理解的形式。在这个项目中,我们关注的是一个基于Java实现的语法分析器和词法分析器。Java是一种...

    pl0语法分析器

    - **错误处理**:在检测到语法错误时,能够给出有意义的错误消息。 - **中间代码生成**:生成中间表示,如三地址码,为后续的代码优化和目标代码生成做准备。 **5. 编译与运行** 在VC6.0环境中,你需要按照以下步骤...

    Rust 实现的 C 语言词法分析器和语法分析器.zip

    在IT领域,编译是将高级编程语言转换为机器可执行代码的过程,而词法分析器(也称为扫描器)和语法分析器(也称为解析器)是编译器的关键组成部分。Rust是一种系统级编程语言,以其内存安全和性能著称,常用于构建...

    pl0语法分析器(编译原理实验)

    **编译原理实验:PL0语言语法分析器** 在计算机科学领域,编译器是将高级编程语言转换为机器可理解的低级语言的关键工具。编译原理是研究这一过程的理论基础,它包括词法分析、语法分析、语义分析、代码生成等多个...

    词法分析器、语法分析器、语义分析器一起实现

    在编程语言处理领域,词法分析器(Lexer)、语法分析器(Parser)和语义分析器(Semantic Analyzer)是编译器或解释器的核心组成部分。本文将深入探讨这些概念,并结合C语言的实现来理解它们的功能和交互。 首先,...

    语法分析器实验报告.docx

    【语法分析器】是编译器设计中的关键组成部分,它负责根据给定的语法规则对词法分析器产生的单词序列进行语法验证和结构解析。本实验报告详细介绍了使用LL(1)文法分析法来设计和实现一个语法分析器的过程。 **一、...

    南华大学编译原理实验 词法分析器代码报告+语法分析器+期末复习PPT

    例如,对于C语言,保留字如"if"、"else",标识符如变量名,常数如整型或浮点型数值,运算符如"+"、"-",以及分隔符如括号、逗号等,都是词法分析器需要识别的对象。通过词法分析器,源代码被转换成一系列有意义的...

    词法语法分析器

    总的来说,MFC实现的词法语法分析器是编译技术的一个实例,它处理类C语言的源代码,将其分解为词法单元,构建语法结构,生成中间代码,并在过程中进行错误检查。这对于理解和实现编译器有着重要的教育意义,同时也为...

    编译原理c++语法分析器

    以C++类声明为例,语法分析器需要识别出"class"关键字,接着是类名,可能的基类列表,然后是成员变量和成员函数的定义。在这个过程中,分析器需要不断检查当前输入是否符合预定的语法规则,并逐步构建出抽象语法树...

    语法分析器 完美运行

    该标题表明这是一款能够完美运行的语法分析器,意味着它在处理特定语言的语法时表现稳定且准确。 #### 1.2 描述:“很好,适合学习,c语言写的语法分析器。很强大,也很完美。” 这段描述进一步强调了该语法分析器...

    语法分析器 tiny语言语法分析

    Tiny语言是一种简单的编程语言,用于教学或小型应用,其语法分析器的设计和实现对于学习编译原理和技术具有重要意义。 首先,我们要了解什么是语法分析。在编译器的前端,语法分析器(通常称为解析器)根据词法分析...

    语法分析器 Cminus

    在实现Cminus的语法分析器时,开发者需要考虑如何处理语法错误,比如未定义的变量、括号不匹配、运算符优先级错误等。错误处理机制通常包括产生错误消息并尝试恢复解析过程,以便尽可能多地解析源代码。 此外,为了...

    java编写的LR语法分析器(编译原理实验)

    实验结果显示,java编写的LR语法分析器可以正确地读取LR语法表文件,进行语法分析和错误检测,并生成语法树。该实验结果验证了LR语法分析器在编译原理中的重要性,并为后续的编译器设计和实现提供了有价值的参考。

    函数绘图语言的词法分析器

    总之,词法分析器是编译器的第一步,它将源代码分解为易于处理的标记,为后续的语法分析和代码生成奠定了基础。在这个案例中,我们有一个用C语言实现的专门针对函数绘图语言的词法分析器,这为我们提供了一个了解...

    用java语言写的语法分析器

    5. **错误处理**:一个好的语法分析器不仅要正确处理合法的输入,还需要具备良好的错误检测和报告机制,以便于用户定位和修复问题。 通过学习和实践这样的Java语法分析器,开发者不仅可以加深对Java语言的理解,还...

    四川大学 编译原理 Tiny语法分析器 纯代码

    本文介绍了基于Visual Studio 2013的Tiny语言语法分析器的实现,包括核心数据结构的设计、关键函数的功能以及整体流程。通过这个项目的学习,可以深入了解编译原理中的词法分析和语法分析,并掌握如何构建一个简单的...

    编译原理词法分析器语法分析器

    在给定的文件中,`main.cpp`很可能是实现整个编译器或解析器逻辑的主程序文件,其中包含了词法分析器和语法分析器的调用以及可能的错误处理和输出功能。`Scanner.h`是词法分析器的头文件,它可能定义了词法单元的...

    pl0词法语法分析器

    在这个项目中,我们将探讨如何使用C++编写词法分析器和语法分析器来处理PL0语言的源代码。 首先,词法分析器(也称为扫描器或 tokenizer)是编译器的第一个阶段,它读取源代码中的字符流,并将它们转换为有意义的...

    计算器语法分析器

    计算器语法分析器是一种工具,它解析输入的数学表达式并执行计算。在这个示例中,我们使用了两个经典的工具——Flex(词法分析器生成器)和Bison(语法分析器生成器)来创建这个分析器。以下是相关知识点的详细说明...

Global site tag (gtag.js) - Google Analytics