编译原理实验:语法分析器

实验二  语法分析

一、实验目的

采用自上而下的方法实现PL/0语言程序的语法分析器,以加深对自上而下语法分析过程的理解。

二、实验要求

1、要求每位同学单独完成语法分析器,并接受检查;

2、撰写实验报告。

(1)对示例PL/0程序进行语法分析后的输出结果;

(2)对示例PL/0程序至少三次不同位置的改动,引入语法错误,给出改动情况和语法分析后的报错的对应;

(3)用流程图或伪代码的形式描述典型子程序的结构(可选);

(4)书写设计和实现的过程中出现的一些问题以及解决方法(可选)。

三、实验内容

1、PL/0文法:

在词法规则基础上,引入一组非终结符和产生式集合构成PL/0语言的上下文无关文法。

VN = { program, block, statement, condition, expression, term, factor }

其中:program为开始符号;

VT = { ident, number, "const", "var", "procedure", "call", "begin", "end", "if", "then", "while", "do", "odd", ".", ",", "=", ";", ":=", "#", "<", ">", "+", "-", "*", "/", "(", ")"  }

其中:ident代表标识符,number代表数值,双引号括起来的符号是源程序中出现的原始字符串(包括关键字、算符等),每个对应一个单词种别。

2、实验步骤

(1)按照EBNF文法设计语法分析程序的整体结构;

(2)针对每个语法单位编写相应的子程序,完成递归下降分析程序。

3、程序功能要求

(1)程序的输入:可以读取标准输入,或者打开指定的源程序文件。

(2)复用实验一的词法分析器代码,词法分析得到的词法单位对应文法中的终结符。

(3)对语法正确的示例程序,分析后给出“语法正确”的提示。如果分析过程中遇到错误不需要尝试恢复分析,停止该次分析过程即可,但应尽量给出说明性较强的错误提示。

以下为待分析代码

// PL/0 demo

(*
	This is a multi-line 
	comment
*)

const limit = 10;
var n, f, test, t1, t2;
begin
     n := 0;
     f := 1;
     while n # limit do
     begin
          n := n + 1;
          f := f * n;
     end;
     test := 1 + 2 - 3 * 4 / ( 5 - 6 ) - 7;
	t1 := test * 2;
	t2 := t1 + test;
     call print;	// print all var
end.

以下为语法分析器实现代码

# include<iostream>
# include<string>
# include<fstream>
# include<sstream>
# include<vector>
# include<map>
#include <iostream>
using namespace std;

//词法分析器
//以下是我对单词种别划分
/*
    关键字:
    begin       0
    end         1
    if          2
    then        3
    while       4
    do          5
    const       6
    var         7
    call        8
    procedure   9
    odd         10

    运算符:
    +           11
    -           12
    *           13
    /           14
    =           15
    #           16
    <           17
    >           18
    =           19
    (           20
    )           21
    ,           22
    .           23
    ;           24

    标识符:    25
    常数:      26
*/

//函数列表
bool isIdentifier(string s);//标识符
bool isKeywords(string s);  //关键字
bool isDigit(string s);     //整型数字
bool isOperator(string s);  //多字符运算符
bool isOperator(char c);    //单字符运算符
string result(string s);    //根据传入的参数s产生对应的输出

//函数实现
bool isIdentifier(string s)
{
    if (!isKeywords(s)) //标识符不能是关键字
    {
        if ((s[0] >= 'a' && s[0] <= 'z') || (s[0] >= 'A' && s[0] <= 'Z'))   //首字母必须是字母
        {
            for (int i = 1; i < s.length(); i++)
            {
                if ((s[i] >= 'a' && s[i] <= 'z') || (s[i] >= 'A' && s[i] <= 'Z')    //非首字母能为字母或数字
                    || (s[i] >= '0' && s[i] <= '9'))
                    continue;
                else return false;
            }
            return true;
        }
        return false;
    }
    return false;
}

bool isKeywords(string s)
{
    static vector<string> keyVec = { "begin" , "end" , "if" , "then" , "while" , "do" , "const" ,"var" , "call" , "procedure" , "odd" };  //PL/0的关键字列表
    vector<string>::iterator result = find(keyVec.begin(), keyVec.end(), s);    //查找字符串是否存在关键词列表中
    if (result != keyVec.end()) //如果结果不为end则存在,也即该词为关键字
        return true;
    else return false;
}

bool isDigit(string s)
{
    if (s[0] >= '0' && s[0] <= '9') //首字符为数字
    {
        for (int i = 1; i < s.length(); ++i)    //后面字符也为数字
            if (s[i] >= '0' && s[i] <= '9')
                continue;
            else return false;
        return true;
    }
    return false;
}

bool isOperator(string s)
{
    static vector<string> opeVec = { "+" , "-" , "*" , "/" , "=", "#" , "<" , ">" , ":=" , "(" , ")" , "," , "." , ";" };   //PL/0的运算符列表
    vector<string>::iterator result = find(opeVec.begin(), opeVec.end(), s);    //
    if (result != opeVec.end())
        return true;
    else return false;
}

bool isOperator(char c)
{
    static vector<char> opeVec = { '+' , '-' , '*' , '/' , '=', '#' , '<' , '>' , '(' , ')' , ',' , '.' , ';' , ':' };    //PL/0的单字符运算符列表,其中单字:应也算为合法
    vector<char>::iterator result = find(opeVec.begin(), opeVec.end(), c);
    if (result != opeVec.end())
        return true;
    else return false;
}

string result(string s) //根据传入的参数s产生对应的输出
{
    //种别码
    //1.标识符
    if (isIdentifier(s))
        return "(标识符--25," + s + ")";

    //2.整型常量
    if (isDigit(s))
        return "(整型常量--26," + s + ")";

    //建立静态字典
    static map<string, string> WordsDictionary;

    //3.关键字
    WordsDictionary["begin"] = "0";
    WordsDictionary["end"] = "1";
    WordsDictionary["if"] = "2";
    WordsDictionary["then"] = "3";
    WordsDictionary["while"] = "4";
    WordsDictionary["do"] = "5";
    WordsDictionary["const"] = "6";
    WordsDictionary["var"] = "7";
    WordsDictionary["call"] = "8";
    WordsDictionary["procedure"] = "9";
    WordsDictionary["odd"] = "10";
    if (isKeywords(s))
        return "(关键字--" + WordsDictionary[s] + "," + s + ")";

    //4.运算符
    WordsDictionary["+"] = "11";
    WordsDictionary["-"] = "12";
    WordsDictionary["*"] = "13";
    WordsDictionary["/"] = "14";
    WordsDictionary["="] = "15";
    WordsDictionary["#"] = "16";
    WordsDictionary["<"] = "17";
    WordsDictionary[">"] = "18";
    WordsDictionary[":="] = "19";
    WordsDictionary["("] = "20";
    WordsDictionary[")"] = "21";
    WordsDictionary[","] = "22";
    WordsDictionary["."] = "23";
    WordsDictionary[";"] = "24";
    if (isOperator(s))
        return "(运算符--" + WordsDictionary[s] + "," + s + ")";
    return "Error";
}

//分析词法,并将其记录下来,用以之后的的语法分析
vector<string> LexicalAnalysis()
{
    string file = ("TestData1.txt");
    ifstream input(file);   //输入文件流,注意编码,文本文件编码格式需和项目一直,否则乱码

    ofstream output("Result.txt", ofstream::app);   //先将TtestData.txt内容拷贝到Result.txt中
    string copy;

    getline(input, copy, '\0');
    cout << copy << endl;   //测试是否正确

    input.close();
    input.open(file);   //此时input已经指到了文件尾,为了后面的读取,需要关闭再打开

    output << "原数据:\n";
    output << copy << endl;
    output << "处理后结果:\n";   //测试结果要求以原数据与结果对照的形式输出并保存在Result.txt中,同时要把结果输出到屏幕。

    string str;
    string words;

    cout << "处理后结果:\n";
    bool skip = false;

    vector<string> AllWords;    //记录所有被识别的单词

    while (getline(input, str)) //读取文件每一次读取一行,遇到EOF结束
    {
        istringstream strCin(str);  //从输入流中获取单词,需要用到输入流对象,即istringstream
        string s;
        if (skip)
        {
            if (str.find("*)") != -1)
                skip = false;
            continue;
        }
        while (strCin >> words)
        {
            if (words == "//")  //跳过注释
                break;
            else if (words == "(*" || words == "*)")
            {
                skip = true;
                break;
            }
            /*注意处理逗号,比如int a,b;这里有一个单词"a,b;”,所以要处理一个字符串里面的各种运算符,但是这样会很麻烦,
            发现没有,用ide写代码写完一句输入分号时,ide会自动加入空格,这样就方便处理多了*/

            //1.首先可以确定的是关键字肯定是单独作为一个单词的
            if (isKeywords(words))
            {
                s = result(words);
                AllWords.push_back(words);  //记录关键字
                cout << s << endl;
                output << s << endl;
                continue;
            }

            //2,对单词进行扫描,肯定是标识符,运算符,逗号分号,数字等等混合在一起的单词
            vector<int> index = { 0 };
            for (int i = 0; i < words.length(); i++)
            {

                //运算符有两位的,比如"<=",">=","==","!="
                if ((i < words.length() - 1) && isOperator(words[i]) && isOperator(words[i + 1]))
                {
                    //但是要注意只有以上四种两位运算符,比如+-,))就不是,但是))还是要输出),)
                    if (string(words.begin() + i, words.begin() + i + 2) == ":=")
                    {
                        if (find(index.begin(), index.end(), i) == index.end()) //避免重复下标
                            index.push_back(i);
                        index.push_back(i + 2);
                        ++i;
                    }
                    else if (isOperator(words[i]))
                    {
                        if (find(index.begin(), index.end(), i) == index.end())
                            index.push_back(i);
                        if (find(index.begin(), index.end(), i + 1) == index.end())
                            index.push_back(i + 1);

                    }
                }
                //逗号,运算符作为分隔
                else if (isOperator(words[i]))
                {
                    if (find(index.begin(), index.end(), i) == index.end())
                        //比如遇到"a,b"这里下标0和1将a分开,1到2将逗号分开,2到3将b分开
                        index.push_back(i);
                    if (find(index.begin(), index.end(), i + 1) == index.end())
                        index.push_back(i + 1);

                    //如果是a<=b这样的呢?一样,先0和1将a分开,1和2将<分开,2和3将=分开
                    //3和4将b分开,然后后面分隔单词时,注意如果相邻都是运算符,则忽略,比如
                    //后面判断到1和2,2和3都是运算符,则忽略2

                }

                for (int i = 0; i < index.size() - 1; i++)
                {
                    string rel;
                    //比如遇到"<=",需要提取”<=“
                    /*if (isOperator(words[index[i]]) && isOperator(words[index[i + 1]]))
                    {
                        rel = result(string(words.begin() + index[i], words.begin() + index[i + 2]));
                        ++i;
                    }
                    else*/
                    rel = result(string(words.begin() + index[i], words.begin() + index[i + 1]));
                    AllWords.push_back(string(words.begin() + index[i], words.begin() + index[i + 1])); //记录单词


                    output << rel << endl;
                    cout << rel << endl;
                }


            }
            if (index.size() == 1)  //考虑一下是不是标识符
            {
                string rel;
                rel = result(words);
                AllWords.push_back(words);//记录标识符
                output << rel << endl;
                cout << rel << endl;
            }
        }
    }
    output.close();
    input.close();
    return AllWords;
}
//词法分析器



//语法分析器
//token数据及下标定义
vector<string> tokens = LexicalAnalysis();
int index = 0;
bool success = true;
string symbolarray[] = { "=", "#", "<", ">" };
int symbollength = 4;

//对实验文档中的消除左递归和回溯的PL/0的EBNF文法分析
/*
    program:程序,由 block 和 "." 组成。
    block:代码块,包含 constdecl、vardecl、procdecl 和 statement 四部分。
    constdecl:常量声明,由可选的 "const" 关键字,多个 constitem,以及 ";" 组成。
    constitem:常量条目,包括标识符 ident 和数字 number 之间的 "=" 号连接。
    vardecl:变量声明,由可选的 "var" 关键字,多个标识符 ident,以及 ";" 组成。
    procdecl:过程声明,由多个 "procedure" 关键字,标识符 ident,代码块 block 和 ";" 组成。
    statement:语句,包括赋值语句 assignstmt、过程调用语句 callstmt、复合语句 compstmt、条件语句 ifstmt 和循环语句 whilestmt。
    assignstmt:赋值语句,包括标识符 ident,":=" 连接后面的 expression。
    callstmt:过程调用语句,包括 "call" 关键字和标识符 ident。
    compstmt:复合语句,由 "begin" 关键字和多个语句 statement,以及 "end" 关键字组成。
    ifstmt:条件语句,由 "if" 关键字、condition、"then" 关键字和语句 statement 组成。
    whilestmt:循环语句,由 "while" 关键字、condition、"do" 关键字和语句 statement 组成。
    condition:条件判断,包括 "odd" 和 expression 之间的关系运算符("="、"#"、"<"、">")。
    expression:表达式,由 term 和多个加减法运算符组成。
    term:项,由 factor 和多个乘除法运算符组成。
    factor:因子,包括可选的正负号、标识符 ident、数字 number 和括号中的 expression。
*/

//函数列表,注释为对应语法单位
void exception_print(int type, string expected);    //打印异常
void match(string expected);           //单输入匹配函数
void match(string expected, bool majority);             //多输入匹配函数
void parse_program();   //program -> block "."
void parse_block();     //block -> constdecl vardecl procdecl statement
void parse_constdecl(); //constdecl ->["const" constitem{ "," constitem } ";"]
void parse_constitem(); //constitem -> ident "=" number
void parse_vardecl();   //vardecl -> ["var" ident {"," ident} ";"]
void parse_procdecl();  //procdecl -> {"procedure" ident ";" block ";"}
void parse_statement(); //statement -> assignstmt | callstmt | compstmt | ifstmt | whilestmt
void parse_assignstmt();//assignstmt ->[ident ":=" expression]
void parse_callstmt();  //callstmt -> ["call" ident]
void parse_compstmt();  //compstmt -> ["begin" statement {";" statement} "end"]
void parse_ifstmt();    //ifstmt -> ["if" condition "then" statement]
void parse_whilestmt(); //whilestmt -> ["while" condition "do" statement]
void parse_condition(); //condition = "odd" expression | expression ("="|"#"|"<"|">") expression
void parse_expression();//expression -> term { ("+"|"-") term}
void parse_term();      //term -> factor {("*"|"/") factor}
void parse_factor();    //factor -> [ "+"|"-"] (ident | number | "(" expression ")")
void parse_ident();     //ident -> letter {letter | digit}
void parse_number();    //number -> digit {digit}

//函数实现
void exception_print(int type, string expected = "")
{
    string rel = "";
    switch (type)
    {
    case 0: //语法错误
        rel = "语法错误:预期为 " + expected + ",但输入的是 " + tokens[index];
        break;
    case 1: //标识符错误
        rel = "标识符 " + tokens[index] + " 格式错误";
        break;
    case 2: //整数错误
        rel = "整数 " + tokens[index] + "格式错误";
        break;
    }
    ofstream output("Result.txt", ofstream::app);
    cout << rel << endl;
    output << rel << endl;
    success = false;
    exit(100);
}

void match(string expected)
{
    if (tokens[index] == expected)
        index++;
    else
        exception_print(0, expected);
}

void match(string expected, bool majority)
{
    bool iseuqal = false;
    for (int i = 0; i < symbollength; i++)
    {
        if (tokens[index] == symbolarray[i])
        {
            index++;
            iseuqal = true;
            break;
        }
        expected += symbolarray[i];
        if (i != symbollength - 1)
            expected += " ";
    }
    if (!iseuqal)
        exception_print(0, expected);
}

void parse_program()
{
    parse_block();
    match(".");
}

void parse_block()
{
    parse_constdecl();
    parse_vardecl();
    parse_procdecl();
    parse_statement();
}

void parse_constdecl()
{
    if (tokens[index] == "const")
    {
        match("const");
        parse_constitem();
        while (tokens[index] == ",")
        {
            match(",");
            parse_constitem();
        }
        match(";");
    }
}

void parse_constitem()
{
    parse_ident();
    match("=");
    parse_number();
}

void parse_vardecl()
{
    if (tokens[index] == "var")
    {
        match("var");
        parse_ident();
        while (tokens[index] == ",")
        {
            match(",");
            parse_ident();
        }
        match(";");
    }
}

void parse_procdecl()
{
    while (tokens[index] == "procedure")
    {
        match("procedure");
        parse_ident();
        match(";");
        parse_block();
        match(";");
    }
}

void parse_statement()
{
    if (isIdentifier(tokens[index]))
        parse_assignstmt();
    else if (tokens[index] == "call")
        parse_callstmt();
    else if (tokens[index] == "begin")
        parse_compstmt();
    else if (tokens[index] == "if")
        parse_ifstmt();
    else if (tokens[index] == "while")
        parse_whilestmt();
}

void parse_assignstmt()
{
    parse_ident();
    match(":=");
    parse_expression();
}

void parse_callstmt()
{
    match("call");
    parse_ident();
}

void parse_compstmt()
{
    match("begin");
    parse_statement();
    while (tokens[index] == ";")
    {
        match(";");
        parse_statement();
    }
    match("end");
}

void parse_ifstmt()
{
    match("if");
    parse_condition();
    match("then");
    parse_statement();
}

void parse_whilestmt()
{
    match("while");
    parse_condition();
    match("do");
    parse_statement();
}

void parse_condition()
{
    if (tokens[index] == "odd")
    {
        match("odd");
        parse_expression();
    }
    else
    {
        parse_expression();
        match("",true);
        parse_expression();
    }
}

void parse_expression()
{
    parse_term();
    while (tokens[index] == "+" || tokens[index] == "-")
    {
        match(tokens[index]);
        parse_term();
    }
}

void parse_term()
{
    parse_factor();
    while (tokens[index] == "*" || tokens[index] == "/")
    {
        match(tokens[index]);
        parse_factor();
    }
}

void parse_factor()
{
    if (tokens[index] == "+" || tokens[index] == "-")
        match(tokens[index]);
    if (isDigit(tokens[index]))
        parse_number();
    else if (isIdentifier(tokens[index]))
        parse_ident();
    else
    {
        match("(");
        parse_expression();
        match(")");
    }
}

void parse_ident()
{
    if (isIdentifier(tokens[index]))
        match(tokens[index]);
    else
        exception_print(1);
}
void parse_number()
{
    if (isDigit(tokens[index]))
        match(tokens[index]);
    else
        exception_print(2);
}

//分析语法,并输出其结果
bool GrammaticalAnalysis()
{
    parse_program();
    ofstream output("Result.txt", ofstream::app);
    if (success)
    {
        cout << "语法正确" << endl;
        output << "语法正确" << endl;
    }
    return success;
}
//语法分析器

//主方法
int main()
{
    GrammaticalAnalysis();
    system("pause");
    return 0;
}

  • 6
    点赞
  • 72
    收藏
    觉得还不错? 一键收藏
  • 8
    评论
递归下降分析法 一、实验目的: 根据某一文法编制调试递归下降分析程序,以便对任意输入的符号串进行分析。本次实验的目的主要是加深对递归下降分析法的理解。 二、实验说明 1、递归下降分析法的功能 词法分析器的功能是利用函数之间的递归调用模拟语法树自上而下的构造过程。 2、递归下降分析法的前提 改造文法:消除二义性、消除左递归、提取左因子,判断是否为LL(1)文法, 3、递归下降分析法实验设计思想及算法 为G的每个非终结符号U构造一个递归过程,不妨命名为U。 U的产生式的右边指出这个过程的代码结构: (1)若是终结符号,则和向前看符号对照, 若匹配则向前进一个符号;否则出错。 (2)若是非终结符号,则调用与此非终结符对应的过程。当A的右部有多个产生式时,可用选择结构实现。 三、实验要求 (一)准备: 1.阅读课本有关章节, 2.考虑好设计方案; 3.设计出模块结构、测试数据,初步编制好程序。 (二)上课上机: 将源代码拷贝到机上调试,发现错误,再修改完善。第二次上机调试通过。 (三)程序要求: 程序输入/输出示例: 对下列文法,用递归下降分析法对任意输入的符号串进行分析: (1)E->eBaA (2)A->a|bAcB (3)B->dEd|aC (4)C->e|dc 输出的格式如下: (1)递归下降分析程序,编制人:姓名,学号,班级 (2)输入一以#结束的符号串:在此位置输入符号串例如:eadeaa# (3)输出结果:eadeaa#为合法符号串 注意: 1.如果遇到错误的表达式,应输出错误提示信息(该信息越详细越好); 2.对学有余力的同学,可以详细的输出推导的过程,即详细列出每一步使用的产生式。 (四)程序思路 0.定义部分:定义常量、变量、数据结构。 1.初始化:从文件将输入符号串输入到字符缓冲区中。 2.利用递归下降分析法分析,对每个非终结符编写函数,在主函数中调用文法开始符号的函数。
pl0语法分析器编译原理实验; 用C写的。 /语法分析过程中 /利用词法分析的结果进行分析 /严格按照PL0程序定义来编写 / /<程序> ::= <程序首部> <分程序>. /<程序首部> ::= PROGRAM <标识符>; /<分程序> ::= [<常量说明部分>][<变量说明部分>][<过程说明部分>]<语句部分> /<常量说明部分> ::= CONST <常量定义>{,<常量定义>}; /<常量定义> ::= <标识符>=<无符号整数> /<变量说明部分> ::= VAR <标识符>{,<标识符>}; /<过程说明部分> ::= <过程首部>;<分程序>;【原课件中没有最后的分号,经分析应该有分号】 /<过程首部> ::= PROCEDURE <标识符> /<语句部分> ::= <语句>|<复合语句> /<复合语句> ::= BEGIN <语句>{;<语句>} END【符合语句应该注意的是,END前距离END最近的那条语句一定没有分号,其他语句必须有分号】 /<语句>::= <赋值语句>|<条件语句>|<当型 循环语句>|<过程调用语句>|<读语句>|<写语句>|<复合语句> /<赋值语句> ::= <标识符>:=<表达式> /<读语句> ::= READ(<标识符>{,<标识符>}) /<写语句> ::= WRITE(<表达式>{,<表达式>}) /<过程调用语句> ::= CALL <标识符>【原课件中有分号,实际不应该有】 /<条件语句> ::= IF <条件> THEN <语句> /<当型循环语句> ::= WHILE <条件> DO <语句> /<因子> ::= <标识符>|<常量>|(<表达式>) /<项> ::= <因子>{<乘法运算符><因子>} /<乘法运算符> ::= *|/ /<表达式> ::= [+|-]<项>{<加法运算符><项>} /<加法运算符> ::= +|- /<条件> ::= <表达式><关系运算符><表达式>|ODD <表达式> /<关系运算符> ::= #|=|>|>=|<|<=
这个里面的都是测试数据,总共得分5分。从控制台输入,不能从文件中读取。实现了基本功能,加分项目都没有去实现,没有函数数组这些的实现。这是用C++语言写的,新建parser类别要选C++,其他对于VS的配置和C语言一样。for语句用的是枚举所有情况,你可以自行修改。 对预备工作中自然语言描述的简化C编译器的语言特性的语法,设计上下文无关文法进行描述 借助Yacc工具实现语法分析器 考虑语法树的构造: 1.语法树数据结构的设计:节点类型的设定,不同类型节点应保存哪些信息,多叉树的实现方式 2.实现辅助函数,完成节点创建、树创建等功能 3.利用辅助函数,修改上下文无关文法,设计翻译模式 4.修改Yacc程序,实现能构造语法树的分析器 考虑符号表处理的扩充 1.完成语法分析后,符号表项应增加哪些标识符的属性,保存语法分析的结果 2.如何扩充符号表数据结构,Yacc程序如何与Lex程序交互,正确填写符号表项 以一个简单的C源程序验证你的语法分析器,可以文本方式输出语法树结构,以节点编号输出父子关系,来验证分析器的正确性,如下例: main() { int a, b; if (a == 0) a = b + 1; } 可能的输出为: 0 : Type Specifier, integer, Children: 1 : ID Declaration, symbol: a Children: 2 : ID Declaration, symbol: b Children: 3 : Var Declaration, Children: 0 1 2 4 : ID Declaration, symbol: a Children: 5 : Const Declaration, value:0, Children: 6 : Expr, op: ==, Children: 4 5 7 : ID Declaration, symbol: a Children: 8 : ID Declaration, symbol: b Children: 9 : Const Declaration, value:1, Children: 10: Expr, op: +, Children: 8 9 11: Expr, op: =, Children: 7 10 12: if statement, Children: 6 11 13: compound statement, Children: 3 12
下面是一个简单的基于C语言实现的LL(1)语法分析器示例代码,仅供参考: ```c #include <stdio.h> #include <stdlib.h> #include <string.h> #define MAX_BUF_SIZE 1024 #define MAX_STACK_SIZE 1024 // 预测分析表 char parsing_table[10][10] = { /* E T F + * ( ) i $ */ {'1', ' ', ' ', ' ', ' ', '2', ' ', '3', ' ', ' '}, // E {' ', '4', ' ', '5', ' ', ' ', ' ', ' ', '6', ' '}, // T {'7', ' ', '8', ' ', ' ', '9', ' ', ' ', '10', ' '}, // F }; // 符号栈 char stack[MAX_STACK_SIZE]; int top = -1; // 输入缓冲区 char buffer[MAX_BUF_SIZE]; int buf_idx = 0; // 读入输入 char read_input() { if (buf_idx == strlen(buffer)) { return '$'; } return buffer[buf_idx++]; } // 获取栈顶元素 char get_top() { if (top >= 0) { return stack[top]; } return ' '; } // 弹出栈顶元素 void pop() { if (top >= 0) { top--; } } // 压入元素到栈顶 void push(char c) { if (top < MAX_STACK_SIZE-1) { stack[++top] = c; } } // LL(1)语法分析 void parse() { push('$'); push('E'); char lookahead = read_input(); while (top >= 0) { char top_char = get_top(); if (top_char == lookahead) { printf("Match %c\n", lookahead); pop(); lookahead = read_input(); } else if (top_char >= 'A' && top_char <= 'Z') { int row = top_char - 'A'; int col = lookahead - '0'; char *production = parsing_table[row][col]; if (production == ' ') { printf("Error: Parsing table entry is empty!\n"); exit(1); } else { printf("Apply production %c -> %s\n", top_char, production); pop(); int i; for (i = strlen(production)-1; i >= 0; i--) { push(production[i]); } } } else { printf("Error: Invalid character %c on stack!\n", top_char); exit(1); } } } int main() { printf("Enter input string: "); fgets(buffer, MAX_BUF_SIZE, stdin); buffer[strlen(buffer)-1] = '\0'; // 去掉换行符 parse(); return 0; } ``` 该代码实现了一个简单的LL(1)语法分析器,其基本思路是:使用一个符号栈来模拟语法分析过程,根据预测分析表进行分析,将分析结果输出为语法树。用户需要输入一个待分析的字符串,程序将输出分析过程中的每个步骤,包括匹配、应用产生式等。需要注意的是,该代码只能处理特定的文法,如果需要处理其他文法,需要修改预测分析表和产生式。

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值