实验二. 自上而下语法分析
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();
}