内容:设计并实现含多条简单赋值语句的语法分析程序,要求有一定的出错提示与错误恢复功能。
源代码:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#define _KEY_WORD_END "waiting for your expanding"//定义关键字结束标志
typedef struct//单词二元组的结构
{
int typenum;
char *word;
}WORD;
char input[255];//输入换缓冲区
char token[255]="";//单词缓冲区
int p_input;//输入换缓冲区指针
int p_token;//单词缓冲区指针
int kk=0;
int row=1;
WORD* oneword=new WORD;
char ch;//当前读入字符
char* rwtab[]={"begin","if","then","while","do","end",_KEY_WORD_END};//可扩充的关键字数组
int syn;
WORD* scaner();//词法扫描函数,获得一个单词
char m_getch(){//从输入缓冲区读取一个字符到ch中
ch=input[p_input];
p_input=p_input+1;
return (ch);
}
void retract(){//回退一个字符
p_input=p_input-1;
}
int factor();
int term()
{
factor();
while(syn==15||syn==16)//判断是否为*,/
{
scaner();//读下一个单词符号
factor();//调用factor函数
}
return syn;
}
int expression()
{
term();//调用term函数
while(syn==13||syn==14)//判断是否为+,-
{
scaner();//读下一个单词符号;
term();//调用term函数
}
return syn;
}
int statement()
{
if(syn!=10)
{
printf("第%d行:输出语句错误\n",row);
kk=1;
}
scaner();//读下一个单词符号
if(syn!=18)
{
printf("第%d行:赋值语句错误\n",row);
kk=1;
}
scaner();//读下一个单词符号
expression();//调用expression函数
if(syn==28)
{
printf("第%d行:多‘)’错误\n",row);
kk=1;
scaner();
}
return syn;
}
int yucu()
{
statement();//调用statement()
while(syn==26)//判断是否为;
{
scaner();//读下一个单词符号
statement();//调用statement函数
}
return syn;
}
int irparser()
{
scaner();
if(syn!=1)
{
printf("第%d行:begin错误\n",row);
kk=1;
}
scaner();//读下一个单词符号
yucu();//调用yucu函数
if(syn==6)//判断是否为end
{
scaner();//读下一个单词符号
if(syn==0&&kk==0)//前面语句未出错则kk为0,下一个单词为#则结束
{
printf("success\n");
}
}
else
{
printf("第%d行:缺end错误\n",row);
kk=1;
}
return syn;
}
int factor()
{
if(syn==27)//判断是否为'('
{
scaner();//读下一个单词符号
expression();//调用expression函数
if(syn==28)
{
scaner();
}
else
{
printf("第%d行:缺')'错误\n",row);
kk=1;
}
}
else
{
if(syn!=10&&syn!=11)
{
printf("第%d行:表达式错误\n",row);
kk=1;
}
scaner();//读下一个单词符号
}
return syn;
}
int main()
{
int over=1;
int ch1;
int i=0;
WORD* oneword=new WORD;
FILE *fp1;
fp1=fopen("f2.txt","r");
if(fp1==NULL)
{
printf("error");
}
while((ch1=fgetc(fp1))!='#'){
input[i]=ch1;
i++;
}
p_input=0;
irparser();
fclose(fp1);//关闭文件
return 0;
}
void getbc(){//去掉空白符号
while(ch==' '||ch=='\n'){
if(ch=='\n')
row=row+1;
ch=input[p_input];
p_input=p_input+1;
}
}
void concat(){//拼接单词
token[p_token]=ch;
p_token=p_token+1;
token[p_token]='\0';
}
int letter(){//判断是否字母
if(ch>='a'&&ch<='z'||ch>='A'&&ch<='Z')
return 1;
else
return 0;
}
int digit(){//判断是否为数字
if(ch>='0'&&ch<='9'||ch=='.')
return 1;
else
return 0;
}
int reserve(){//检索关键字表格
int i=0;
while(strcmp(rwtab[i],_KEY_WORD_END)){
if(!strcmp(rwtab[i],token)){
return i+1;
}
i=i+1;
}
return 10;
}
char* dtb(){//数字转换为二进制
return NULL;
}
WORD* scaner(){
WORD* myword=new WORD;
myword->typenum=10;
myword->word="";
p_token=0;
m_getch();
getbc();
if(letter()){
while(letter()||digit()){
concat();
m_getch();
}
retract();
myword->typenum=reserve();
myword->word=token;
syn=myword->typenum;
return myword;
}
else if(digit()){
while(digit()){
concat();
m_getch();
}
retract();
myword->typenum=11;
myword->word=token;
syn=myword->typenum;
return myword;
}
else switch(ch){
case '=': m_getch();
if(ch=='='){
myword->typenum=39;
myword->word="==";
return myword;
}
retract();
myword->typenum=25;
myword->word="=";
syn=myword->typenum;
return myword;
break;
case '+': myword->typenum=13;
myword->word="+";
syn=myword->typenum;
return myword;
break;
case '-': myword->typenum=14;
myword->word="-";
syn=myword->typenum;
return myword;
break;
case '*': m_getch();
if(ch=='/'){
myword->typenum=700;
myword->word="*/";
syn=myword->typenum;
return myword;
}
retract();
myword->typenum=15;
myword->word="*";
syn=myword->typenum;
return myword;
break;
case '/': m_getch();
if(ch=='/'){
myword->typenum=500;
myword->word="//";
syn=myword->typenum;
return myword;
}
if(ch=='*'){
myword->typenum=600;
myword->word="/*";
syn=myword->typenum;
return myword;
}
retract();
myword->typenum=16;
myword->word="/";
syn=myword->typenum;
return myword;
break;
case '(': myword->typenum=27;
myword->word="(";
syn=myword->typenum;
return myword;
break;
case ')': myword->typenum=28;
myword->word=")";
syn=myword->typenum;
return myword;
break;
case '[': myword->typenum=29;
myword->word="[";
syn=myword->typenum;
return myword;
break;
case ']': myword->typenum=30;
myword->word="]";
syn=myword->typenum;
return myword;
break;
case '{': myword->typenum=31;
myword->word="{";
syn=myword->typenum;
return myword;
break;
case '}': myword->typenum=32;
myword->word="}";
syn=myword->typenum;
return myword;
break;
case ',': myword->typenum=33;
myword->word=",";
syn=myword->typenum;
return myword;
break;
case ':': m_getch();
if(ch=='='){
myword->typenum=18;
myword->word=":=";
syn=myword->typenum;
return myword ;
}
retract();
myword->typenum=17;
myword->word=":";
syn=myword->typenum;
return myword;
break;
case ';': myword->typenum=26;
myword->word=";";
syn=myword->typenum;
return myword;
break;
case '>': m_getch();
if(ch=='='){
myword->typenum=24;
myword->word=">=";
syn=myword->typenum;
return myword;
}
retract();
myword->typenum=23;
myword->word=">";
syn=myword->typenum;
return myword;
break;
case '<': m_getch();
if(ch=='='){
myword->typenum=22;
myword->word="<=";
syn=myword->typenum;
return myword;
}
else if(ch=='>'){
myword->typenum=21;
myword->word="<>";
return myword;
}
retract();
myword->typenum=20;
myword->word="<";
syn=myword->typenum;
return myword;
break;
case '!': m_getch();
if(ch=='='){
myword->typenum=40;
myword->word="!=";
syn=myword->typenum;
return myword;
}
retract();
myword->typenum=-1;
myword->word="ERROR";
syn=myword->typenum;
return myword;
break;
default:myword->typenum=0;
myword->word="ERROR";
syn=myword->typenum;
return myword;
}
}
以下测试文本文件命名均为f2.txt。
测试文本1:
文本1测试结果:
测试文本2:
文本2测试结果:
注:本人知识有限,所做此程序暂无法解决分号问题,一旦分号错误,漏打等,程序的出错提示会有误,因此只能用于简单的出错提示,连续赋值这种无法正确实现。(若有大佬能帮忙改正,极为感谢!)