简易的编译器——语法分析

运行环境:Dev-C++ 5.4.0

一、前提了解

语法分析的作用是识别由词法分析给出的单词符号串是否是给定文法的正确句子(程序)。PL/0语言语法可用EBNF形式描述,其中的一个EBNF描述如下。

PL/0语言语法的EBNF描述

PL/0语法单位

EBNF描述

<程序>

::=<分程序>.

<分程序>

::=[<常量说明部分>][<变量说明部分>][<过程说明部分>]<语句>

<常量说明部分>

::=const<常量定义>{,<常量定义>};

<常量定义>

::=<标识符>=<无符号整数>

<变量说明部分>

::=var<标识符>{,<标识符>};

<过程说明部分>

::=<过程首部><分程序>{;<过程说明部分>};

<过程首部>

::=procedure<标识符>;

<语句>

::=<赋值语句>|<条件语句>|<当型循环语句>|<过程调用语句>|<读语句>|<写语句>|<复合语句>|<空语句>

<赋值语句>

::=<标识符>:=<表达式>

<复合语句>

::=begin<语句>{;<语句>}end

<空语句>

::=ɛ

<条件>

::=<表达式><关系运算符><表达式>|odd<表达式>

<表达式>

::=[+|-]<项>{<加减运算符><项>}

<项>

::=<因子>{<乘除运算符><因子>}

<因子>

::=<标识符>|<无符号整数>|’(’<表达式>’)’

<加减运算符>

::=+|-

<乘除运算符>

::=*|/

<关系运算符>

::==|#|<|<=|>|>=

<条件语句>

::=if<条件>then<语句>

<过程调用语句>

::=call<标识符>

<当型循环语句>

::=while<条件>do<语句>

<读语句>

::=read’(’<标识符>{,<标识符>}’)’

<写语句>

::=write’(’<表达式>{,<表达式>}’)’

注:PL/0中变量的数据类型只有整型。

二、算法设计方法

        语法分析常用的程序设计方法可分为自顶向下分析和自底向上分析两类。

        其中,自顶向下分析包括预测分析法和递归下降分析法,自底向上分析包括LR分析法和算符优先分析法。此外,还可以通过语法分析器自动生成工具(例如yacc)编写语法分析程序。

        由于本词法分析使用了每一行进行单词类型判断,故只可简单使用预测分析法和递归下降分析法的相结合。

        在具体实现中,该语法分析是基于文件中的一行来判断是否语法出现问题,若出现问题,则输出语法错误以及所在文件中的行数;若整个文件皆无语法错误,则输出“语法正确”字样。而这样是通过每一行皆使用这7个函数进行语法分析判断,使用数组tmp[10]来进行存储每一行的语法对错,并将结果返回给上一个调用函数,直至分析完整个文件。

        目前,仍存在着的不足有,条件语句中,表达式只可为标识符-运算符-标识符,并且亦无法判断begin-end语句的对错。需要继续加强改进。

 三、结果展示

1、出现语法错误

(1)输入

const a := 10;
var   b, c d;

//单行注释

/*
* 多行注释
*/

procedure procedure fun1;
    if a <= 10 
        begin
            c = b + a
        end;
begin
    read(b;
    while b # 0 
        begin
            call fun1;
            write 2 * c);
            read(b);
        end;
end.

(2)输出

 2、语法正确

(1)输入

const a = 10;
var   b, c;

procedure p;
    if a <= 10 then
        begin
            c := b + a;
        end;
begin
    read(b);
    while b # 0 do
        begin
            call p;
            write(2 * c);
            read(b);
        end;
end.

(2)输出

 四、重要代码

(1)常数说明部分-常数定义-const 

//常数说明部分-常数定义-const 
int Is_constant(char jiangbo[][10],int bobo,int line_num,char bo[][1],int bo_n){
	if(bo[0][0]=='0'&&strcmp(jiangbo[0],"const")==0){
		int tmp=-1;
		for(int i=1;i<bobo-1;i++){
			if(bo[i][0]=='4'){
				if(bo[i+1][0]=='2'&&strcmp(jiangbo[i+1],"=")==0){
					if(bo[i+2][0]=='3'){
						tmp=1;
					}
				}
			}
			if(tmp==1){
				break;
			}	
		} 
		if(strcmp(jiangbo[bobo-1],";")!=0){
			tmp=-1;
		}
		if(tmp!=1){
			printf("(语法错误,行号:%d)\n",line_num);
			return 1;
		}
	}
	return 0;
}

(2)变量说明部分-var

//变量说明部分-var
int Is_varialble(char jiangbo[][10],int bobo,int line_num,char bo[][1],int bo_n){
	//printf("-%c\n",bo[0][0]);
	if(bo[0][0]=='0'&&strcmp(jiangbo[0],"var")==0){
		//printf("11111\n");
		int tmp=-1;
		for(int i=1;i<bobo;i++){
			//printf("22222\n");
			//printf("%d=%c\n",i,bo[i][0]);
			if(bo[i][0]=='4'){
				if(i==bo_n-1){//只有一个标识符或者最后一个标识符,对上面的补充 
					tmp=1;
					break;
				}
				tmp=-1;
				//printf("33333\n");
				if(bobo-2==1){ //表示只有一个标识符 
					tmp=1;
					break;
				}else{
					//printf("44444\n");
					//printf("%d,%c\n",i,jiangbo[i][0]);
					//printf("=%d=\n",strcmp(jiangbo[i+1],","));
					if(strcmp(jiangbo[i+1],",")==0&&bo[i+2][0]=='4'){
						//tmp=1;printf("====1====\n");
						//break;
						//printf("5555555\n");
					}else{
						tmp=-1;
						//if(bo[bo_n-1][0]=='4'&&jiangbo[bo_n-2][0]==','){ //只有一个标识符或者最后一个标识符,对上面的补充 
						//	tmp=1;
						//}
						break;
					}
				}
			} 
			//printf("\n%d,%d,%c\n",i-1,tmp,jiangbo[i][0]);
		} 
		if(strcmp(jiangbo[bobo-1],";")!=0){
			tmp=-1;
		}
		if(tmp!=1){
			printf("(语法错误,行号:%d)\n",line_num);
			return 1;
		}
	}
	return 0;
}

(3)过程首部

//过程首部
int Is_head(char jiangbo[][10],int bobo,int line_num,char bo[][1],int bo_n){
	if(bo[0][0]=='0'&&strcmp(jiangbo[0],"procedure")==0){
		int tmp=-1;
		for(int i=0;i<bobo;i++){
			if(bo[i][0]=='0'&&strcmp(jiangbo[i],"procedure")==0){
				//printf("--1--\n");
				//for(int i=0;i<=bo_n;i++){
				//	printf("%c",bo[i][0]);
				//}
				if(bo[i+1][0]=='4'){
				//	printf("--2--\n");
					tmp=1;
				}else{
					break;
				}
			}
		}
		if(strcmp(jiangbo[bobo-1],";")!=0){
			tmp=-1;
		}
		if(tmp==-1){
			printf("(语法错误,行号:%d)\n",line_num);
			return 1;
		}
	}
	return 0;
} 

 

(4)条件语句-条件(+语句)-表达式+运算符+表达式 

 

//条件语句-条件(+语句)-表达式+运算符+表达式 
int Is_if(char jiangbo[][10],int bobo,int line_num,char bo[][1],int bo_n){
	if(bo[0][0]=='0'&&strcmp(jiangbo[0],"if")==0){
		int tmp=-1;
		for(int i=1;i<bobo;i++){
			if(bo[i][0]=='0'&&strcmp(jiangbo[i],"then")==0){
				tmp=1; //存在if-then 
			}
		}
		if(tmp==1){ //看条件是否符合规范 
			//表达式往小了说是标识符,往大了说是一个式子
			//先弄标识符的
			for(int i=1;i<bobo;i++){
				if((bo[i][0]=='4'||bo[i][0]=='3')&&bo[i+1][0]=='2'&&(bo[i+2][0]=='4'||bo[i+2][0]=='3')){
					tmp=1;//printf("1111111111\n");
					break;
				}
				else{
					tmp=-1;
				}
			}
			if(tmp!=1){
				printf("(语法错误,行号:%d)\n",line_num);
				return 1;
			}
		}else{
			printf("(语法错误,行号:%d)\n",line_num);
			return 1;
		}
	}
	return 0;
} 

(5)赋值语句-标识符+:=+表达式-->标识符+:=+标识符+运算符+标识符 

//赋值语句-标识符+:=+表达式-->标识符+:=+标识符+运算符+标识符 
int Is_boundary(char jiangbo[][10],int bobo,int line_num,char bo[][1],int bo_n){
	int tmp=-1;
	if(bo[0][0]=='4'){
		for(int i=1;i<bobo;i++){
			if(bo[i][0]=='2'&&strcmp(jiangbo[i],":=")==0){//赋值语句 
				if((bo[i+1][0]=='4'||bo[i+1][0]=='3')&&bo[i+2][0]=='2'&&(bo[i+3][0]=='4'||bo[i+3][0]=='3')){
					tmp=1;
					break;
				}
			}else if(bo[i][0]=='2'&&strcmp(jiangbo[i],"=")==0){//常量定义 
				if(bo[i][0]=='3'){
					tmp=1;
					break;
				}
			}
		}
		//printf("=%d,%s\n",bo_n,jiangbo[bobo-1]);
		//printf("1.%d\n",tmp);
		if(strcmp(jiangbo[bobo-1],";")!=0){
			tmp=-1;
		}
		//printf("2.%d\n",tmp);
		if(tmp==-1){
			printf("(语法错误,行号:%d)\n",line_num);
			return 1;
		}
	}
	return 0;
} 

 

(6)读、写语句 读-(+标识符+)

//读、写语句 读-(+标识符+) 
int Is_RW(char jiangbo[][10],int bobo,int line_num,char bo[][1],int bo_n){
 	if(bo[0][0]=='0'&&strcmp(jiangbo[0],"read")==0){
		int x=-1;int y=-1;
		for(int i=1;i<bobo;i++){
			if(strcmp(jiangbo[i],"(")==0){
				x=i;
			}
			if(strcmp(jiangbo[i],")")==0){
				y=i;
			}
		}
		for(int i=x+1;i<y;i++){
			if(bo[i][0]!='4'){
				if(strcmp(jiangbo[i],",")!=0){
					printf("(语法错误,行号:%d)\n",line_num);
					break;
					return 1;
				}
			}
		}
		if(x==-1||y==-1){
			printf("(语法错误,行号:%d)\n",line_num);
			return 1;
		}
		if(strcmp(jiangbo[bobo-1],";")!=0){
			printf("(语法错误,行号:%d)\n",line_num);
			return 1;
		}
	}else if(bo[0][0]=='0'&&strcmp(jiangbo[0],"write")==0){
		int tmp=-1;
		int x=-1;int y=-1;
		for(int i=1;i<bobo;i++){
			if(strcmp(jiangbo[i],"(")==0){
				x=i;
			}
			if(strcmp(jiangbo[i],")")==0){
				y=i;
			}
		}
		for(int i=x+1;i<y;i++){ //表达式 
			if((bo[i][0]=='4'||bo[i][0]=='3')
			&&bo[i+1][0]=='2'
			&&(bo[i+2][0]=='4'||bo[i+2][0]=='3')){
				tmp=1;
				break;
			}
		}
		if(x==-1||y==-1){
			printf("(语法错误,行号:%d)\n",line_num);
			return 1;
		}
		if(tmp==-1){
			printf("(语法错误,行号:%d)\n",line_num);
			return 1;
		}
		if(strcmp(jiangbo[bobo-1],";")!=0){
			printf("(语法错误,行号:%d)\n",line_num);
			return 1;
		}
	}
	return 0;
} 

 

(7)循环语句  while-条件-do  条件-表达式+运算符+表达式 

 

//循环语句  while-条件-do  条件-表达式+运算符+表达式 
int Is_while(char jiangbo[][10],int bobo,int line_num,char bo[][1],int bo_n){
	if(bo[0][0]=='0'&&strcmp(jiangbo[0],"while")==0){
		int tmp=-1;
		for(int i=1;i<bobo;i++){
			if(bo[i][0]=='0'&&strcmp(jiangbo[i],"do")==0){
				tmp=1;
			}
		}
		if(tmp==1){ //看条件是否符合规范 
			//表达式往小了说是标识符,往大了说是一个式子
			//先弄标识符的
			for(int i=1;i<bobo;i++){
				if((bo[i][0]=='4'||bo[i][0]=='3')&&bo[i+1][0]=='2'&&(bo[i+2][0]=='4'||bo[i+2][0]=='3')){
					tmp=1;
					break;
				}
				else{
					tmp=-1;
				}
			}
			if(tmp!=1){
				printf("(语法错误,行号:%d)\n",line_num);
				return 1;
			}
		}else{
			//printf("-----------\n");
			printf("(语法错误,行号:%d)\n",line_num);
			return 1;
		}
	}
	return 0;
}

补充说明:

        其中found函数在词法分析中已展示出了代码,其中包括了jiangbo数组、bo数组等(自己随便命名,并不规范)。

剩余代码若展示过于多,故不予展示。

需要私聊。

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
C#简易编译器 namespace 编译 { public class Grammar { List<token> tokens; List<symble> symbles; public string error = ""; int i = 0; public Grammar(Morphology m) { tokens = m.tokens; symbles = m.symbles; Dispose(); } private void Next() { if (i < tokens.Count - 1) { i++; } } private void Before() { if (i > 0) { i--; } } #region 主要函数 private void Dispose() { if (tokens[i].Code == 12)//含有program { Next(); if (tokens[i].Code == 18)//是标识符 { //执行程序体 Next(); ProBody(); } else { error = "该程序program缺少方法名"; } } else { error = "该程序缺少关键字:program"; } } #endregion #region 程序体 private void ProBody() { if (tokens[i].Code == 16) { Next(); VarDef(); } else if (tokens[i].Code == 2) { Next(); ComSent(); } else { error = "程序体缺少var或begin"; } } #endregion #region 变量定义 private void VarDef() { if (IsIdlist()) { Next(); if (tokens[i].Code == 29)//: { Next(); if (tokens[i].Code == 9 || tokens[i].Code == 3 || tokens[i].Code == 13)//integer,bool,real { int j = i; j = j - 2; symbles[tokens[j].Addr].Type = tokens[i].Code; j--; while (tokens[j].Code == 28) { j--; symbles[tokens[j].Addr].Type = tokens[i].Code; } Next(); if (tokens[i].Code == 30) { Next(); if (tokens[i].Code == 2) { Next(); ComSent(); } else { VarDef(); } } else { error = "变量定义后面缺少;"; } } else { error = "变量定义缺少类型或类型定义错误"; return; } } else { error = "var后面缺少冒号"; } } else { error = "变量定义标识符出错"; } } #endregion #region 判断是不是标识符表 private bool IsIdlist() { if (tokens[i].Code == 18) { Next(); if (tokens[i].Code == 28)//, { Next(); return IsIdlist(); } else { Before(); return true; } } else { return false; } } #endregion #region 复合句 private void ComSent() { SentList(); if (error == "") { if (tokens[i].Code == 6) { return; } else { error = "复合句末尾缺少end"; } } } #endregion #region 语句表 private void SentList() { ExecSent(); if (error == "") { Next(); if (tokens[i].Code == 30) { Next(); SentList(); } } } #endregion #region 执行句 private void ExecSent() { if (tokens[i].Code == 18) { Next(); AssiSent(); } else if (tokens[i].Code == 2 || tokens[i].Code == 8 || tokens[i].Code == 17) { StructSent(); } else { Before(); } } #endregion #region 赋值句 private void AssiSent() { if (tokens[i].Code == 31)//:= { Next(); Expression(); } else { error = "赋值句变量后缺少:="; } } #endregion #region 表达式 private void Expression() { if (tokens[i].Code == 7 || tokens[i].Code == 15 || (tokens[i].Addr != -1 && symbles[tokens[i].Addr].Type == 3)) { BoolExp(); } else { AritExp(); } } #endregion #region 布尔表达式 private void BoolExp() { BoolItem(); if (error == "") { Next(); if (tokens[i].Code == 11) { Next(); BoolExp(); } else { Before(); } } else { return; } } #endregion #region 布尔项 private void BoolItem() { BoolFactor(); if (error == "") { Next(); if (tokens[i].Code == 1) { Next(); BoolItem(); } else { Before(); } } } #endregion #region 布尔因子 private void BoolFactor() { if (tokens[i].Code == 10) { Next(); BoolFactor(); } else { BoolValue(); } } #endregion #region 布尔量 private void BoolValue() { if (tokens[i].Code == 15 || tokens[i].Code == 7) { return; } else if (tokens[i].Code == 18) { Next(); if (tokens[i].Code == 34 || tokens[i].Code == 33 || tokens[i].Code == 32 || tokens[i].Code == 37 || tokens[i].Code == 36 || tokens[i].Code == 35) { Next(); if (tokens[i].Code == 18) { } else { error = "关系运算符后缺少标识符"; } } else { Before(); } } else if (tokens[i].Code == 21) { BoolExp(); //? if (tokens[i].Code == 22) { return; } else { error = "布尔量中的布尔表达式缺少一个)"; } } else { error = "布尔量出错"; } } #endregion #region 算数表达式 private void AritExp() { Item(); if (error == "") { Next(); if (tokens[i].Code == 23 || tokens[i].Code == 24) { Next(); AritExp(); } else { Before(); return; } } else { return; } } #endregion #region 项 private void Item() { Factor(); if (error == "") { Next(); if (tokens[i].Code == 25 || tokens[i].Code == 26) { Next(); Item(); } else { Before(); return; } } else { return; } } #endregion #region 因子 private void Factor() { if (tokens[i].Code == 21) { Next(); AritExp(); Next(); if (tokens[i].Code == 22) { return; } else { error = "因子中算数表达式缺少)"; } } else { CalQua(); } } #endregion #region 算数量 private void CalQua() { if (tokens[i].Code == 18 || tokens[i].Code == 19 || tokens[i].Code == 20) { return; } else { error = "算数量出错"; } } #endregion #region 结构句 private void StructSent() { if (tokens[i].Code == 2) { Next(); ComSent(); } else if (tokens[i].Code == 8) { Next(); IfSent(); } else if (tokens[i].Code == 17) { Next(); WhileSent(); } } #endregion #region if语句 private void IfSent() { BoolExp(); if (error == "") { Next(); if (tokens[i].Code == 14) { Next(); ExecSent(); Next(); if (tokens[i].Code == 5) { Next(); ExecSent(); } else { Before(); return; } } else { error = "if...then语句缺少then"; } } else { error = "if语句布尔表达式出错"; } } #endregion #region while语句 private void WhileSent() { BoolExp(); if (error == "") { Next(); if (tokens[i].Code == 4) { Next(); ExecSent(); } else { error = "while语句缺少do"; } } } #endregion } }
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值