编译原理实验二_语法分析程序设计

一. 实验目的

理解词法分析器的任务和工作原理;掌握计算机语言语法分析程序的设计方法,并能够针对给定语言的语法规则,使用某种高级编程语言实现其语法分析器。

二. 实验内容

对于只含有+、*运算的算术表达式,编写相应的语法分析程序,要求:

1. 用表驱动的预测分析法进行语法分析。

2. 采用某种高级程序设计语言,设计并实现语法分析程序。

3. 设计恰当的测试用例对语法分析程序进行测试。

三.实验设备

计算机、Windows 操作系统、编程语言集成开发环境。

四.实验原理(或程序框图)及步骤

设计思路

首先明确该语言的语法规则,并用上下文无关文法将语法规则描述出来,并对文法进行消除左递归、提取左因子等操作;设计好文法后,学习表驱动的预测分析法的原理,明确分析过程,然后构造出对应的LL(1)分析表;最后设计测试用例。

在实现时,先将设计好的文法及其分析表输入,用struct type来保存上下无关文法,用数组保存分析表。然后逐行读取文件,调用分析函数。分析函数中每次读取分析栈栈顶元素,剩余栈读取当前待分析元素,然后逐步判读是否为剩余栈最后一个元素、是否元素没完但是分析栈已经为空、都不满足分析当前元素是否为终结符、为非终结符在分析表中查找对应非终结符以及对应元素,输出;一直循环上述,直到分析栈为空或者剩余栈为空。

文法:

E->E+T|T

T->T*F|F

F->(E)|i

消除左递归:                    

                                      

E->TG                               

G->+TG|ε                  

T->FS               

S->*FS|ε             

F->(E)|i              

表4.1 对应文法的LL(1)分析表

非终结符

输入符号

+

*

i

$

E

E->TG

E->TG

G

G->+TG

G->ε

G->ε

T

T->FS

T->FS

S

S->ε

S->*FS

S->ε

S->ε

F

F->(E)

F->i

流程图

图4.1 流程图

数据结构:

Struct

char origin

string array

int length

void init( )

还使用了用数组实现的栈结构。

五.程序源代码

#include <iostream>
#include <string>
#include <fstream>
#include <vector>
#include <cstring>
using namespace std;
const string ExpFileName = "C:/Users/29645/Desktop/语法分析.txt";
char analyeStack[20];                           /*分析栈*/
char restStack[20];                             /*剩余栈*/
//char TOKEN[20];
const string v1 = "i+*$"; /*终结符 */
const string v2 = "EGTSF";      /*非终结符   */
int top, ridx, len; /*len为输入串长度 */
bool endYN =true;

struct type { /*产生式类型定义      */
    char origin;   /*产生式左侧字符 大写字符  */
    string array; /*产生式右边字符 */
    int length;    /*字符个数      */
    type() :origin(NULL), array(""), length(0) {}
    void init(char a, string b) {
        origin = a;
        array = b;
        length = array.length();
    }
};
type e, t, g, g1, s, s1, f, f1; /* 产生式结构体变量 */
type R[10][10];                 /* 预测分析表 */
void print() {/*输出分析栈和剩余栈 */
    for (int i = 0; i <= top + 1; ++i)   /*输出分析栈  */
        cout << analyeStack[i];
    cout << "\t\t";

    for (int i = 0; i < ridx; ++i) /*输出对齐符*/
        cout << ' ';
    for (int i = ridx; i < len; ++i)   /*输出剩余串*/
        cout << restStack[i];
    cout << "\t\t\t";
}
// 读文件
vector<string> readFile(string fileName) {
    vector<string> res;
    try {
        ifstream fin;
        fin.open(fileName);
        string temp;
        while (getline(fin, temp))
            res.push_back(temp);
        return res;
    }
    catch (const exception& e) {
        cerr << e.what() << '\n';
        return res;
    }
}
bool isTerminator(char c) { // 判断是否是终结符
    return v1.find(c) != string::npos;
}
void init(string exp) {//初始化
    top = ridx = 0;
    len = exp.length();     /*分析串长度*/
    for (int i = 0; i < len; ++i)
        restStack[i] = exp[i];
}
void analyze(string exp) {  // 分析一个文法
    init(exp);
    int k = 0;
    analyeStack[top] = '$';
    analyeStack[++top] = 'E'; /*'$','E'进栈*/
    cout << "步骤\t\t分析栈 \t\t剩余字符 \t\t所用产生式 " << endl;
    while (true) {
        char ch = restStack[ridx];//剩余栈,ridx指向待匹配的终结符   
        char x = analyeStack[top--]; /*x为当前栈顶字符*/
        cout << ++k << "\t\t";
        if (ridx >= len - 1) {//到最后一个字符
            if (ch == '$') {//已全部匹配,结束符为$
                if (endYN) {
                    cout << "分析成功!\n" << endl; /*接受 */
                }
                else
                {
                    cout << "分析结束,中途出错!AC!\n" << endl; /*接受 */
                }
                return;
            }
            else {
                cout << "分析出错,结束符不为“$”" << endl;
                return;
            }

        }
        else if (x == '$') {//没匹配完,栈已经空,出错,不满足该文法
            print();
            cout << "分析出错,不满足该文法" << endl;
            return;
        }

        if (isTerminator(x)) {
            if (x == ch) {  // 匹配上了
                print();
                cout << ch << "匹配" << endl;
                ch = restStack[++ridx]; /*下一个输入字符*/
            }
            else {             /*出错处理*/
                print();
                cout << "分析出错,错误终结符为" << ch << endl; /*输出出错终结符*/
                endYN = false;
            }
        }
        else {    /*非终结符处理*/
            int m, n;   // 非终结符下标, 终结符下标
            //string::npos 静态常量,用于表示未找到匹配项的情况
            ( v2.find(x) != string::npos ) ? m = v2.find(x) : m = -1;  // m为-1则说明找不到该非终结符,出错
            ( v1.find(ch) != string::npos ) ? n = v1.find(ch) : n = -1; // n为-1则说明找不到该终结符,出错
            if (m == -1 || n == -1) { /*出错处理*/
                print();
                cout << "分析出错,错误符号为" << ch << endl; /*输出出错非终结符*/
                endYN = false;
                ridx++;
            }
            else {
                type nowType = R[m][n];/*用来接受C[m][n]*/

                if (nowType.origin != NULL) {/*判断是否为空*/
                    print();
                    cout << nowType.origin << "->" << nowType.array <<  endl; /*输出产生式*/
                    for (int j = (nowType.length - 1); j >= 0; --j) /*产生式逆序入栈*/
                        analyeStack[++top] = nowType.array[j];

                }
                else {//分析表中没有配对
                    print();
                    cout << endl;
                    continue;
                }
            }
            //else { /*出错处理*/
            //    print();
            //    cout << "分析出错,错误非终结符为" << x << endl; /*输出出错非终结符*/
            //    return;
            //}
        }
    }
}
int main() {
    e.init('E', "TG"), t.init('T', "FS");
    g.init('G', "+TG");
    s.init('S', "*FS");
    f.init('F', "(E)"), f1.init('F', "i"); /* 结构体变量 */
    /*填充分析表*/
    R[0][0] = R[0][3] = e;
    R[1][1] = g;
    R[1][4] = R[1][5] = g1;
    R[2][0] = R[2][3] = t;
    R[3][2] = s;
    R[3][4] = R[3][5] = R[3][1] = s1;
    R[4][0] = f1; R[4][3] = f;
 
    cout << "读取的文件名为:" << ExpFileName << endl;
    vector<string> exps = readFile(ExpFileName);
    int len = exps.size();
    for (int i = 0; i < len; i++) {
        endYN = true;
        string exp = exps[i];
        cout << "------------------待分析字符串" << i + 1 << ":" << exp << "--------------------" << endl;
      
        cout << "字符串" << i + 1 << ":" << exp << endl;
        analyze(exp);
    }
    return 0;
}

六.实验数据、结果分析

图6.1 测试用例

图6.2 字符串i+i*i$

图6.3 字符串j**i$

图6.4 字符串i-i$

图6.5 字符串i+i*i

图6.6 字符串i+i+**i$

图6.7 字符串iiiii$

七. 实验小结

  • 22
    点赞
  • 17
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
语法分析编译原理中的重要部分,它的作用是将词法分析阶段得到的词法单元序列转换成抽象语法树(AST)或语法分析树(Parse Tree),以便于后续的语义分析、中间代码生成和目标代码生成等环节的进行。在本次实验中,我们将使用Java语言实现一个简单的语法分析器。 实验要求: 1. 实现自顶向下的递归下降分析器。 2. 支持的文法如下: ``` <program> ::= <stmts_list> <stmts_list> ::= <stmt> | <stmts_list> <stmt> <stmt> ::= <if_stmt> | <while_stmt> | <assign_stmt> <if_stmt> ::= if <condition> then <stmts_list> end <while_stmt> ::= while <condition> do <stmts_list> end <assign_stmt> ::= <id> = <expr> <condition> ::= <expr> <relop> <expr> <expr> ::= <term> | <expr> <addop> <term> <term> ::= <factor> | <term> <mulop> <factor> <factor> ::= <id> | <number> | '(' <expr> ')' <relop> ::= '<' | '>' | '=' | '<=' | '>=' | '<>' <addop> ::= '+' | '-' <mulop> ::= '*' | '/' <id> ::= <letter> | <id> <letter> | <id> <digit> <number> ::= <digit> | <number> <digit> <letter> ::= A | B | ... | Z | a | b | ... | z <digit> ::= 0 | 1 | ... | 9 ``` 注意:文法中的关键字 if、then、end、while、do、and 等均为保留字。 3. 实现的语法分析器应具备以下功能: - 能够识别出语法正确的程序,并输出相应的语法分析树或抽象语法树。 - 能够识别出语法错误的程序,并给出相应的错误提示信息。 - 能够处理注释和空格等无意义的字符。 4. 实验提交要求: - 实验报告,包括程序设计实验结果分析。 - 程序源代码。 实验设计思路: 1. 根据给定的文法,设计语法分析器的语法规则和对应的产生式。 2. 编写相应的Java代码,将文法转换为递归下降分析器所需要的形式。 3. 实现从输入的源代码中读取词法单元序列的功能。 4. 实现递归下降分析器的核心算法,对输入的词法单元序列进行语法分析,并构建相应的语法分析树或抽象语法树。 5. 在语法分析过程中,需要处理注释和空格等无意义的字符,以便于正确识别语法错误。 6. 在语法分析过程中,需要对输入的源代码进行错误检查,并给出相应的错误提示信息。 7. 输出语法分析树或抽象语法树,以便于后续的语义分析、中间代码生成和目标代码生成等环节的进行。 实验结果分析: 经过实验测试,我们的语法分析器能够正确地识别出合法的程序,并输出相应的语法分析树或抽象语法树。同时,它也能够正确地识别出语法错误的程序,并给出相应的错误提示信息。总的来说,本次实验取得了较好的实验效果。 实验源代码: 见下方代码框:

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值