[语法分析]识别变量的分析器

   变量这玩意儿本身很简单,无非是一个标识符开头,然后若干对中间夹着一个算数运算的正反方括号,而分析算术运算节点的任务又可以委托给专门的分析器来做,因此识别变量的分析器本身其实没什么需要做的。下面是它的数据结构。

struct VariableAnalyser {
    memberSyntaxAnalyser
    struct VariableNode* var; // 用来存放识别的变量
};

下面是它的各成员函数的实现,这里用了一种有趣的实现方式。

/* variable-analyser.c */
#include<stdlib.h>
#include"datastruct.h"
#include"syntax-analyser.h"
#include"syntax-node.h"

#include"COOL/MemoryAllocationDebugger.h"

extern struct Stack* analyserStack;
extern struct SyntaxAnalyser* newOperationAnalyser(void);

#define wrapname(name) name ## _VariableAnalyser
void wrapname(consumeIdentifier)(void*, struct Token*);
void wrapname(consumeLBracket)(void*, struct Token*);
void wrapname(consumeRBracket)(void*, struct Token*);

void wrapname(consumeIdentifier)(void* self, struct Token* t)
{
    ((struct VariableAnalyser*)self)->var = newVariableNode(t->image);
    ((struct VariableAnalyser*)self)->consumeToken = wrapname(consumeLBracket);
}

void wrapname(consumeLBracket)(void* self, struct Token* t)
{
    if(LBRACKET == t->type) {
        analyserStack->push(analyserStack, newOperationAnalyser());
    } else {
//        printf("Varaible analyser returns.\n");
        struct VariableNode* var = ((struct VariableAnalyser*)self)->var;
        revert(analyserStack->pop(analyserStack));
        struct SyntaxAnalyser* analyser = analyserStack->peek(analyserStack);
        analyser->consumeNonTerminal(analyser, (struct AbstractSyntaxNode*)var);
        analyser = analyserStack->peek(analyserStack);
        analyser->consumeToken(analyser, t);
    }
}

void wrapname(consumeRBracket)(void* self, struct Token* t)
{
    if(RBRACKET == t->type) {
        ((struct VariableAnalyser*)self)->consumeToken =
                                               wrapname(consumeLBracket);
    } else {
        printf("Expecting `]', but %s\n", t->image);
        // TODO 错误处理
    }
}

void wrapname(consumeNonTerminal)(void* self, struct AbstractSyntaxNode* op)
{
    struct VariableAnalyser* varAna = (struct VariableAnalyser*)self;
    varAna->var->dimInfor->enqueue(varAna->var->dimInfor, op);
    varAna->consumeToken = wrapname(consumeRBracket);
}

struct SyntaxAnalyser* newVariableAnalyser(void)
{
    struct VariableAnalyser* varAna = (struct VariableAnalyser*)
                                      allocate(sizeof(struct VariableAnalyser));
    varAna->consumeToken = wrapname(consumeIdentifier);
    varAna->consumeNonTerminal = wrapname(consumeNonTerminal);
    return (struct SyntaxAnalyser*)varAna;
}
#undef wrapname

你一定还记得在OperationAnalyser的实现中,为了区分当前需要的是一个运算符还是一个数,它的consumeToken函数指向一个分流函数,该分流函数根据当前OperationAnalyserneedFactor成员判断是该调用consumeFactor还是consumeOperator,那是一种不好的实现:本应该可以用多态来实现的部分,却滥用分支语句,这在设计模式上是有问题的。现在VariableAnalyser纠正了这一点。在一个VariableAnalyser刚刚新建时,它的consumeToken函数指向wrapname(consumeIdentifier)函数,然后在该函数内将自身的consumeToken函数改指向wrapname(consumeLBracket)函数。其它的函数中也可以看到类似的小动作。这些小动作使设计更清晰了。

附:一个用来测试语法分析模块的驱动器

    当然,这并不意味着语法分析结束了,还有错误处理没有完成呢。

    这个是语法分析器头文件。记得把分析器结构定义放进 datastruct.h 中。

/* syntax-analyser.h */
#ifndef _SYNTAX_ANALYSER_H
#define _SYNTAX_ANALYSER_H

#include"datastruct.h"

struct SyntaxAnalyser* newOperationAnalyser(void);

void initialLRStates(void);
void destructLRStates(void);
struct SyntaxAnalyser* newLRAnalyser(void);

struct SyntaxAnalyser* newVariableAnalyser(void);

#ifdef _DEBUG_MODE
#include"operation-analyser.c"
#include"lr-analyser.c"
#include"variable-analyser.c"
#endif /* _DEBUG_MODE */

#endif /* _SYNTAX_ANALYSER_H */

    下面这个东西脱胎于OperationAnalyser的测试驱动器。不过也没有处理行号,你可以结合词法分析的测试来进行修改。

#include<stdio.h>

#ifndef _DEBUG_MODE
#define _DEBUG_MODE
#endif /* _DEBUG_MODE */
#include"COOL/MemoryAllocationDebugger.h"

#include"datastruct.h"
#include"syntax-node.h"
#include"syntax-analyser.h"
#include"dfa.h"
#include"dfa.c"

FILE* treeout;

struct FakeDefaultAnalyser {
    memberSyntaxAnalyser
};

struct SyntaxAnalyser* newFakeDefaultAnalyser(void);
void FakeDefaultAnalyser_ConsumeNT(void*, struct AbstractSyntaxNode*);
void FakeDefaultAnalyser_ConsumeT(void*, struct Token*);

struct Stack* analyserStack; // 分析器栈
FILE* input; // 输入文件

// 存放终结符
char buffer[64];
struct Token token = {
    0, SKIP, NULL, buffer
};

int main()
{
    treeout = fopen("syntax.xml", "w"); // 输出为xml
    input = fopen("testin", "r");
    analyserStack = newStack();
    analyserStack->push(analyserStack, newFakeDefaultAnalyser());

    initialLRStates();
    tokenize();
    destructLRStates();

    printf("Test done.\n");
    revert(analyserStack->pop(analyserStack));
    analyserStack->finalize(analyserStack);
    showAlloc;
    fclose(input);
    fclose(treeout);
    return 0;
}

struct SyntaxAnalyser* newFakeDefaultAnalyser(void)
{
    struct SyntaxAnalyser* defAna = (struct SyntaxAnalyser*)
                                  allocate(sizeof(struct FakeDefaultAnalyser));
    defAna->consumeToken = FakeDefaultAnalyser_ConsumeT;
    defAna->consumeNonTerminal = FakeDefaultAnalyser_ConsumeNT;
    return defAna;
}

void FakeDefaultAnalyser_ConsumeNT(void* self, struct AbstractSyntaxNode* node)
{
    printf("\nReturned.\n");
    if(NULL == node) {
        fprintf(treeout, "NULL returned.\n");
    } else {
        fprintf(treeout, "<Jerry>\n");
        node->printree(node, 1);
        fprintf(treeout, "</Jerry>\n");
        node->delNode(node);
    }
}

void FakeDefaultAnalyser_ConsumeT(void* self, struct Token* t)
{
    if(NULL == t->image) {
        printf("Token passed:  %2d / NULL image\n", t->type);
    } else {
        printf("Error before %s\n", t->image);
        exit(1);
    }
}

int nextChar(void)
{
    return fgetc(input);
}

struct Token* firstToken(void)
{
    analyserStack->push(analyserStack, newLRAnalyser());
    return &token;
}

struct Token* nextToken(void)
{
    if(SKIP != token.type) {
        struct SyntaxAnalyser* analyser = (struct SyntaxAnalyser*)
                                          (analyserStack->peek(analyserStack));
        analyser->consumeToken(analyser, &token);
    }
    return &token;
}

void eofToken(void)
{
    nextToken();
    struct SyntaxAnalyser* analyser = (struct SyntaxAnalyser*)
                                      (analyserStack->peek(analyserStack));
    struct Token endToken = {0, END, NULL, NULL};
    analyser->consumeToken(analyser, &endToken);
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值