实验三、语法分析实验
一、 实验目的
(1) 编制一个语法分析程序
(2) 语法分析是在词法分析的基础上进行编写的,主要任务是根据词法分析出的种别码来判断。
(3) 通过语法分析的练习,能够进一步了解编译原理。
(4) 通过了解语法分析程序的设计原则、单词的描述技术、识别机制及语法分析程序的自动构造原理。
二、 实验内容和要求
(1) 以词法分析生成的单词符号序列作为输入
(2) 根据语言的语法规则,识别出各种语法成分
表达式、赋值语句、程序段等
(3) 并在分析过程中进行语法检查,检查所给的单词符号序列是否是该语言的一个句子
(4) 某种形式的语法树作为输出或报告错误
三、 实验方法、步骤及结果测试
1、实验方法、步骤:
² 自上而下分析法
³ 如果文法有左递归?
³ 如果文法不是LL(1)文法?
³ 非确定的,穷举试探
³ 确定的, 没有回溯
® 如何判断是否是LL(1)文法?
® 要求是LL(1)文法
® 文法改写为LL(1)文法
² 自下而上分析法
2、原理分析:我本来的词法分析程序是利用链队列(好处:先进先出且不浪费存储空间)进行存储用户输入字符串,以回车键结束,可当我用到语法分析程序的时候,我就发现了很多问题(暂时还没解决),所以我就改了一个简单的词法分析程序,以适应语法分析程序,这次我是用了一个二维数组来存储用户输入的字符串,每次只取一个字符(syn)进行语法分析。
void E() { printf("E "); T();E1(); } void E1() { printf("E1 "); if (syn==13||syn==14) { scaner(); T();E1(); } else { if (syn!=28 && syn!=25) error(); } } void T() { printf("T "); F();T1(); } void T1() { printf("T1 "); if (syn==15||syn==16) { scaner(); F();T1(); } else { if (syn!=28 && syn!=25 && syn!=13&&syn!=14) error(); } } void F() { printf("F "); if (syn==27) { scaner(); E(); if(syn==28) scaner(); else error(); } else if (syn==11 || syn==10) scaner(); }
四、实验总结
这次的实验有点赶,因为我之前是用链队列来进词法分析程序的,由于这种方法应用到语法分析程序中就有点问题了,
所以我就临时改了一个简单的词法分析程序,这次我是用数组来存储用户输入的字符串,这样的好处是编写简单,清
晰明了,可也有它的不足之处,例如存储空间是固定的,没有灵活性。
#include <stdio.h> //#include <string.h> #define M 100 #define N 20 char str[M], wrong[N]; char ch; int syn,t,m,n,sum; char *keyword[6]= {"begin","if","then","while","do","end"}; void scaner(); void error(); void E(); void T(); void E1(); void F(); void T1(); main() { char c; t=0; printf("Please input the arithmetic expressions: "); do{ ch=getchar(); str[t++]=ch; }while (ch!='='); t=0; do{ scaner(); switch(syn) { case 11: printf(" (%d,%d)",syn,sum); break; case -1: printf(" (%s,mistake)",wrong);break; default: printf(" (%d,%s)",syn, wrong); } }while (syn!=25); getchar(); printf(" Wheter or not choice output grammer(y|n):"); scanf("%c",&c); if(c=='Y'||c=='y'){ t=0; scaner(); E(); if (syn==25) printf(" Grammer correct "); else printf(" Grammer mistake "); } } void scaner() { for (n=0;n<20;n++) wrong[n]=NULL; m=0; sum=0; ch=str[t++]; while (ch==' ') {ch=str[t++];} if (ch>='a'&& ch<='z') {while (ch>='a'&& ch<='z'||ch>='0' && ch<='9') { wrong[m++]=ch; ch=str[t++]; } syn=10;t--; for (n=0;n<6;n++) if(strcmp(wrong,keyword[n])==0) {syn=n+1;break;} } else if(ch>='0' && ch<='9') {while (ch>='0' && ch<='9') {sum=sum*10+(ch-'0'); ch=str[t++];} syn=11;t--; } else switch(ch) { case '<': wrong[m++]=ch; ch=str[t++]; if (ch=='>') {syn=21;wrong[m++]=ch;} else if (ch=='=') {syn=22;wrong[m++]=ch;} else {syn=20;t--;} break; case '>': m=0; wrong[m++]=ch; ch=str[t++]; if (ch=='='){syn=24;wrong[m++]=ch;} else {syn=23;t--;} break; case ':': m=0; wrong[m++]=ch; ch=str[t++]; if (ch=='='){syn=18;wrong[m++]=ch;} else {syn=17;t--;} break; case '+': syn=13;wrong[0]=ch;break; case '-': syn=14;wrong[0]=ch;break; case '*': syn=15;wrong[0]=ch;break; case '/': syn=16;wrong[0]=ch;break; case '(': syn=27;wrong[0]=ch;break; case ')': syn=28;wrong[0]=ch;break; case '=': syn=25;wrong[0]=ch;break; case ';': syn=26;wrong[0]=ch;break; default: syn=-1;wrong[0]=ch; } } void E() { printf("E "); T();E1(); } void E1() { printf("E1 "); if (syn==13||syn==14) { scaner(); T();E1(); } else { if (syn!=28 && syn!=25) error(); } } void T() { printf("T "); F();T1(); } void T1() { printf("T1 "); if (syn==15||syn==16) { scaner(); F();T1(); } else { if (syn!=28 && syn!=25 && syn!=13&&syn!=14) error(); } } void F() { printf("F "); if (syn==27) { scaner(); E(); if(syn==28) scaner(); else error(); } else if (syn==11 || syn==10) scaner(); } void error() { printf(" (%d,%s)mistake ",syn, wrong); }