编译原理五 LR(1)分析法【C语言实现】

一、实验目的

构造LR分析程序,利用它进行语法分析,判断给出的符号串是否为该文法识别的句子,了解 LR(K)分析方法是严格的从左向右扫描,和自底向上的语法分析方法。 

二、实验预习提示


1、使用 LR 的优点:


(1)LR 分析器能够构造来识别所有能用上下文无关文法写的程序设计语言的结构。
(2)LR 分析方法是已知的最一般的无回溯移进-归约方法,它能够和其他移进-归约方法
一样有效地实现。
(3)LR 方法能分析的文法类是预测分析法能分析的文法类的真超集。
(4)LR 分析器能及时察觉语法错误,快到自左向右扫描输入的最大可能。
为了使一个文法是 LR 的,只要保证当句柄出现在栈顶时,自左向右扫描的移进-归约
分析器能够及时识别它便足够了。当句柄出现在栈顶时,LR 分析器必须要扫描整个栈就可
以知道这一点,栈顶的状态符号包含了所需要的一切信息。如果仅知道栈内的文法符号就能
确定栈顶是什么句柄。LR 分析表的转移函数本质上就是这样的有限自动机。不过,这个有
限自动机不需要根据每步动作读栈,因为,如果这个识别句柄的有限自动机自底向上读栈中
的文法符号的话,它达到的状态正是这时栈顶的状态符号所表示的状态,所以,LR 分析器
可以从栈顶的状态确定它需要从栈中了解的一切。


2、LR 分析器由三个部分组成:


(1)总控程序,也可以称为驱动程序。对所有的 LR 分析器总控程序都是相同的。
(2)分析表或分析函数,不同的文法分析表将不同,同一个文法采用的 LR 分析器不同
时,分析表将不同,分析表又可以分为动作表(ACTION)和状态转换(GOTO)表两
个部分,它们都可用二维数组表示。
(3)分析栈,包括文法符号栈和相应的状态栈,它们均是先进后出栈。
分析器的动作就是由栈顶状态和当前输入符号所决定。
LR 分析器结构:

 其中:SP 为栈指针,S[i]为状态栈,X[i]为文法符号栈。状态转换表用 GOTO[i,X]=j
表示,规定当栈顶状态为 i,遇到当前文法符号为 X 时应转向状态 j,X 为终结符或非终结符。
ACTION[i,a]规定了栈顶状态为 i 时遇到输入符号 a 应执行。动作有四种可能:
(1)移进:
action[i,a]= Sj:状态 j 移入到状态栈,把 a 移入到文法符号栈,其中 i,j 表示状态
号。
(2)归约:
action[i,a]=rk:当在栈顶形成句柄时,则归约为相应的非终结符 A,即文法中有
A->B 的产生式,若 B 的长度为 R(即|B|=R),则从状态栈和文法符号栈中自顶向下去掉
R 个符号,即栈指针 SP 减去 R,并把 A 移入文法符号栈内,j=GOTO[i,A]移进状态栈,
其中 i 为修改指针后的栈顶状态。
(3)接受 acc:
当归约到文法符号栈中只剩文法的开始符号 S 时,并且输入符号串已结束即当前
输入符是'#',则为分析成功。
(4)报错:
当遇到状态栈顶为某一状态下出现不该遇到的文法符号时,则报错,说明输入端不
是该文法能接受的符号串。
3、LL(1)分析法实验设计思想及算法

三、实验过程和指导:


(一)准备:
1.阅读课本有关章节,
2.考虑好设计方案;
3.设计出模块结构、测试数据,初步编制好程序。
(二)上课上机:
将源代码拷贝到机上调试,发现错误,再修改完善。
(三)程序要求:
程序输入/输出示例:
对下列文法,用 LR 分析法对任意输入的符号串进行分析:
(1)E->E+T| E—T (2)E->T (3)T->T*F| T/F (4)T->F (5)F->(E) (6)F->i
输出的格式如下:
(1)LR 分析程序,编制人:姓名,学号,班级
(2)输入一以#结束的符号串(包括+—*/()i#):在此位置输入符号串
(3)输出过程如下: 

 (4)输入符号串为非法符号串(或者为合法符号串)
备注:(1)在“所用产生式”一列中如果对应有推导则写出所用产生式;如果为匹配终结符则
写明匹配的终结符;如分析异常出错则写为“分析出错”;若成功结束则写为“分析成功”。
(2) 在此位置输入符号串为用户自行输入的符号串。
注意:1.表达式中允许使用运算符(+-*/)、分割符(括号)、字符 i,结束符#; 2.如果遇到错误的表达式,应输出错误提示信息(该信息越详细越好);
3.对学有余力的同学,测试用的表达式事先放在文本文件中,一行存放一个表达式,同时以
分号分割。同时将预期的输出结果写在另一个文本文件中,以便和输出进行对照;
(四)程序思路(仅供参考):
模块结构:
(1)定义部分:定义常量、变量、数据结构。
(2)初始化:设立 LR 分析表、初始化变量空间(包括堆栈、结构体、数组、临时变量等);
(3)控制部分:从键盘输入一个表达式符号串;
(4)利用 LR 分析算法进行表达式处理:根据 LR 分析表对表达式符号串进行堆栈(或其
他)操作,输出分析结果,如果遇到错误则显示错误信息。


#include <stdio.h>
#include <stdlib.h>
#define MAXROW 16
#define MAXACTIONCOL 8
#define MAXGOTOCOL 3
#define MAXDEPTH 50
#define MAXCOUNT 9

typedef struct {
    int status;
    char symbol;
}stack_e;
stack_e stack[MAXDEPTH];
int top = 0;
char surplus[MAXDEPTH];
int length = 0;
typedef struct{
    char left;
    const char* right;
    int length;
}grammar;
grammar grammars[MAXCOUNT] = {
        (grammar){'S', "E", 1},
        (grammar){'E', "E+T", 3},
        (grammar){'E', "E-T", 3},
        (grammar){'E', "T", 1},
        (grammar){'T', "T*F", 3},
        (grammar){'T', "T/F", 3},
        (grammar){'T', "F", 1},
        (grammar){'F', "(E)", 3},
        (grammar){'F', "i", 1}
};
int action_tab[MAXROW][MAXACTIONCOL] = {
        { 0, 0, 0, 0, 4, 0, 5, 0},
        { 6, 7, 0, 0, 0, 0, 0, 999},
        {-3,-3, 8, 9, 0,-3, 0,-3},
        {-6,-6,-6,-6, 0,-6, 0,-6},
        { 0, 0, 0, 0, 4, 0, 5, 0},
        {-8,-8,-8,-8, 0,-8, 0,-8},
        { 0, 0, 0, 0, 4, 0, 5, 0},
        { 0, 0, 0, 0, 4, 0, 5, 0},
        { 0, 0, 0, 0, 4, 0, 5, 0},
        { 0, 0, 0, 0, 4, 0, 5, 0},
        { 6, 7, 0, 0, 0,15, 0, 0},
        {-1,-1, 8, 9, 0,-1, 0,-1},
        {-2,-2, 8, 9, 0,-2, 0,-2},
        {-4,-4,-4,-4, 0,-4, 0,-4},
        {-5,-5,-5,-5, 0,-5, 0,-5},
        {-7,-7,-7,-7, 0,-7, 0,-7}
};
int goto_tab[MAXROW][MAXGOTOCOL] = {
        { 1, 2, 3},
        { 0, 0, 0},
        { 0, 0, 0},
        { 0, 0, 0},
        {10, 2, 3},
        { 0, 0, 0},
        { 0,11, 3},
        { 0,12, 3},
        { 0, 0,13},
        { 0, 0,14},
        { 0, 0, 0},
        { 0, 0, 0},
        { 0, 0, 0},
        { 0, 0, 0},
        { 0, 0, 0},
        { 0, 0, 0}
};
const char vt[]={'+','-','*','/','(',')','i','#'};
const char vn[]={'E','T','F'};

void ExitWithStop(int erno)
{
    system("pause");
    exit(erno);
}

void Push(stack_e ele) {
    if (top<MAXDEPTH) {
        stack[++top] = ele;
    }
    else {
        printf("Error:stack is full!\n");
        ExitWithStop(1);
    }
}

stack_e Pop() {
    stack_e ele = stack[top];
    if (top>0) {
        stack[top--] = (stack_e){-1, '\0'};
    }
    else {
        printf("Error:stack is empty!\n");
        ExitWithStop(1);
    }
    return ele;
}

int ConvertInVt(char curch) {
    int i;
    for (i = 0; i < MAXACTIONCOL; ++i) {
        if (vt[i]==curch) {
            return i;
        }
    }
    return -1;
}

int ConvertInVn(char symbol) {
    int i;
    for (i = 0; i < MAXGOTOCOL; ++i) {
        if (vn[i]==symbol) {
            return i;
        }
    }
    return -1;
}

void PrintInfo(char curch) {
    int i;
    int length;
    length = printf("%d",stack[0].status);
    for(i=1;i<=top;++i) {
    	length += printf("%c%d",stack[i].symbol, stack[i].status);
	}
	for(i=0;i<24-length;++i) {
		printf(" ");
	}
	length = printf("%c%s",curch, surplus);
	for(i=0;i<24-length;++i) {
		printf(" ");
	}
}

char NextToken() {
    int i=1;
    char ch = surplus[0];
    while (surplus[i-1]!='\0') {
        surplus[i-1] = surplus[i];
        ++i;
    }
    return ch;
}

void Predict() {
    int flag = 1;
    int action;
    char curch;
    stack[top] = (stack_e){0, '#'};
    curch = NextToken();
    while (flag) {
        action = action_tab[stack[top].status][ConvertInVt(curch)];
        if (999 == action) {
            break;
        } else if (0 == action) {
            PrintInfo(curch);
            printf("Error!\n");
            ExitWithStop(1);
        } else if (action > 0) {
        	PrintInfo(curch);
        	printf("Shift %c\n",curch);
            Push((stack_e){action, curch});
            curch = NextToken();
        } else if (action < 0) {
            int i;
            int go;
            grammar g = grammars[-action];
            PrintInfo(curch);
            printf("Reduce %c with %c->%s\n",g.left,g.left,g.right);
            for (i = g.length-1; i >= 0; --i) {
                Pop();
            }
            go = goto_tab[stack[top].status][ConvertInVn(g.left)];
            Push((stack_e){go, g.left});
        } else {
            printf("Error with Action Table!\n");
            ExitWithStop(1);
        }
    }
    PrintInfo(curch);
    printf("Accepted!\n");
}

int main()
{
    char ch = 0;
    printf("LR method. create by Gaochao,2013***,CS2115\n");
    printf("input a expression within 50 characters which endwith '#':");
    while(ch!='#') {
        ch = getchar();
        if ('+' != ch && '-' != ch && '*' != ch && '/' != ch && '(' != ch && ')' != ch && 'i' != ch && '#' != ch) {
            printf("There are some wrong characters!");
            ExitWithStop(1);
        }
        else {
            surplus[length++] = ch;
        }
    }
    surplus[length] = 0;
    printf("Stack\t\t\tThe remaining string\tAction\n");
    Predict();
    system("pause");
    return 0;
}

  • 16
    点赞
  • 128
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 1
    评论
LR(0)分析表是一种自底向上的语法分析方法,用于分析上下文无关文法。下面是构造LR(0)分析表的C语言代码示例: ```c #include <stdio.h> #include <stdlib.h> #include <string.h> #define MAX_SYMBOLS 100 #define MAX_STATES 100 int num_symbols, num_states; char symbols[MAX_SYMBOLS]; char states[MAX_STATES][MAX_SYMBOLS]; int num_transitions[MAX_STATES][MAX_SYMBOLS]; char transitions[MAX_STATES][MAX_SYMBOLS][MAX_STATES]; int get_symbol_index(char symbol) { for (int i = 0; i < num_symbols; i++) { if (symbols[i] == symbol) { return i; } } return -1; } void add_transition(int state, char symbol, int next_state) { int symbol_index = get_symbol_index(symbol); if (symbol_index == -1) { symbols[num_symbols++] = symbol; symbol_index = num_symbols - 1; } num_transitions[state][symbol_index]++; transitions[state][symbol_index][next_state] = 1;} void print_table() { printf("State\t"); for (int i = 0; i < num_symbols; i++) { printf("%c\t", symbols[i]); } printf("\n"); for (int i = 0; i < num_states; i++) { printf("%d\t", i); for (int j = 0; j < num_symbols; j++) { if (num_transitions[i][j] == 0) { printf(".\t"); } else if (num_transitions[i][j] == 1) { int next_state = -1; for (int k = 0; k < num_states; k++) { if (transitions[i][j][k]) { next_state = k; break; } } printf("%d\t", next_state); } else { printf("{"); for (int k = 0; k < num_states; k++) { if (transitions[i][j][k]) { printf("%d,", k); } } printf("}\t"); } } printf("\n"); } } int main() { // TODO: 构造LR(0)分析表的代码 print_table(); return 0; } ```

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

wangkay88

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值