自下而上语法分析-----编译原理------c++

实验三. 自下而上语法分析
1. 实验目的
(1) 给出 PL/0 文法规范,要求编写 PL/0 语言的语法分析程序。
(2) 通过设计、编制、调试一个典型的自下而上语法分析程序,实现对 词法分析程序所提供的单词序列进行语法检查和结构分析,进一步 掌握常用的语法分析方法。
(3) 选择最有代表性的语法分析方法,如算符优先分析法、LR 分析法; 或者调研语法分析器的自动生成工具 YACC 的功能与工作原理,使用 YACC 生成一个自底向上的语法分析器。
2. 实验准备
微机安装好 C 语言,或 C++,或 Visual C++,或自己需要用的语言.
3. 实验内容
已给 PL/0 语言文法,构造表达式部分的语法分析器。

4. 实验要求
(1) 将实验一“词法分析”的输出结果,作为表达式语法分析器的输入,进行语法解析,对于语法正确的表达式,报告“语法正确”;对于语法错误的表达式,报告“语法错误”,指出错误原因。
(2) 把语法分析器设计成一个独立一遍的过程。
(3) 采用递归下降分析法或者采用预测分析法实现语法分析。
5. 设计思想
(1)算符优先分析算法
进行算符优先分析算法时需要构造优先关系表,构造优先关系表至为关键的一步便是构造FIRSTVT和LASTVT。
(2)G(<表达式>):
<表达式> ::= [+|-]<项>{<加法运算符> <项>}
<项> ::= <因子>{<乘法运算符> <因子>}
<因子> ::= <标识符>|<无符号整数>| ‘(’<表达式>‘)’
<加法运算符> ::= +|-
<乘法运算符> ::= |/
<关系运算符> ::= =|#|<|<=|>|>=
<标识符> ::=<字母>{<字母>|<数字>}
<无符号整数> ::= <数字>{<数字>}
<字母> ::= a|b|…|X|Y|Z
<数字> ::= 0|1|…|8|9
常见的文法表示方式:
G(E):
E-> +TK|-TK|TK
K-> AT|ε
T-> FN
N-> MF|ε
A -> +|-
M -> |/
R -> =|#|<|<=|>|>=
D -> 0|1|2|3|4|5|6|7|8|9
Z -> a|b|c|d|e|f|…|x|y|z
P -> DP|D
F -> Z|ZF|FD
由于用词法分析的结果作为输入,为编程方便,没有细分标识符和无符号整数。
a.此文法无公共左因子,也无需消除左递归
b.FIRSTVT集合:
FIRSTVT (表达式)={+,-, 标识符,无符号整数,( ,
,/}
FIRSTVT (项)= {标识符,无符号整数,(,
,/ }
FIRSTVT (因子)= {标识符,无符号整数,( }
FIRSTVT (加法运算符)= {+,-}
FIRSTVT (乘法运算符)={ ,/}
FIRSTVT (关系运算符)={=,#,<,<=,>,>= }
LASTVT集合:
LASTVT (表达式)={+,-, 标识符,无符号整数,),
,/ }
LASTVT (项)= {标识符,无符号整数,),*,/}
LASTVT (因子)= {标识符,无符号整数,)}
LASTVT (加法运算符)= {}
LASTVT (乘法运算符)={}
LASTVT (关系运算符)={}
由b.可构造算符优先表如下:
在这里插入图片描述
(3)子程序算法:(本算法没有细致的划分标识符和无符号整数,直接用上一次实验的词法分析所得结果提取单词编码进行输出判断,在itc上用的cin作为输入)
//FIRSTVT
PROCEDURE INSERT(P,a);
IF NOT F[P,a] THEN
BEGIN
F[P,a] := TRUE
PUSH[P,a] ONTO STACK
END
//主程序
BEGIN
FOR 每一个非终结符P和终结符a
DO F[P,a] := FALSE;
FOR 每个形如 P->a… 或 P->Qa…的产生式
DO INSERT(P,a)
WHILE STACK非空 DO
BEGIN
把STACK的顶项记为(Q,a)弹出去
FOR 每个形如 P->Q…的产生式 DO
INSERT(P,a)
END OF WHILE;
END
//LASTVT
PROCEDURE INSERT(P,a);
IF NOT F[P,a] THEN
BEGIN
F[P,a] := TRUE
PUSH[P,a] ONTO STACK
END
//主程序
BEGIN
FOR 每一个非终结符P和终结符a
DO F[P,a] := FALSE;
FOR 每个形如 P->…a 或 P->…aQ的产生式
DO INSERT(P,a)
WHILE STACK非空 DO
BEGIN
把STACK的顶项记为(Q,a)弹出去
FOR 每个形如 P->…Q的产生式 DO
INSERT(P,a)
END OF WHILE;
END
//优先关系表
FOR 每个产生式 P->X1X2…Xn DO
FOR i := 1 TO n-1 DO
BEGIN
IF Xi和X(i+1)均为终结符
THEN 置 Xi优先级等于X(i+1);
IF i<=n-2 且Xi和X(i+2)都为终结符,但X(i+1)为非终结符
THEN 置 Xi优先级等于X(i+2);
IF Xi为终结符而X(i+1)为非终结符
THEN FOR FIRSTVT(X(i+1))中的每个a DO 置 Xi优先级低于b;
IF Xi为非终结符而X(i+1)为终结符
THEN FOR LASTVT(Xi)中的每个a DO 置 a优先级高于X(i+1);
END
//算符优先
k = 1; S[k] = ‘#’;
REPEAT
把下一个输入符号读进a中;
IF S[k] 属于 VT THEN j = k ELSE j = k-1;
While S[j] > a DO
BEGIN
REPEAT
Q = S[j];
IF S[j-1] 属于 VT THEN j = j-1 ELSE j = j-2
UNTIL S[j] < Q;
把S[j+1]…S[k]归约为某个N;
k = j+1;
S[k] = N;
END OF WHILE;
IF S[j] < a OR S[j] = a THEN
BEGIN k = k+1; S[k] = a END
ELSE ERROR /调用出错诊察程序/
UNTIL a = ‘#’

(4)算法流程图
在这里插入图片描述
(5)输入输出源程序

#include<fstream>
#include<cstring>
#include<string>
#include<fstream>
#include<sstream>
#include<iostream>
#include<map>
#include<bits/stdc++.h>
#define Max 9//MAX根据优先关系表得出
using namespace std;
map<string,int> order;//定义终结符在优先表中的序号
stack<string> symbols,save;//定义两个栈,其中symbols为符号栈,save是用来存储临时变量的
vector<string> Terminator;//使用vector迭代器减少空间的使用,用于数组,操作方便,存放终结符的符号
vector<string>::iterator judge;//使用vector迭代器判断是否为终结符
string sequence[1000];//待输入的符号串
string str;//从文本中读入的字符串
string sym;//当前的符号
map<string,string> Word;//使用map数据结构实现key-value对应
std::map<string,string>::iterator it;//用来遍历key-value对应关系的迭代器
string pointer; //指针
void map_init();//key-value(单词-编码)对应关系进行初始化
void lexicalAnalysis();//词法分析过程
int flag=0;
int number=0;
ifstream file("./2.txt");
int priorityTable[Max][Max]={{0,0,1,1,1,1,1,2,2},//算符优先表,其中0表示“=”,1表示“<”,2表示“>",3表示空
                          {0,0,1,1,1,1,1,2,2},//这张表是在写程序之前根据文法计算出来的,在实现报告中显示
                          {2,2,0,0,1,1,1,2,2},
                          {2,2,0,0,1,1,1,2,2},
                          {2,2,2,2,0,3,3,2,2},
                          {2,2,2,2,3,0,3,2,2},
                          {1,1,1,1,1,1,1,0,2},
                          {2,2,2,2,3,3,0,2,2},
                          {1,1,1,1,1,1,1,1,0}};
void init(){//初始化定义终结符的序列
    order["plus"]=0;
    order["minus"]=1;
    order["times"]=2;
    order["slash"]=3;
    order["ident"]=4;
    order["number"]=5;
    order["lparen"]=6;
    order["rparen"]=7;
    order["#"]=8;
    for(int i=0;i<9;i++){
        Terminator.push_back("plus");
        Terminator.push_back("minus");
        Terminator.push_back("times");
        Terminator.push_back("slash");
        Terminator.push_back("ident");
        Terminator.push_back("number");
        Terminator.push_back("lparen");
        Terminator.push_back("rparen");
        Terminator.push_back("#");
    }
}
int judgePriority(string a,string b){//从算符优先表中判断两个string符号的优先级,以便在算符优先分析函数中对不同关系做出不同的算法分析
    int row,column;//行列对应的符号,与sequence对应
    row=order[a];
    column=order[b];
    if(priorityTable[row][column]==0){//当前关系为“=”
        return 0;
    }else if(priorityTable[row][column]==1){//当前关系为“<”
        return 1;
    }else if(priorityTable[row][column]==2){//当前关系为“>”
        return 2;
    }else return 3;//当前关系为空
}
int advance(){//表示指针的移动
    //getline(infile,str);
    number++;
    int found;
    cin>>str;
    if(number>7){//用于文末终结符的结束   错误判断
        flag++;
        if(flag==1){
            sym="#";
            return 1;
        }
        else if(flag>1){
            return 0;
        }
    }
    found=str.find(',',0);//找“,”的位置
    sym=str.substr(1,found-1);//指定位置复制子字符串,比如(lparen,() --pointer为lparen
    return 1;
}

int SearchTerminator(string c){//判断是不是终结符
    judge=find(Terminator.begin(),Terminator.end(),c);//用find函数从终结符开始到结束逐个查找是否有c
    if(judge == Terminator.end()){
        return 0;//末尾是“#”,指的是分析结束
    }else{
        return 1;
    }
}

int OperatorAnalysis(){//算符优先分析,由p93得
    int k=1,j=0;//初始:深度为1
    string b,q;
    symbols.push("#");//符号栈压入"#"
    while(advance()){//把输入串中下一个字符读进sym中;

        if(SearchTerminator(symbols.top())){//如果栈顶的字符为终结符
            j=k;
            q=symbols.top();//将q指向栈顶
        }else{//不是非终结符
            j=k-1;//从当前栈,指针向下移动一个
            b=symbols.top();//将b指向栈顶
            symbols.pop();
            save.push(b);//放在b中等待规约
            q=symbols.top();//栈顶为指针向下移动一个
        }
        while(judgePriority(q,sym)==2){//优先关系while(symbols[j]>a)
            if(!SearchTerminator(symbols.top())){//非终结符等待归约
               b=symbols.top();
               symbols.pop();
               save.push(b);
            }
            do{//if symbols[j-1]为终结符  j--;否则j:=j-2;
                b=symbols.top();
                symbols.pop();
                save.push(b);
                j--;
                if(SearchTerminator(symbols.top())){
                    q=symbols.top();
                }else{
                    save.push(symbols.top());
                    symbols.pop();
                    q=symbols.top();
                    j--;
                }
            }while(judgePriority(q,b)!=1);//直到symbols[j]<q;
            for(int i=0;i<k-j;i++){//save归约串
                sequence[i]=save.top();
                save.pop();
            }
            if(sequence[0]=="term"){//判断是否为表达式
                if(!((k-j)%2)){
                    cout<<"No,it is wrong.";//表达式归约出错
                    return 0;
                }
                for(int i=0;i<k-j;i++){
                    if(!(i%2)){
                        if(sequence[i]!="term"){
                            cout<<"No,it is wrong.";//表达式归约出错
                            return 0;
                        }
                    }else{
                        if(sequence[i]!="plus"||sequence[i]!="minus"){
                            cout<<"No,it is wrong.";//表达式归约出错
                            return 0;
                        }
                    }
                    k=j+1;
                    symbols.push("expression");
                }
            }else if(sequence[0]=="factor"){//判断是否为项
                if(!((k-j)%2)){
                    cout<<"No,it is wrong.";//项规约出错
                    return 0;
                }
                for(int i=0;i<k-j;i++){
                    if(i%2){
                        if(sequence[i]!="factor"){
                            cout<<"No,it is wrong.";
                            return 0;
                        }
                    }else{
                        if(sequence[i]!="times"||sequence[i]!="slash"){
                            cout<<"No,it is wrong.";
                            return 0;
                        }
                    }

                }
                k=j+1;
                symbols.push("term");
            }else if(sequence[0]=="lparen"){//判断是否为因子
                if(sequence[0]=="lparen"){
                    if((k-j)!=3){
                        cout<<"No,it is wrong.";//因子规约错误
                        return 0;
                    }
                    if(sequence[1]!="expression"||sequence[2]!="rparen"){
                        cout<<"No,it is wrong.";
                        return 0;
                    }
                }
                k=j+1;
                if(symbols.top()!="times"||symbols.top()!="slash"||sym!="times"||sym!="slash"){
                     symbols.push("term");
                }
                else symbols.push("factor");
            }else if(sequence[0]=="number"||sequence[0]=="ident"){//标识符 整数  + - * /
                k=j+1;
                if(symbols.top()!="times"||symbols.top()!="slash"||sym!="times"||sym!="slash"){//加法运算符、乘法运算符
                     symbols.push("term");
                }
                else symbols.push("factor");
            }else{
                cout<<"No,it is wrong.";//字符规约出错
                return 0;
            }
        }
        if(judgePriority(q,sym)==1||judgePriority(q,sym)==0){//symbols[j]</=sym
            k++;
            symbols.push(sym);
        }
    }
    if(k==3){//深度为3时
        for(int i=0;i<3;i++){//判断是否为"#"以此判断表达式是否正确
            b=symbols.top();
            symbols.pop();
            if(i==0&&b!="#"){
                cout<<"No,it is wrong.";//表达式出错
                return 0;
            }else if(i==1&&b!="expression"){
                cout<<"No,it is wrong.";//表达式出错
                return 0;
            }else if(i==2&&b!="#"){
                cout<<"No,it is wrong.";//表达式出错
                return 0;
            }
        }
        return 1;
    }
    else{
       cout<<"No,it is wrong.";//表达式出错
       return 0;
    }
}

void map_init(){//key-value(单词-编码)对应关系进行初始化
    Word["begin"]="beginsym";
    Word["call"]="callsym";
    Word["const"]="constsym";
    Word["do"]="dosym";
    Word["end"]="endsym";
    Word["if"]="ifsym";
    Word["odd"]="oddsym";
    Word["procedure"]="proceduresym";
    Word["read"]="readsym";
    Word["then"]="thensym";
    Word["var"]="varsym";
    Word["while"]="whilesym";
    Word["write"]="writesym";
    Word["+"]="plus";
    Word["-"]="minus";
    Word["*"]="times";
    Word["/"]="slash";
    Word["="]="eql";
    Word["<>"]="neq";
    Word["<"]="lss";
    Word["<="]="leq";
    Word[">"]="gtr";
    Word[">="]="geq";
    Word[":="]="becomes";
    Word["("]="lparen";
    Word[")"]="rparen";
    Word[","]="comma";
    Word[";"]="semicolon";
    Word["."]="period";
    Word["#"]="#";
}
void lexicalAnalysis(){
      string word;//识别单词
    string str;//识别字符
    ifstream infile("./1.txt");
    ofstream outfile("./2.txt");
    ostringstream buf;
    char ch;
    while(buf&&infile.get(ch)) buf.put(ch);//将文件中的字符读出来
    str=buf.str();
    for(std::size_t i=0;i<str.size();i++){//对整个字符串进行遍历
        while(str[i]==' '||str[i]=='\n') i++;//若最开始为空格或换行符,则将指针的位置往后移
        if(isalpha(str[i])){//对标识符和基本字进行识别,调用库函数isalpha()
            word=str[i++];
            while(isalpha(str[i])||isdigit(str[i])){
                word+=str[i++];
            }
            it=Word.find(word);//返回word在Word中的迭代器
            if(it!=Word.end()){//判断是不是基本字,若为基本字则进行输出
                outfile<<"("<<Word[word]<<","<<word<<")"<<endl;
            }
            else{//否则为标识符直接输出
                outfile<<"(ident"<<","<<word<<")"<<endl;
            }
            i--;
        }
        else if(isdigit(str[i])){//判断是不是常数,调用库函数isdigit()
            word=str[i++];
            while(isdigit(str[i])){
                word+=str[i++];
            }
            if(isalpha(str[i])){
                outfile<<"error!"<<endl;
                break;
            }
            else{
                outfile<<"(number"<<","<<word<<")"<<endl;
            }
            i--;
        }else if(str[i]=='<'){//对<,<=,<>分别进行判断
            word=str[i++];
            if(str[i]=='>'){
                word+=str[i];
                outfile<<"("<<Word[word]<<","<<word<<")"<<endl;
            }else if(str[i]=='='){
                word+=str[i];
                outfile<<"("<<Word[word]<<","<<word<<")"<<endl;
            }else if(str[i]!=' '||!isdigit(str[i])||!isalpha(str[i])){
                outfile<<"("<<Word[word]<<","<<word<<")"<<endl;
                 i--;
            }else{
                outfile<<"error!"<<endl;
                break;
            }
        }else if(str[i]=='>'){//对>,>=分别进行判断
            word=str[i++];
            if(str[i]=='='){
                word+=str[i];
                outfile<<"("<<Word[word]<<","<<word<<")"<<endl;
            }else if(str[i]!=' '||!isdigit(str[i])||!isalpha(str[i])){
                outfile<<"("<<Word[word]<<","<<word<<")"<<endl;
                i--;
            }else{
                outfile<<"error!"<<endl;
                break;
            }
        }else if(str[i]==':'){//对:=进行判断
            word=str[i++];
            if(str[i]=='='){
                word+=str[i];
                outfile<<"("<<Word[word]<<","<<word<<")"<<endl;
            }else{
                outfile<<"error!"<<endl;
                break;
            }

        }else{//对其他的基本字依次进行判断
            word=str[i];
            it=Word.find(word);
            if(it!=Word.end()){
                outfile<<"("<<Word[word]<<","<<word<<")"<<endl;
            }else{
                break;
            }
        }
    }
    infile.close();
    outfile.close();
}

int main(){
    //map_init();//key-value(单词-编码)对应关系进行初始化
    //lexicalAnalysis();
    init();//初始化终结符序列
    if(OperatorAnalysis()){
        cout<<"Yes,it is correct."<<endl;//如果算符优先法分析return 1 ,则分析正确
    }
    return 0;
}

在这里插入图片描述

  • 3
    点赞
  • 20
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值