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

实验二. 自上而下语法分析
1. 实验目的
(1) 给出 PL/0 文法规范,要求编写 PL/0 语言的语法分析程序。
(2) 通过设计、编制、调试一个典型的自上而下语法分析程序,实现对 词法分析程序所提供的单词序列进行语法检查和结构分析,进一步 掌握常用的语法分析方法。
(3) 选择最有代表性的语法分析方法,如递归下降分析法、预测分析法; 选择对各种常见程序语言都具备的语法结构,如赋值语句,特别是 表达式,作为分析对象。
2. 实验准备
微机安装好 C 语言,或 C++,或 Visual C++,或自己需要用的语言.
3. 实验内容
已给 PL/0 语言文法,构造表达式部分的语法分析器。

4. 实验要求
(1) 将实验一“词法分析”的输出结果,作为表达式语法分析器的输入,进行语法解析,对于语法正确的表达式,报告“语法正确”;对于语法错误的表达式,报告“语法错误”,指出错误原因。
(2) 把语法分析器设计成一个独立一遍的过程。
(3) 采用递归下降分析法或者采用预测分析法实现语法分析。
5. 设计思想
(1)递归下降分析方法
当一个文法满足LL(1)条件时,就可以为它构造一个不带回溯的自上而下分析程序,这个程序是由一组递归程序组成的,每个过程对应文法的一个非终结符。
(2)G(<表达式>):
<表达式> ::= [+|-]<项>{<加法运算符> <项>}
<项> ::= <因子>{<乘法运算符> <因子>}
<因子> ::= <标识符>|<无符号整数>| ‘(’<表达式>‘)’
<加法运算符> ::= +|-
<乘法运算符> ::= |/
<关系运算符> ::= =|#|<|<=|>|>=
常见的文法表示方式:
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
T -> DT|D
F -> Z|ZF|FD
a.此文法无公共左因子,也无需消除左递归
b.FIRST集合:
FIRST(<表达式>)={+,-,<标识符>,<无符号整数>,(}
FIRST(<项>)={<标识符>,<无符号整数>,(}
FIRST(<因子>)={<标识符>,<无符号整数>,(}
FIRST(<加法运算符>)={+,-}
FIRST(<乘法运算符>)={
,/}
FIRST(<关系运算符>)={=,#,<,<=,>,>=}
c.FOLLOW集合:
FOLLOW(<表达式>)={#,)}
FOLLOW(<项>)={+,-,#,)}
FOLLOW(<因子>)={
,/,+,-,#,)}
FOLLOW(<加法运算符>)={<标识符>,<无符号整数>,(}
FOLLOW(<乘法运算符>)={<标识符>,<无符号整数>,(}
FOLLOW(<关系运算符>)={}
由非终结符分项的FIRST集两两不相交,且一个非终结符的FIRST集和FOLLOW集不相交,所以此文法为LL(1)文法,可以用递归下降分析法。
(3)子程序算法:(本算法没有细致的划分标识符和无符号整数,直接用上一次实验的词法分析所得结果提取单词编码进行输出判断)

 PROCEDURE <表达式>:

BEGIN
IF SYM=’+’ OR SYM=’-’ THEN
BEGIN
ADVANCE;
<项>;
WHINE <加法运算符> DO
BEGIN
ADVANCE;
<项>;
END
END
ELSE ERROR
END

PROCEDURE <项>:
BEGIN
<因子>
WHINE <乘法运算符> DO
BEGIN
ADVANCE;
<因子>;
END
END

PROCEDURE <因子>:
BEGIN
IF SYM=‘标识符’ OR ‘无符号整数’
BEGIN
ADVANCE;
END
ELSE IF SYM=’(’
BEGIN
ADVANCE;
<表达式>
IF SYM=’)’
BEGIN
ADVANCE;
END
ELSE ERROR
END
ELSE ERROR
END

PRODUCE <加法运算符>:
BEGIN
IF SYM=’+’ OR ‘-’
BEGIN
FLAG=TURE
END
ELSE
BEGIN
FLAG=FLASE
END
END

PRODUCE <乘法运算符>:
BEGIN
IF SYM=’*’ OR ‘/’
BEGIN
FLAG=TURE
END
ELSE
BEGIN
FLAG=FLASE
END
END

PRODUCE <关系运算符>:
BEGIN
IF SYM=’=’ OR ‘#’ OR ‘<’ OR ‘<=’ OR ‘>’ OR ‘>=’
BEGIN
FLAG=TURE
END
ELSE
BEGIN
FLAG=FLASE
END
END

PROGRAM PAESER
BEGIN
ADVANCE;
<表达式>
IF SYM<>’#’ THEN ERROR
END
(4)算法流程图
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
(5)输入输出源程序

#include<fstream>
#include<cstring>
#include<string>
#include<fstream>
#include<sstream>
#include<iostream>
#include<map>
#include<bits/stdc++.h>
using namespace std;
map<string,string> Word;//使用map数据结构实现key-value对应
std::map<string,string>::iterator it;//用来遍历key-value对应关系的迭代器
string str;//string变量进行字符识别
string pointer; //指针

void map_init();//key-value(单词-编码)对应关系进行初始化
void lexicalAnalysis();//词法分析过程
void expression();//表达式算法过程
void term();//项算法过程
void factor();//因子算法过程
int additionOperator();//加法运算符算法过程
int MultiplicationExpression();//乘法运算符算法过程
int relationshipOperator();//关系运算符算法过程
int advance();
//全局变量
int error=0;//记录错误的个数
int lparenum=0;//记录左括号的个数
int found;//提取字符串中指针的位置
int flag=0;//记录往后移动一个指针是否正确
int n=0;//记录输入的行数
ifstream file("./2.txt");

int main(){
    map_init();//key-value(单词-编码)对应关系进行初始化
    lexicalAnalysis();
    flag=advance();
    if(flag){//当识别出编码时开始识别表达式
        expression();
    }
    if(flag!=-1&&!error){//当没有出现错误时就表示自上而下语法分析正确
        cout<<"Yes,it is correct."<<endl;
    }

    file.close();
    return 0;
}

int advance(){//表示指针的移动
    if(!getline(file,str)){
        return 0;//到文件末尾结束
    }
    found=str.find(',',0);//查找字符‘,’,返回索引值
    if(found==-1){//没有找到时表示识别错误
        error++;
        cout<<"Syntax error : recognition character error "<<endl;
        return -1;//表示程序错误
    }
    pointer=str.substr(1,found-1);//指定位置复制子字符串,比如(lparen,() --pointer为lparen
    return 1;//返回全局变量str
}


void expression(){
    if(error){//有错误项显示error
        return;
	}
	if((pointer=="plus")||(pointer=="minus")){//当指向'+'或'-'的时候
		flag=advance();//指向下一个单词编码
		if(!error){
            return;
		}
		if(flag==0){
            cout<<"Syntax error : add operator  last missing item"<<endl;
            error++;
			return;
		}
	}
	term();
	if(error){
        return;
	}
	while(additionOperator()){//循环过程:当识别单词编码为plus或minus时,trem()
		flag=advance();
		if(error){
            return;
		}
		if(flag==0){
            cout<<"Syntax error : add operator  last missing item"<<endl;
            error++;
			return;
		}
		term();
		if(error){
            return;
		}
	}
	return;
}

void term(){
    factor();
    if(error){
        return;
    }
	while(MultiplicationExpression()){//循环:当指向单词编码为times或则slash时,factor()
		flag=advance();
		if(error){
            return;
		}
		if(flag==0){
			error++;
			cout<<"Syntax error : multiplication operator missing factor"<<endl;
			return;
		}
		if(error){
            return;
		}
		factor();
		if(error){
            return;
		}
	}
	return;
}

void factor(){
    if(pointer=="ident"||pointer=="number"){//如果识别的是标识符和整数时,指针往后移动,识别单词编码
        flag=advance();
        if(error){
            return;//强制break
		}
		if(lparenum==0&&pointer=="rparen"){
            error++;
			cout<<"Syntax error  : ')' does not match"<<endl;
			return;
        }
    }
    else if(pointer=="lparen"){//如果识别左括号成功,则判断是否为表达式、右括号
        lparenum++;
        flag=advance();
        if(error){
            return;
		}
		if(flag==0){//error : 已到文件末尾,只剩左括号,没有右括号与之匹配
			error++;
			cout<<" Syntax error : '(' followed by missing expression, no ')' matches it"<<endl;
			return;
		}
        expression();
        if(error){
            return;
		}
        if(flag==0||pointer!="rparen"){
			error++;
			cout<<"Syntax error : no ')' matches opening bracket"<<endl;
			return;
		}else{
		    lparenum--;//有右括号与左括号匹配,左括号数减1
            flag=advance();
            if(error){
                return;
            }
            if(flag==0){
                return;
            }
		}
    }else{
		cout<<"Syntax error :factor header is not < identifier > | < unsigned integer > | '(' "<<endl;
		error++;
		return;
	}
	return;
}

int additionOperator(){
    if((pointer=="plus")||(pointer=="minus"))//如果识别的是'+'和'-'时,识别正确
        return 1;
    else
        return 0;
}

int MultiplicationExpression(){
    if((pointer=="times")||(pointer=="slash"))//如果识别的是'*'和'/'时,指针往后移动,识别单词编码
        return 1;
    else
        return 0;
}

int relationshipOperator(){//=|#|<|<=|>|>=
    if((pointer=="eql")||(pointer=="#")||(pointer=="lss")||(pointer=="leq")||(pointer=="gtr")||(pointer=="geq"))//如果识别的是=|#|<|<=|>|>=时,指针往后移动,识别单词编码
        return 1;
    else
        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();
}

在这里插入图片描述

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值