通过设计、编制、调试一个递归下降语法分析程序,实现对词法分析程序所提供的单词序列进行语法检查和结构分析,掌握常用的语法分析方法。通过本实验,应达到以下目标:
(1) 掌握从源程序文件中读取有效字符的方法和产生源程序的内部表示文件的方法。
(2) 掌握语法分析的实现方法。
(3) 上机调试编出的语法分析程序。
完成以下描述算术表达式的LL(1)文法的递归下降分析程序构造
G[E]:
E → TE′
E′→ +TE′|ε
T → FT′
T′→ *FT′|ε
F → (E) | i
说明:终结符号i为用户定义的简单变量,即标识符的定义。
要求具有如下功能:
1)从文件读入算术表达式/或者从终端输入
2)总控函数分析算术表达式;
3)根据分析结果正误,分别给出不同信息
lab2.h
#include
#include
#include
#include
char str[30]; //字符串数组
int subscript = 0; //str数组的下标
int len; //数组长度
int tnum; //测试次数
FILE *fp = NULL; //声明文件
//1、处理非终结符E的子程序
void processE();
//2、处理非终结符E_e(即E')的子程序,e即英文extend
void processE_e();
//3、处理非终结符T的子程序
void processT();
//4、处理非终结符T_e的子程序
void processT_e();
//5、处理非终结符F的子程序
void processF();
//6、从文件读入算术表达式
void readFromFile(FILE *fp);
//7、从终端输入算数表达式
void enterFromTerminal();
lab2.c
#include "lab2.h"
//1、处理非终结符E的子程序,E->TE'
void processE(){
processT();
processE_e();
}
//2、处理非终结符E_e(即E')的子程序,E'->+TE'|ε
void processE_e(){
if(str[subscript] == '+'){
subscript ++;
processT();
processE_e();
}
}
//3、处理非终结符T的子程序,T->FT'
void processT(){
processF();
processT_e();
}
//4、处理非终结符T_e的子程序,T'->*FT'|ε
void processT_e(){
if(str[subscript] == '*'){
subscript ++;
processF();
processT_e();
}
}
//5、处理非终结符F的子程序,F->(E)|i
void processF(){
if(str[subscript] == 'i')
subscript ++;
//printf("Successfully!\n");
else if(str[subscript] == '('){
subscript ++;
processE();
if(str[subscript] == ')')
subscript ++;
else{
printf("The string is illegal.Error!");
exit(0);
}
}
else{
printf("The string is illegal.Error!");
exit(0);
}
}
//6、从文件读入算术表达式
void readFromFile(FILE *fp){
while(fgets(str, 100, fp) != NULL){
printf("Read line = %s",str);
processE();
printf("Analyze successfully!\n");
subscript = 0; //下标继续从0开始
}
printf("—————End of reading file—————\n");
}
//7、从终端输入算数表达式
void enterFromTerminal(){
printf("Please enter the number of strings you want to parse:");
scanf("%d",&tnum);
while(tnum--){
printf("Please enter a string:\n");
scanf("%s",str);
len = strlen(str);
//printf("%d",len);
//str[len+1] = '\0';
processE();
printf("Analyze successfully!\n");
//strcpy(str,""); //清空数组,为下一次字符串输入腾出空间
subscript = 0; //下标继续从0开始
}
}
//总控函数
int main(){
int choice;
while(1){
printf("--------------------------------------------------------------------------------------\n");
printf("1、Enter from terminal\n");
printf("2、Read from file\n");
printf("Please choose (1 or 2) which method you want to analyze arithmetic expressions:\n");
printf("(Note:Press 0 to exit)\n");
scanf("%d",&choice);
switch(choice){
case 1:
enterFromTerminal();
printf("\n");
break;
case 2:
fp = fopen("test.txt", "r");
if (!fp)
printf("The file doesn't exist\n");
else
readFromFile(fp);
fclose(fp);
printf("\n");
break;
case 0:
// system("cls");
printf("Exited!\n");
exit(0);
break;
}
}
return 0;
}
lab2.py
# 全局变量
subscript = 0 # str数组下标
str = "" # 字符串
# 1、处理非终结符E的子程序,E->TE'
def processE():
processT()
processE_e()
# 2、处理非终结符E_e(即E')的子程序,E'->+TE'|ε
def processE_e():
global subscript
global str
if str[subscript] == '+':
subscript = subscript + 1
processT()
processE_e()
# 3、处理非终结符T的子程序,T->FT'
def processT():
processF()
processT_e()
# 4、处理非终结符T_e的子程序,T'->*FT'|ε
def processT_e():
global subscript
global str
if str[subscript] == '*':
subscript = subscript + 1
processF()
processT_e()
# 5、处理非终结符F的子程序,F->(E)|i
def processF():
global subscript
global str
if str[subscript] == 'i':
subscript = subscript + 1
elif str[subscript] == '(':
subscript = subscript + 1
processE()
if str[subscript] == ')':
subscript = subscript + 1
else:
print(str)
print("The string is illegal.Error!")
return
else:
print(str)
print("The string is illegal.Error!")
return
# 6、从文件读入算术表达式
def readFromFile():
global subscript
global str
# Open file
fileHandler = open ("test.txt", "r")
while True:
# Get next line from file
line = fileHandler.readline()
# If line is empty then end of file reached
if not line :
break
str = line.strip()
print("Read line = ",str)
str += '#'
processE()
print("Analyze successfully!")
subscript = 0;
# Close Close
fileHandler.close()
print("—————End of reading file—————")
# 7、从终端输入算数表达式
def enterFromTerminal():
global str
tnum = input("Please enter the number of strings you want to parse:")
tnum = int(tnum)
while tnum > 0:
str = input("Please enter a string(end with '#'):")
processE()
print("Analyze suinputccessfully!")
str = ""
subscript = 0 # 下标继续从0开始
tnum = tnum - 1
# 总控函数
if __name__ == '__main__':
while True:
print("1、Enter from terminal")
print("2、Read from file")
print("Please choose (1 or 2) which method you want to analyze arithmetic expressions:")
print("(Note:Press any key to exit)")
ch = input()
if ch == '1':
enterFromTerminal()
elif ch == '2':
readFromFile()
else:
print("Exited!")
break
3、Flex&Bison
lab2ll.l
%{
#include
int yyerror(char *str);
#include "lab2yy.tab.h"
%}
%%
[ \t]* {}
[0-9]+ {
yylval = atoi(yytext);
return DIGIT;
}
[*+\n] return *yytext;
. {yyerror("The string is illegal.Error!");}
%%
int yyerror(char *str){
fprintf(stderr,"%s\n",str);
return 1;
}
int yywrap(){
return 1;
}
lab2yy.y
{
#include
#include
#include
int yylex();
int yyerror(char *str);
%}
%token DIGIT
%%
line : expr {printf("%d\n",$1);}
;
expr : expr '+' term {$$ = $1 + $3;}
| term
;
term : term '*' factor {$$ = $1 * $3;}
| factor
;
factor : '(' expr ')' {$$ = $2;}
| DIGIT
;
%%
int main() {
printf("-----------Parser----------------\n");
yyparse();
return 0;
}
/*
终端编译flex&yacc文件命令如下:
bison -vdty lab2yy.y
此时会产生三个文件,即y.tab.h, y.tab.c, y.output
或 bison -d lab2yy.y
此时会产生两个文件,即lab2yy.tab.h lab2yy.tab.c
flex lab2ll.l
此时会产生一个文件,即lex.yy.c
gcc -o lab2yy y.tab.c lex.yy.c
或 gcc -o lab2yy lab2yy.tab.c lex.yy.c(第二个bison命令时)
.\lab2yy
*/
(1条消息) 递归下降语法分析程序设计_poclist的博客-CSDN博客https://blog.csdn.net/bfboys/article/details/52530550(1条消息) 【编译原理】【C语言】实验三:递归下降分析法_zoxiii的博客-CSDN博客_递归下降分析https://blog.csdn.net/qq_41315788/article/details/122455432第13章 用 bison 做语法分析 — 自己动手写编译器 (pandolia.net)https://pandolia.net/tinyc/ch13_bison.html编译工程附录:Bison基础 - 知乎 (zhihu.com)https://zhuanlan.zhihu.com/p/111445997#:~:text=%24%E5%B0%B1%E6%98%AFbison%E4%B8%AD%E6%AF%8F%E4%B8%AA%E4%BA%A7%E7%94%9F%E5%BC%8F%E4%B8%AD%E5%90%84%E9%A1%B9%E7%9A%84%E5%80%BC%EF%BC%9B%24%24%E4%BA%A7%E7%94%9F%E5%BC%8F%E5%B7%A6%E9%83%A8%EF%BC%9B%241%E6%98%AF%E4%BA%A7%E7%94%9F%E5%BC%8F%E5%8F%B3%E8%BE%B9%E7%AC%AC1%E4%B8%AA%E7%AC%A6%E5%8F%B7%E7%BB%91%E5%AE%9A%E7%9A%84%E5%80%BC%EF%BC%8C%242%E6%98%AF%E7%AC%AC2%E4%B8%AA%E7%AC%A6%E5%8F%B7%EF%BC%8C%243%E6%98%AF%E7%AC%AC3%E4%B8%AA%E7%AC%A6%E5%8F%B7%EF%BC%8C%E4%BB%A5%E6%AD%A4%E7%B1%BB%E6%8E%A8%E3%80%82,%E5%A6%82%E6%9E%9C%E6%B2%A1%E6%9C%89%E6%98%BE%E5%BC%8F%E6%8C%87%E5%AE%9A%E5%A4%84%E7%90%86%E8%AF%AD%E5%8F%A5%EF%BC%8Cbison%E9%BB%98%E8%AE%A4%E6%83%85%E5%86%B5%E4%B8%8B%E6%8A%8A%241%E7%9A%84%E5%80%BC%E6%8B%B7%E8%B4%9D%E7%BB%99%24%24%E3%80%82---------------------------------------------------------------------------------------------------------------------------------
不足之处欢迎指正~