得到token序列后,我们就可以采用递归下降法对其进行语法分析。如果没有语法错误,打印token序列,提示没有语法错误,否则,打印已经匹配的token,提示语法错误。(下面程序使用vs2013编译)
#define _CRT_SECURE_NO_WARNINGS
#include <stdio.h>
#include <stdlib.h>
#include <iostream>
#include <string>
#include <vector>
using namespace std;
//token结构体
struct Token
{
Token(string str, int pos)
{
this->type = str;
this->pos = pos;
}
string type;
int pos;
};
vector<string> IdTable;//全局变量,标示符表
vector<int> NbTable;//全局变量,INTC值表
FILE *g_pf;//全局变量,打开*.token的文件指针
FILE *g_pf_log;//全局变量,日志文件*.log的文件指针
vector<string> result;//记录匹配成功的token
int max_read_num = 0;//最大匹配token数量
//从文件中读入一个token,需要先打开*.token文件
Token *ReadToken(FILE *pf)
{
if (pf == NULL)
exit(-1);
char buf1[256] = { 0 };
char buf2[256] = { 0 };
int num = 0;
if (!pf)
return NULL;
while (!feof(pf))
{
memset(buf1, 0, sizeof(buf1));
memset(buf2, 0, sizeof(buf2));
fgets(buf1, sizeof(buf1), pf);
result.push_back(buf1);
if (result.size() > max_read_num)//记录读入token数量最大值
max_read_num = result.size();
if (g_pf_log)
fprintf(g_pf_log,"读入%s\n", buf1);
sscanf(buf1, "(%[^,],%[^)]", buf1, buf2);
if (buf2[0] == '"')
{
return new Token(buf1, -1);
}
else if (buf2[0] == '[')
{
sscanf(buf2, "[%[0-9]", buf2);
num = atoi(buf2);
return new Token(buf1, num);
}
else
{
return NULL;
}
}
return NULL;
}
//从文件流中回退一个token,需要先打开*.token文件
void BackToken(FILE*pf)
{
if (pf == NULL)
exit(-1);
string tmp = result[result.size() - 1];
int i = tmp.size();
while (i)
{
ungetc(tmp[--i], pf);
}
if (g_pf_log)
fprintf(g_pf_log, "返回%s\n", result[result.size() - 1].c_str());
result.erase(result.end() - 1);
}
//总程序
bool MatchProgramHead();
bool MatchDeclarePart();
bool MatchProgramBody();
bool MatchProgramName();
bool MatchTypeDecpart();
bool MatchVarDecpart();
bool MatchProcDecpart();
bool MatchTypeDec();
bool MatchTypeDecList();
bool MatchTypeDecMore();
bool MatchTypeId();
bool MatchTypeName();
bool MatchBaseName();
bool MatchStructureType();
bool MatchArrayType();
bool MatchLow();
bool MatchTop();
bool MatchRecType();
bool MatchFieldDecList();
bool MatchFieldDecMore();
bool MatchIdList();
bool MatchIdMore();
//变量声明
bool MatchVarDecpart();
bool MatchVarDec();
bool MatchVarDecList();
bool MatchVarDecMore();
bool MatchVarIdList();
bool MatchVarIdMore();
//过程声明
bool MatchProcDecpart();
bool MatchProcDec();
bool MatchProcDecMore();
bool MatchProcName();
//参数声明
bool MatchParamList();
bool MatchParamDecList();
bool MatchParamMore();
bool MatchParam();
bool MatchFormList();
bool MatchFidMore();
//过程中的声明
bool MatchProcDecPart();
//过程体
bool MatchProcBody();
bool MatchProgramBody();
//语句序列
bool MatchStmList();
bool MatchStmMore();
//语句
bool MatchStm();
bool MatchAssCall();
bool MatchAssignmentRest();
bool MatchConditionalStm();
bool MatchLoopStm();
bool MatchInputStm();
bool MatchInvar();
bool MatchOutputStm();
bool MatchReturnStm();
bool MatchCallStmRest();
bool MatchActParamList();
bool MatchActParamMore();
bool MatchRelExp();
bool MatchOtherRelE();
bool MatchExp();
bool MatchOtherTerm();
bool MatchTerm();
bool MatchOtherFactor();
bool MatchFactor();
bool MatchVariable();
bool MatchVariMore();
bool MatchFieldVar();
bool MatchFieldVarMore();
bool MatchCmpOp();
bool MatchAddOp();
bool MatchMultOp();
bool MatchProgram()
{
if (!MatchProgramHead())
return false;
if (!MatchDeclarePart())
return false;
if (!MatchProgramBody())
return false;
if (ReadToken(g_pf)->type != "$.")
{
BackToken(g_pf);
return false;
}
return true;
}
bool MatchProgramHead()
{
if (ReadToken(g_pf)->type == "$program")
return MatchProgramName();
return false;
}
bool MatchProgramName()
{
if (ReadToken(g_pf)->type == "$id")
return true;
return false;
}
bool MatchDeclarePart()
{
if (!MatchTypeDecpart())
return false;
if (!MatchVarDecpart())
return false;
if (!MatchProcDecpart())
return false;
return true;
}
bool MatchTypeDecpart()
{
MatchTypeDec();
return true;
}
bool MatchTypeDec()
{
if (ReadToken(g_pf)->type != "$type")
{
BackToken(g_pf);
return false;
}
else
{
if (!MatchTypeDecList())
{
BackToken(g_pf);
return false;
}
else
{
return true;
}
}
}
bool MatchTypeDecList()
{
if (!MatchTypeId())
return false;
if (ReadToken(g_pf)->type != "$=")
{
BackToken(g_pf);
return false;
}
if (!MatchTypeName())
{
BackToken(g_pf);
return false;
}
if (ReadToken(g_pf)->type != "$;")
{
BackToken(g_pf);
BackToken(g_pf);
return false;
}
return MatchTypeDecMore();
}
bool MatchTypeDecMore()
{
MatchTypeDecList();
return true;
}
bool MatchTypeId()
{
if (ReadToken(g_pf)->type == "$id")
return true;
else
{
BackToken(g_pf);
return false;
}
}
bool MatchTypeName()
{
if (MatchBaseName())
return true;
if (MatchStructureType())
return true;
if (ReadToken(g_pf)->type == "$id")
return true;
else
{
BackToken(g_pf);
return false;
}
return false;
}
bool MatchBaseName()
{
if (ReadToken(g_pf)->type == "$integer")
return true;
else
{
BackToken(g_pf);
}
if (ReadToken(g_pf)->type == "$char")
return true;
else
{
BackToken(g_pf);
}
return false;
}
bool MatchStructureType()
{
if (MatchArrayType())
return true;
if (MatchRecType())
return true;
return false;
}
bool MatchArrayType()
{
if (ReadToken(g_pf)->type != "$array")
{
BackToken(g_pf);
return false;
}
if (ReadToken(g_pf)->type != "$[")
{
BackToken(g_pf);
BackToken(g_pf);
return false;
}
if (!MatchLow())
{
BackToken(g_pf);
BackToken(g_pf);
return false;
}
if (ReadToken(g_pf)->type != "$.")
{
BackToken(g_pf);
BackToken(g_pf);
BackToken(g_pf);
return false;
}
if (ReadToken(g_pf)->type != "$.")
{
BackToken(g_pf);
BackToken(g_pf);
BackToken(g_pf);
BackToken(g_pf);
return false;
}
if (!MatchTop())
{
BackToken(g_pf);
BackToken(g_pf);
BackToken(g_pf);
BackToken(g_pf);
return false;
}
if (ReadToken(g_pf)->type != "$]")
{
BackToken(g_pf);
BackToken(g_pf);
BackToken(g_pf);
BackToken(g_pf);
BackToken(g_pf);
return false;
}
if (ReadToken(g_pf)->type != "$of")
{
BackToken(g_pf);
BackToken(g_pf);
BackToken(g_pf);
BackToken(g_pf);
BackToken(g_pf);
BackToken(g_pf);
return false;
}
return MatchBaseName();
}
bool MatchLow()
{
if (ReadToken(g_pf)->type != "$INTC")
{
BackToken(g_pf);
return false;
}
return true;
}
bool MatchTop()
{
if (ReadToken(g_pf)->type != "$INTC")
{
BackToken(g_pf);
return false;
}
return true;
}
bool MatchRecType()
{
if (ReadToken(g_pf)->type != "$record")
{
BackToken(g_pf);
return false;
}
if (!MatchFieldDecList())
{
BackToken(g_pf);
return false;
}
if (ReadToken(g_pf)->type != "$end")
{
BackToken(g_pf);
BackToken(g_pf);
return false;
}
return true;
}
bool MatchFieldDecList()
{
if (MatchBaseName())
if (MatchIdList())
if (ReadToken(g_pf)->type == "$;")
{
if (MatchFieldDecMore())
return true;
}
else
{
BackToken(g_pf);
}
if (MatchArrayType())
if (MatchIdList())
if (ReadToken(g_pf)->type == "$;")
{
if (MatchFieldDecMore())
return true;
}
else
{
BackToken(g_pf);
}
return false;
}
bool MatchFieldDecMore()
{
MatchFieldDecList();
return true;
}
bool MatchIdList()
{
if (ReadToken(g_pf)->type != "$id")
{
BackToken(g_pf);
return false;
}
return MatchIdMore();
}
bool MatchIdMore()
{
if (ReadToken(g_pf)->type == "$comma")
if (MatchIdList())
{
return true;
}
else
{
BackToken(g_pf);
}
return true;
}
bool MatchVarDecpart()
{
MatchVarDec();
return true;
}
bool MatchVarDec()
{
if (ReadToken(g_pf)->type != "$var")
{
BackToken(g_pf);
return false;
}
if (MatchVarDecList())
return true;
else
{
BackToken(g_pf);
return false;
}
}
bool MatchVarDecList()
{
if (!MatchTypeName())
return false;
if (!MatchVarIdList())
return false;
if (ReadToken(g_pf)->type != "$;")
{
BackToken(g_pf);
return false;
}
if (!MatchVarDecMore())
return false;
return true;
}
bool MatchVarDecMore()
{
MatchVarDecList();
return true;
}
bool MatchVarIdList()
{
if (ReadToken(g_pf)->type != "$id")
{
BackToken(g_pf);
return false;
}
if (!MatchVarIdMore())
return false;
return true;
}
bool MatchVarIdMore()
{
if (ReadToken(g_pf)->type == "$comma")
{
if (MatchVarIdList())
{
return true;
}
else
{
BackToken(g_pf);
}
}
else
{
BackToken(g_pf);
}
return true;
}
//过程声明
bool MatchProcDecpart()
{
MatchProcDec();
return true;
}
bool MatchProcDec()
{
if (ReadToken(g_pf)->type != "$procedure")
{
BackToken(g_pf);
return false;
}
if (!MatchProcName())
{
BackToken(g_pf);
return false;
}
if (ReadToken(g_pf)->type != "$(")
{
BackToken(g_pf);
BackToken(g_pf);
return false;
}
if (!MatchParamList())
{
BackToken(g_pf);
BackToken(g_pf);
return false;
}
if (ReadToken(g_pf)->type != "$)")
{
BackToken(g_pf);
BackToken(g_pf);
BackToken(g_pf);
return false;
}
if (ReadToken(g_pf)->type != "$;")
{
BackToken(g_pf);
BackToken(g_pf);
BackToken(g_pf);
BackToken(g_pf);
return false;
}
if (!MatchProcDecPart())
{
BackToken(g_pf);
return false;
}
if (!MatchProcBody())
{
BackToken(g_pf);
return false;
}
if (!MatchProcDecMore())
{
BackToken(g_pf);
return false;
}
return true;
}
bool MatchProcDecMore()
{
MatchProcDec();
return true;
}
bool MatchProcName()
{
if (ReadToken(g_pf)->type != "$id")
{
BackToken(g_pf);
return false;
}
return true;
}
//参数声明
bool MatchParamList()
{
MatchParamDecList();
return true;
}
bool MatchParamDecList()
{
if (!MatchParam())
return false;
if (!MatchParamMore())
return false;
return true;
}
bool MatchParamMore()
{
if (ReadToken(g_pf)->type == "$;")
{
if (MatchParamDecList())
return true;
else
BackToken(g_pf);
}
else
{
BackToken(g_pf);
}
return true;
}
bool MatchParam()
{
if (MatchTypeName())
return MatchFormList();
if (ReadToken(g_pf)->type == "$var")
{
if (MatchTypeName())
{
if (MatchFormList())
return true;
else
BackToken(g_pf);
}
else
{
BackToken(g_pf);
}
}
else
{
BackToken(g_pf);
}
return false;
}
bool MatchFormList()
{
if (ReadToken(g_pf)->type != "$id")
{
BackToken(g_pf);
return false;
}
if(!MatchFidMore())
{
BackToken(g_pf);
return false;
}
else
return true;
}
bool MatchFidMore()
{
if (ReadToken(g_pf)->type == "$comma")
{
if (MatchFormList())
return true;
else
BackToken(g_pf);
}
else
{
BackToken(g_pf);
}
return true;
}
//过程中的声明
bool MatchProcDecPart()
{
return MatchDeclarePart();
}
//过程体
bool MatchProcBody()
{
return MatchProgramBody();
}
bool MatchProgramBody()
{
if (ReadToken(g_pf)->type != "$begin")
{
BackToken(g_pf);
return false;
}
if (!MatchStmList())
{
BackToken(g_pf);
return false;
}
if (ReadToken(g_pf)->type != "$end")
{
BackToken(g_pf);
BackToken(g_pf);
return false;
}
return true;
}
//语句序列
bool MatchStmList()
{
if (!MatchStm())
return false;
if (!MatchStmMore())
return false;
return true;
}
bool MatchStmMore()
{
if (ReadToken(g_pf)->type == "$;")
{
if (MatchStmList())
return true;
else
{
BackToken(g_pf);
return false;
}
}
else
BackToken(g_pf);
return true;
}
//语句
bool MatchStm()
{
if (MatchConditionalStm())
return true;
if (MatchLoopStm())
return true;
if (MatchInputStm())
return true;
if (MatchOutputStm())
return true;
if (MatchReturnStm())
return true;
if (ReadToken(g_pf)->type == "$id")
if (MatchAssCall())
return true;
else
BackToken(g_pf);
else
BackToken(g_pf);
return false;
}
bool MatchAssCall()
{
if (MatchAssignmentRest())
return true;
if (MatchCallStmRest())
return true;
return false;
}
bool MatchAssignmentRest()
{
if (!MatchVariMore())
return false;
if (ReadToken(g_pf)->type == "$:=")
{
if (!MatchExp())
{
BackToken(g_pf);
return false;
}
else
{
return true;
}
}
else
{
BackToken(g_pf);
return false;
}
}
bool MatchConditionalStm()
{
if (ReadToken(g_pf)->type != "$if")
{
BackToken(g_pf);
return false;
}
if (!MatchRelExp())
{
BackToken(g_pf);
return false;
}
if (ReadToken(g_pf)->type != "$then")
{
BackToken(g_pf);
BackToken(g_pf);
return false;
}
if (!MatchStmList())
{
BackToken(g_pf);
BackToken(g_pf);
return false;
}
if (ReadToken(g_pf)->type != "$else")
{
BackToken(g_pf);
BackToken(g_pf);
BackToken(g_pf);
return false;
}
if (!MatchStmList())
{
BackToken(g_pf);
BackToken(g_pf);
BackToken(g_pf);
return false;
}
if (ReadToken(g_pf)->type != "$fi")
{
BackToken(g_pf);
BackToken(g_pf);
BackToken(g_pf);
BackToken(g_pf);
return false;
}
return true;
}
bool MatchLoopStm()
{
if (ReadToken(g_pf)->type != "$while")
{
BackToken(g_pf);
return false;
}
if (!MatchRelExp())
{
BackToken(g_pf);
return false;
}
if (ReadToken(g_pf)->type != "$do")
{
BackToken(g_pf);
BackToken(g_pf);
return false;
}
if (!MatchStmList())
{
BackToken(g_pf);
BackToken(g_pf);
return false;
}
if (ReadToken(g_pf)->type != "$endwh")
{
BackToken(g_pf);
BackToken(g_pf);
BackToken(g_pf);
return false;
}
return true;
}
bool MatchInputStm()
{
if (ReadToken(g_pf)->type != "$read")
{
BackToken(g_pf);
return false;
}
if (ReadToken(g_pf)->type != "$(")
{
BackToken(g_pf);
BackToken(g_pf);
return false;
}
if (!MatchInvar())
{
BackToken(g_pf);
BackToken(g_pf);
return false;
}
if (ReadToken(g_pf)->type != "$)")
{
BackToken(g_pf);
BackToken(g_pf);
BackToken(g_pf);
return false;
}
return true;
}
bool MatchInvar()
{
if (ReadToken(g_pf)->type != "$id")
{
BackToken(g_pf);
return false;
}
return true;
}
bool MatchOutputStm()
{
if (ReadToken(g_pf)->type != "$write")
{
BackToken(g_pf);
return false;
}
if (ReadToken(g_pf)->type != "$(")
{
BackToken(g_pf);
BackToken(g_pf);
return false;
}
if (!MatchExp())
{
BackToken(g_pf);
BackToken(g_pf);
return false;
}
if (ReadToken(g_pf)->type != "$)")
{
BackToken(g_pf);
BackToken(g_pf);
BackToken(g_pf);
return false;
}
return true;
}
bool MatchReturnStm()
{
if (ReadToken(g_pf)->type != "$return")
{
BackToken(g_pf);
return false;
}
if (ReadToken(g_pf)->type != "$(")
{
BackToken(g_pf);
BackToken(g_pf);
return false;
}
if (!MatchExp())
{
BackToken(g_pf);
BackToken(g_pf);
return false;
}
if (ReadToken(g_pf)->type != "$)")
{
BackToken(g_pf);
BackToken(g_pf);
BackToken(g_pf);
return false;
}
return true;
}
bool MatchCallStmRest()
{
if (ReadToken(g_pf)->type != "$(")
{
BackToken(g_pf);
return false;
}
if (!MatchActParamList())
{
BackToken(g_pf);
return false;
}
if (ReadToken(g_pf)->type != "$)")
{
BackToken(g_pf);
BackToken(g_pf);
return false;
}
return true;
}
bool MatchActParamList()
{
if (!MatchExp())
return MatchActParamMore();
return true;
}
bool MatchActParamMore()
{
if (ReadToken(g_pf)->type == "$;")
{
if (MatchActParamList())
return true;
else
{
BackToken(g_pf);
return false;
}
}
else
BackToken(g_pf);
return true;
}
bool MatchRelExp()
{
if (!MatchExp())
return false;
if (!MatchOtherRelE())
return false;
return true;
}
bool MatchOtherRelE()
{
if (!MatchCmpOp())
return false;
if (!MatchExp())
return false;
return true;
}
bool MatchExp()
{
if (!MatchTerm())
return false;
if (!MatchOtherTerm())
return false;
return true;
}
bool MatchOtherTerm()
{
if (MatchAddOp())
return MatchExp();
return true;
}
bool MatchTerm()
{
if (!MatchFactor())
return false;
if (!MatchOtherFactor())
return false;
return true;
}
bool MatchOtherFactor()
{
if (MatchMultOp())
return MatchTerm();
return true;
}
bool MatchFactor()
{
if (ReadToken(g_pf)->type == "$(")
{
if (MatchExp())
{
if(ReadToken(g_pf)->type == "$)")
return true;
else
{
BackToken(g_pf);
BackToken(g_pf);
return false;
}
}
else
{
BackToken(g_pf);
return false;
}
}
else
{
BackToken(g_pf);
}
if (ReadToken(g_pf)->type == "$INTC")
return true;
else
{
BackToken(g_pf);
}
if (MatchVariable())
return true;
return false;
}
bool MatchVariable()
{
if (ReadToken(g_pf)->type != "$id")
{
BackToken(g_pf);
return false;
}
return MatchVariMore();
}
bool MatchVariMore()
{
bool flag = true;
if (ReadToken(g_pf)->type == "$[")
{
if (MatchExp())
{
if (ReadToken(g_pf)->type == "$]")
{
return true;
}
else
{
BackToken(g_pf);
BackToken(g_pf);
return false;
}
}
else
{
BackToken(g_pf);
return false;
}
}
else
{
BackToken(g_pf);
}
if (ReadToken(g_pf)->type == "$.")
if (MatchFieldVar())
return true;
else
{
BackToken(g_pf);
return false;
}
else
{
BackToken(g_pf);
}
return true;
}
bool MatchFieldVar()
{
if (ReadToken(g_pf)->type == "$id")
{
if (MatchFieldVarMore())
return true;
else
{
BackToken(g_pf);
return false;
}
}
else
{
BackToken(g_pf);
return false;
}
}
bool MatchFieldVarMore()
{
if (ReadToken(g_pf)->type == "$[")
{
if (!MatchExp())
{
BackToken(g_pf);
return false;
}
if (ReadToken(g_pf)->type != "$]")
{
BackToken(g_pf);
return false;
}
}
else
{
BackToken(g_pf);
}
return true;
}
bool MatchCmpOp()
{
if (ReadToken(g_pf)->type == "$<")
return true;
else
BackToken(g_pf);
if (ReadToken(g_pf)->type == "$=")
return true;
else
BackToken(g_pf);
return false;
}
bool MatchAddOp()
{
if (ReadToken(g_pf)->type == "$+")
return true;
else
BackToken(g_pf);
if (ReadToken(g_pf)->type == "$-")
return true;
else
BackToken(g_pf);
return false;
}
bool MatchMultOp()
{
if (ReadToken(g_pf)->type == "$*")
return true;
else
BackToken(g_pf);
if (ReadToken(g_pf)->type == "$/")
return true;
else
BackToken(g_pf);
return false;
}
int main(int argc, char **argv)
{
//设置源文件名
string filename;
if (argc >= 2)
filename = argv[1];
else
filename = "snl.txt";
//打开*.token
g_pf = fopen((filename+".token").c_str(), "r");
//判断文件是否存在
if (g_pf == NULL)
{
printf("请先进行词法分析!\n");
return -1;
}
//打开语法分析日志文件,语法分析程序调用过程中记录分析信息
g_pf_log = fopen((filename + ".log").c_str(), "w+");
//进行语法分析,没有语法错误返回true,否则返回false
bool re = MatchProgram();
//最多匹配结果
while (result.size() < max_read_num)
{
ReadToken(g_pf);//读入一个token
}
//关闭文件*.token
fclose(g_pf);
//打开文件*.result
FILE * pfile = fopen((filename+".result").c_str(), "w+");
//打印result中除最后一个token之外的所有token
for (auto iter = result.begin(); iter != result.end() - 1; ++iter)
{
printf(" 已匹配%s", iter->c_str());
fprintf(pfile, "已匹配%s", iter->c_str());
}
if (re)//没有语法错误
{
//打印最后一个单词
printf(" 已匹配%s", (result.end()-1)->c_str());
fprintf(pfile, "已匹配%s", (result.end()-1)->c_str());
//打印提示成功信息
printf("语法分析完成,没有语法错误!\n");
fprintf(pfile, "语法分析完成,没有语法错误!\n");
}
else//存在语法错误
{
//打印错误信息
printf(" 语法错误:单词不匹配%s", (result.end()-1)->c_str());
fprintf(pfile, "语法错误:单词不匹配%s", (result.end()-1)->c_str());
}
//关闭文件*.result
fclose(pfile);
//暂停
system("pause");
}
程序运行结果打印到屏幕,并写入到*.result文件
语法分析阶段完成,如果要写编译器,后面还需要有语义分析,中间代码生成等等。