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

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

阅读更多

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

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);
}
分享到:
评论
2 楼 NeuronR 2009-02-25  
lwwin 写道

我承认我懒惰……testin 的内容能不能也放出=3=~

有几个版本
1> 莫名其妙的语法测试
int x, i = 0;
real y[12];

read x;
while(i < 12 && 1) {
	read y[i];
	i = i + 1;
}
break;
c = x[123][z] >= 12 / 5;


2> 冒泡排序

/**************
* bubble sort *
**************/
int max = 128;
int n;
int a[ max ];
int i; int j;
int tmp;

read n;
if(n < max) {
	i = 0;
	while(i < n) {
		read a[i];
		i = i + 1;
	}
	i = 0;
	while(i < n - 1) {
		j = i + 1;
		while(j < n) {
			if(a[j] < a[i]) {
				tmp = a[j];
				a[j] = a[i];
				a[i] = tmp;
			}
			j = j + 1;
		}
		i = i + 1;
	}
	i = 0;
	while(i < n) {
		write a[i];
		i = i + i;
	}
}


3> 闰年判断
int leap = 0;
int year, ytmp;

read year;

// year Mod 4
ytmp = year;
while ( ytmp >= 4 ) {
	ytmp = ytmp - 4;
}
if ( 0 == ytmp )
	leap = leap + 1;

// year Mod 100
ytmp = year;
while ( ytmp >= 100 ) {
	ytmp = ytmp - 100;
}
if ( 0 == ytmp )
	leap = leap - 1;

// year Mod 400
ytmp = year;
while ( ytmp >= 400 ) {
	ytmp = ytmp - 400;
}
if ( 0 == ytmp )
	leap = leap + 1;

/* if leap is 1, the year is a leap year */
write leap;
1 楼 lwwin 2009-02-25  
我承认我懒惰……testin 的内容能不能也放出=3=~

相关推荐

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

    词法分析器的任务是从源代码文本中识别出一个个独立的、有意义的单元,这些单元被称为“记号”或“token”。例如,在Java程序中,记号可能包括关键字(如`public`,`class`),标识符(如变量名、类名),运算符(如...

    语法分析器 Java

    Java的词法分析器需要识别关键字、标识符、常量、运算符等。 2. **文法定义**:项目可能包含一个形式化的Java语法规则定义,例如使用EBNF(扩展巴科斯范式)。 3. **抽象语法树(AST)**:构建AST是语法分析的关键...

    编译原理(词法分析器+语法分析器) 编译原理(词法分析器+语法分析器)

    " 这条语句在语法分析器的作用下,会被解析为一个声明语句,包括类型“int”,变量名“x”,赋值运算符“=”以及数值常量“5”。语法分析器通过递归下降、LL解析、LR解析、LALR解析等多种方法来实现这一过程。 在...

    词法分析器和语法分析器

    语法分析器需要根据语言的语法规则来识别语句的结构,例如,在 C 语言中,一个基本的语句结构是“变量声明”,它由“变量名”、“赋值符号”和“初值”组成。 在本文中,我们将使用 LittleP+ 文法来描述语法分析器...

    语法分析器实验报告.docx

    实验内容包括选取常见的高级语言语法结构(如表达式、条件语句、循环语句等),定义它们的文法规则,并实现一个能够识别这些规则的语法分析器。输入是源程序文件,输出是对源程序的合法性判断,合法则输出"success...

    自己写的cmm语法分析器

    词法分析器通常是通过正则表达式实现的,它可以识别并分离出源代码中的不同部分。 然后,语法分析器开始工作。最常用的是上下文无关文法(CFG,Context-Free Grammar)的解析方法,如LR(Left-to-Right,Rightmost ...

    编译原理 课程设计 语法分析器

    语法分析器通常使用这些文法来识别和构建程序的结构。 4. **解析技术** - **递归下降解析**:一种简单但有限的解析方法,适用于文法规则较简单的语言。 - **LR解析**:自左向右扫描输入,采用右most衍生来构建...

    词法语法分析器(JAVA)

    在Java中,语法分析器会确保代码符合Java语言的语法规则,如类定义、方法声明、变量赋值等。如果代码符合语法规则,语法分析器会生成抽象语法树(Abstract Syntax Tree, AST),这是对源代码的一种结构化表示。 3. ...

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

    本项目的目标是构建一个能够识别并解析Tiny语言源代码的语法分析器。 ##### 2. 词法分析与语法分析 - **词法分析**:词法分析是编译过程的第一步,它负责将源代码转换为一系列的标记(Token)。在这个过程中,源...

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

    LR语法分析器是编译原理中的一种重要技术,用于分析和识别源代码中的语法结构。 LR语法分析器的原理 LR语法分析器是基于上下文无关语法(Context-Free Grammar)和左递归消除(Left Recursion Elimination)技术...

    词法语法分析器

    在类C语言的词法语法分析器中,生成的中间代码可能包括操作符、操作数和临时变量,表示如“a = b + c”这样的表达式。四元码通常包含四个元素:操作、操作数1、操作数2和结果,例如:“ADD r1, r2, r3”,其中r1是...

    C++版C-语法分析器

    词法分析器(也称为扫描器或lexer)首先读取源代码,识别并生成一个个称为标记(tokens)的最小语法单元。这些标记代表了诸如变量名、关键字、操作符等语言元素。接着,语法分析器(也称作解析器)基于这些标记,...

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

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

    Windows下词法分析分析器Flex和语法分析器bison的使用说明.pdf

    《Windows下词法分析分析器Flex和语法分析器Bison的使用详解》 在计算机科学领域,词法分析和语法分析是编译器设计的重要环节。Flex和Bison是两个强大的开源工具,分别用于词法分析和语法分析,尤其在Windows环境下...

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

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

    编译原理词法语法分析器

    词法分析器根据预定义的词法规则(正则表达式或正规文法)识别这些元素,为后续的语法分析提供基础。在本案例中,词法分析器的实现可能基于状态转换图,通过逐字符扫描源代码并根据规则进行状态转移,识别并输出对应...

    pl/0词法分析器和语法分析器(java)

    词法分析器负责识别源代码中的词汇单元,而语法分析器则根据这些词汇单元构建出程序的抽象语法树(AST)。以下是对这两个关键组件的详细解释: **词法分析器(Lexer)** 词法分析器是编译器的第一个阶段,它将源...

    语法分析器+词法分析器

    例如,在处理C++程序时,词法分析器会识别出关键字(如`int`、`if`)、标识符(如变量名)、操作符(如`+`、`-`)以及常量(如数字、字符串)等。在给定的压缩包文件中,"Scanner"可能包含的就是实现词法分析器的...

    java语言编写词法、语法、语义分析器

    例如,Java的语义分析器会检查变量是否在使用前已被正确声明,操作数类型是否匹配运算符,以及方法调用的参数数量和类型是否正确。在Java中,类加载器和类型系统也是语义分析的重要组成部分。 **编译原理在Java中的...

Global site tag (gtag.js) - Google Analytics