编译原理实验报告:自上而下语法分析

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/Flamewaker/article/details/82899466

1. 实验题目:自上而下语法分析

实验目的

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

实验内容

  已给 PL/0 语言文法,构造表达式部分的语法分析器。
  分析对象〈算术表达式〉的 BNF 定义如下:
  <表达式> ::= [+|-]<项>{<加法运算符> <项>}
  <项> ::= <因子>{<乘法运算符> <因子>}
  <因子> ::= <标识符>|<无符号整数>| ‘(’<表达式>‘)’
  <加法运算符> ::= +|-
  <乘法运算符> ::= *|/
  <关系运算符> ::= =|#|<|<=|>|>=

实验要求

  1. 将实验一“词法分析”的输出结果,作为表达式语法分析器的输入,进行语法解析,对于语法正确的表达式,报告“语法正确法错误的表达式,报告“语法错误”, 指出错误原因。
  2. 把语法分析器设计成一个独立一遍的过程。
  3. 采用递归下降分析法或者采用预测分析法实现语法分析。

输入输出

输入
  PL/0 表达式,用实验一的输出形式作为输入。例如: 对于 PL/0 表达式,(a+15)*b 用下列形式作为输入:
   (lparen,( )
   (ident, a)
   (plus, + )
   (number, 15)
   (rparen,) )
   (times, * )
   (ident, b )
输出
  对于语法正确的表达式,报告“语法正确”;
  对于语法错误的表达式,报告“语法错误”, 指出错误原因

2. 设计思想

  递归下降分析法的原理是利用函数之间的递归调用来模拟语法树自上而下的构建过程。从根节点出发,自顶向下为输入串中寻找一个最左匹配序列,建立一棵语法树。在不含左递归和每个非终结符的所有候选终结首字符集都两两不相交条件下,我们就可能构造出一个不带回溯的自顶向下的分析程序,这个分析程序是由一组递归过程(或函数)组成的,每个过程(或函数)对应文法的而一个非终结符。

语法:
 <表达式> ->[+|-]<项>{<加法运算符> <项>}
 <项> -><因子>{<乘法运算符> <因子>}
 <因子> -> <标识符>|<无符号整数>|(<表达式>)
 <加法运算符> -> +|-
 <乘法运算符> -> *|/

可以得到其语法图
表达式:
在这里插入图片描述

在这里插入图片描述
因子
在这里插入图片描述
计算FIRST集:
  FIRST(<表达式>)={ +, -, (, <标识符>, <无符号整数> }
  FIRST(<因子>)={ <标识符>, <无符号整数>, ( }
  FIRST(<项>)={ <标识符>, <无符号整数>, ( }
  FIRST(<加法运算符>)={ +, - }
  FIRST(<乘法运算符>)={ *, / }

计算FOLLOW集:
  FOLLOW(<表达式>)={ ) }
  FOLLOW (<项>)={ +,- }
  FOLLOW (<因子>)={ *,/ }
  FOLLOW (<加法运算符>)={ <标识符>, <无符号整数>, ( }
  FOLLOW (<乘法运算符>)={ <标识符>, <无符号整数>, ( }

3. 算法流程

  1. 每一个非终结符对应于一个函数(子过程);
  2. 非终结符所对应的右侧产生式为函数体;
  3. 每遇到一个终结符,则需要判断所输入字符是否与之匹配,若匹配则读取下一个,若不匹配,则进行出错处理。
    算法过程可以写成:
PROCEDURE <表达式>:
BEGIN
	IF SYM=’+’ OR SYM=’-’ THEN
	BEGIN
		ADVANCE; <项>;
		WHILE SYM=’+’ OR SYM=’-’ DO
		BEGIN 
			ADVANCE; <项>; 
		END
	END 
	ELSE IF SYM=FIRST(<项>) THEN
	BEGIN
		<项>;
		WHILE SYM=’+’ OR SYM=’-’ DO
		BEGIN 
			ADVANCE; <项>; 
		END
	END 
	ELSE ERROR
END

PROCEDURE <因子>:
BEGIN
	IF SYM=’*’ OR SYM=’/’ THEN
	BEGIN
		ADVANCE; <因子>;
		WHILE SYM=’*’ OR SYM=’/’ DO
		BEGIN 
			ADVANCE; <因子>; 
		END
	END 
	ELSE IF SYM=FIRST(<因子>) THEN
	BEGIN
		<因子>;
		WHILE SYM=’*’ OR SYM=’/’ DO
		BEGIN 
			ADVANCE; <因子>; 
		END
	END 
	ELSE ERROR
END

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

PROGRAM PAESER
BEGIN
	ADVANCE;
	<表达式>;
	IF SYM<>’#’ THEN ERROR
END

语法分析过程的依赖关系:
在这里插入图片描述

4. 源程序

#include<fstream>
#include<cstring>
#include<string>
#include<fstream>
#include<sstream>
#include<iostream>
#include<map>
#include<bits/stdc++.h>
using namespace std;
ifstream infile("F:\\编译原理\\第二次实验\\result.txt");
map<string,string> word;//应用map数据结构形成一个string->string的对应
std::map<string,string>::iterator it;//用来遍历整个对应关系的迭代器
string str;//string变量进行字符识别
string sym; //指针

void expressionAnalysis();//表达式分析
void termAnaysis();//项分析
void factorAnalysis();//因子分析
int advance();

int conterr=0;//记录错误
int lpnum=0;//记录左括号
int found;//提取字符串中指针的位置
int flag=0;//记录往后移动一个指针SYM是否正确

int main(){
    flag=advance();
    if(flag){
        expressionAnalysis();
    }
    if(flag!=-1&&!conterr){
        cout<<"语法正确"<<endl;
    }
    return 0;
}

int advance(){//SYM的移动
    if(!getline(infile,str)){//从文件中提取字符
        return 0;
    }
    found=str.find(',',0);
    if(found==-1){//当为error的时候,没有‘,’
        conterr++;
        cout<<"语法错误 识别字符错误"<<endl;
        return -1;
    }
    sym=str.substr(1,found-1);
    cout<<sym<<endl;
    return 1;
}

void factorAnalysis(){
    if(sym=="ident"||sym=="number"){//如果是标识符和无符号整数,指针就往后移动
        flag=advance();
        if(conterr){
            return;
		}
		if(lpnum==0&&sym=="rparen"){
            conterr++;
			cout<<"语法错误 ')'不匹配"<<endl;
			return;
        }
    }
    else if(sym=="lparen"){//如果是左括号,就要接下来判断是否为表达式,指针往后移动
        lpnum++;
        cout<<lpnum<<endl;
        flag=advance();
        if(conterr){
            return;
		}
		if(flag==0){//当为最后一个标志的时候,若没有右括号匹配就错误
			conterr++;
			cout<<"语法错误 '('后缺少表达式"<<endl;
			return;
		}
        expressionAnalysis();
        if(conterr){
            return;
		}
        if(flag==0||sym!="rparen"){
			conterr++;
			cout<<"语法错误 表达式后面缺少')'"<<endl;
			return;
		}else{
		    lpnum--;
            flag=advance();
            if(conterr){
                return;
            }
            if(flag==0){
                return;
            }
		}
    }else{
		cout<<"语法错误 因子首部不为<标识符>|<无符号整数>|'('"<<endl;
		conterr++;
		return;
	}
	return;
}

void termAnalysis(){
    factorAnalysis();
    if(conterr){
        return;
    }
	while((sym=="times")||(sym=="slash")){//当为'*'或'/'的时候,一直往后识别因子并循环
		flag=advance();
		if(conterr){
            return;
		}
		if(flag==0){
			conterr++;
			cout<<"语法错误 <乘法运算符>后缺因子"<<endl;
			return;
		}
		if(conterr){
            return;
		}
		factorAnalysis();
		if(conterr){
            return;
		}
	}
	return;
}

void expressionAnalysis(){
    if(conterr){
        return;
	}
	if((sym=="plus")||(sym=="minus")){//当为'*'或'/'的时候
		flag=advance();
		if(!conterr){
            return;
		}
		if(flag==0){
            cout<<"语法错误 <加法运算符>后缺项"<<endl;
            conterr++;
			return;
		}
	}
	termAnalysis();
	if(conterr){
        return;
	}
	while((sym=="plus")||(sym=="minus")){//当为'+'或'-'的时候,一直往后识别项并循环
		flag=advance();
		if(conterr){
            return;
		}
		if(flag==0){
            cout<<"语法错误 <加法运算符>后缺项"<<endl;
            conterr++;
			return;
		}
		termAnalysis();
		if(conterr){
            return;
		}
	}
	return;
}

5. 调试数据

输入:
在这里插入图片描述
在这里插入图片描述
输出:
在这里插入图片描述

猜你喜欢

转载自blog.csdn.net/Flamewaker/article/details/82899466