编译原理实践:C++实现语义分析器(学习笔记)

实践说明

【题目要求】
基于已编写的C++语法分析器,分析当前目录下input.txt文件中的语义并生成中间代码。
input.txt中的待分析代码必须以begin开头、以end结尾,文件最后以#结束。
输出结果存放到当前目录下的output.txt文件中。

【可分析语法】
算术表达式
多条简单赋值语句

【操作步骤】
1、在input.txt文件中输入或更改待分析的C源程序段(段末请以#结尾)。
2、双击程序exe文件即可完成语义分析程序的运行。
3、在output.txt文件中查看语义分析结果。

输入举例(input.txt)

begin
int a = 12;
int b = 1 + 2 * 3 - (a - 4) / 8;
a = b % 5;
end#

输出举例(output.txt)

Your words(must start with 'begin', and end with 'end'):

---------------------------------
begin
int a = 12;
int b = 1 + 2 * 3 - (a - 4) / 8;
a = b % 5;
end
---------------------------------

The result of semantic analysis:

(1) a = 12  
(2) t1 = 2 * 3
(3) t2 = 1 + t1
(4) t3 = a - 4
(5) t4 = t3 / 8
(6) t5 = t2 - t4
(7) b = t5  
(8) t6 = b % 5
(9) a = t6  

编程平台

CodeBlocks 10.05

代码实现

基本思路

运用递归下降语法制导翻译法,修改语法分析器,在语法分析部分插入语义动作。

语义分析部分预定义

struct  /*四元式表*/
{
	char result[8];
	char ag1[8];
	char op[8];
	char ag2[8];
}quad[21];
void emit(char *result,char *ag1,char *op,char *ag2); /*声明四元式生成函数*/
char* newtemp();     /*临时变量生成函数*/
int quadIndex = 0;   /*四元式下标*/
int k = 0;           /*临时变量下标*/
int sum = 0;         /*十进制数字*/

主函数定义

int main()
{
    freopen("input.txt","r",stdin);
    freopen("output.txt","w",stdout);

	inputBufferIndex = 0;          // 初始化输入缓冲区下标

	scanf("%[^#]s", inputBuffer);  // 读入源程序字符串到缓冲区,以#结束,允许多行输入,#会读成'\0'
	printf("Your words(must start with 'begin', and end with 'end'):\n\n");
	printf("---------------------------------\n");
    printf("%s\n", inputBuffer);
    printf("---------------------------------\n\n");
    printf("The result of semantic analysis:\n\n");

    oneWord = scaner(); // 获得一个新单词
    lrparser();

	if(lexicalError == true && syntacticError == true)
	{
	    printf("\nPlease correct the above lexical errors and syntactic errors for semantic analysis!\n");
	}
	else
	{
        if(lexicalError == true)
        {
            printf("\nPlease correct the above lexical errors for semantic analysis!\n");
        }
        else if(syntacticError == true)
        {
            printf("\nPlease correct the above syntactic errors for semantic analysis!\n");
        }
	}
	return 0;
}

语义分析部分函数

/*四元式生成函数*/
void emit(char *result,char *ag1,char *op,char *ag2)
{
    strcpy(quad[quadIndex].result,result); // 无法识别'->',得用'.'
    strcpy(quad[quadIndex].ag1,ag1);
    strcpy(quad[quadIndex].op,op);
    strcpy(quad[quadIndex].ag2,ag2);
    ++quadIndex;
}

/*临时变量生成函数*/
char* newtemp()
{
    char *p;
    char m[8];
    p = (char*)malloc(8);
    itoa(++k,m,10);
    strcpy(p+1,m);
    p[0] = 't';
    return p;
}

语法分析主函数

int lrparser()
{
    int schain = 0;
    while(isLineBreak()); // 判断是否存在换行
    if(oneWord -> categoryCode != 1) // 'begin'的种别码
    {
        cout << "missing 'begin' error in line " << rowNumber << "!" << endl;
        syntacticError = true;
    }
    else
    {
        oneWord = scaner(); // 获得一个新单词
    }
    schain = statementString();  // 调用语句串分析函数
    if(oneWord -> categoryCode != 12)
    {
        cout << "missing 'end' error in line " << rowNumber << "!" << endl;
        syntacticError = true;
    }
    else
    {
        oneWord = scaner(); // 获得一个新单词
        while(isLineBreak()); // 判断是否存在换行
        if(oneWord -> categoryCode == 1000 && syntacticError == false && lexicalError == false) // '\0'的种别码
        {
            for(int i = 0; i < quadIndex; ++i)
            {
                cout << "(" << i + 1 << ") ";
                cout << quad[i].result << " = ";
                cout << quad[i].ag1 << " ";
                cout << quad[i].op << " ";
                cout << quad[i].ag2 << endl;
            }
        }
        else
        {
            if(oneWord -> categoryCode != 1000)
            {
                cout << "the syntax after the first 'end' is invalid in line " << rowNumber << "!" << endl;
                syntacticError = true;
            }
            while(true)
            {
                oneWord = scaner(); // 获得一个新单词
                while(isLineBreak()); // 判断是否存在换行
                isLexicalError(); // 调用检测词法错误函数
                if(oneWord -> categoryCode == 1000)
                {
                    break;
                }
            }
        }
    }
    return schain;
}

语句串分析函数

int statementString()
{
    int schain = 0;
    while(isLineBreak()); // 判断是否存在换行
    schain = statement(); // 调用语句分析函数
    while(oneWord -> categoryCode == 64) // ';'的种别码
    {
        oneWord = scaner(); // 获得一个新单词
        while(isLineBreak()); // 判断是否存在换行
        isLexicalError(); // 调用检测词法错误函数
        schain = statement(); // 调用语句分析函数
    }
    return schain;
}

语句分析函数

int statement()
{
    char tt[8];
    char eplace[8];
    int schain = 0;
    switch (oneWord -> categoryCode)
    {
        case 1:
        {
            cout << "only the first 'begin' is valid in line " << rowNumber << "!" << endl;
            oneWord -> categoryCode = 64;
            syntacticError = true;
            break;
        }
        case 2:
        case 3:
        case 4:
        case 5:
        case 6:
        case 7:
        case 8:
        case 9:
        case 10:
        case 11:
        case 13:
        {
            if(oneWord -> categoryCode >= 2 && oneWord -> categoryCode <= 11)
            {
                oneWord = scaner(); // 获得一个新单词
                isLexicalError(); // 调用检测词法错误函数
                if(oneWord -> categoryCode == 64 || oneWord -> categoryCode == 12 || oneWord -> categoryCode == 1000
                   || oneWord -> categoryCode == 20) // 说明出现char;或char end或char'\0'或char'\n'的情况
                {
                    if(oneWord -> categoryCode == 20)
                    {
                        cout << "statement error in line " << (rowNumber - 1) << "!" << endl;
                        oneWord -> categoryCode = 64;
                    }
                    else
                    {
                        cout << "statement error in line " << rowNumber << "!" << endl;
                    }
                    syntacticError = true;
                }
            }
            strcpy(tt,wordBuffer);
            oneWord = scaner(); // 获得一个新单词
            isLexicalError(); // 调用检测词法错误函数
            if(oneWord -> categoryCode == 20)
            {
                cout << "missing ';' error in line "  << (rowNumber - 1) << "!" << endl;
                oneWord -> categoryCode = 64;
                syntacticError = true;
            }
            else if(oneWord -> categoryCode == 12 || oneWord -> categoryCode == 1000)
            {
                cout << "missing ';' error in line "  << rowNumber << "!" << endl;
                syntacticError = true;
            }
            else if(oneWord -> categoryCode >= 42 && oneWord -> categoryCode <= 52)
                          // '='、'+='、'-='、'*='、'/='、'%='、'>>='、'<<='、'&='、'^='、'|='的种别码
            {
                oneWord = scaner(); // 获得一个新单词
                while(isLineBreak()); // 判断是否存在换行
                isLexicalError(); // 调用检测词法错误函数
                strcpy(eplace,expression()); // 调用(等号右边的)表达式分析函数
                emit(tt,eplace,"","");
                schain = 0;
                if(oneWord -> categoryCode != 64) // 表达式一定以分号为结束
                {
                    if(oneWord -> categoryCode == 20) // 说明是换行符
                    {
                        cout << "missing ';' error in line "  << (rowNumber - 1) << "!" << endl;
                        oneWord -> categoryCode = 64;
                    }
                    else
                    {
                        cout << "missing ';' error in line "  << rowNumber << "!" << endl;
                    }
                    syntacticError = true;
                }
            }
            else if(oneWord -> categoryCode != 64)
            {
                cout << "missing equal sign error in line "  << rowNumber << "!" << endl;
                syntacticError = true;
            }
            return schain;
            break;
        }
        case 12:
        case 1000:
        {
            break;
        }
        default:
        {
            cout << "statement error in line " << rowNumber << "!" << endl;
            syntacticError = true;
            oneWord = scaner(); // 获得一个新单词
            while(isLineBreak()); // 判断是否存在换行
            isLexicalError(); // 调用检测词法错误函数
            while(oneWord -> categoryCode != 64 && oneWord -> categoryCode != 12
                && oneWord -> categoryCode != 1000)
            {
                oneWord = scaner(); // 获得一个新单词
                while(isLineBreak()); // 判断是否存在换行
                isLexicalError(); // 调用检测词法错误函数
            }
        }
    }
}

(等号右边的)表达式分析函数

char* expression()
{
    char *tp;
    char *ep2;
    char *eplace;
    char *tt;
    tp = (char*)malloc(12);
    ep2 = (char*)malloc(12);
    eplace = (char*)malloc(12);
    tt = (char*)malloc(12);
    strcpy(eplace,term()); // 调用项分析函数生成表达式计算的第一项eplace
    while(oneWord -> categoryCode == 21 || oneWord -> categoryCode == 22) // '+'或'-'的种别码
    {
        strcpy(tt,oneWord -> value);
        oneWord = scaner(); // 获得一个新单词
        while(isLineBreak()); // 判断是否存在换行
        isLexicalError(); // 调用检测词法错误函数
        strcpy(ep2,term()); // 调用项分析函数生成表达式计算的第二项ep2
        strcpy(tp,newtemp()); // 调用newtemp产生临时变量tp存储计算结果
        emit(tp,eplace,tt,ep2); // 生成四元式送入四元式表
        strcpy(eplace,tp); // 将计算结果作为下一次表达式计算的第一项eplace
    }
    return eplace;
}

项分析函数

char* term()
{
    char *tp;
    char *ep2;
    char *eplace;
    char *tt;
    tp = (char*)malloc(12);
    ep2 = (char*)malloc(12);
    eplace = (char*)malloc(12);
    tt = (char*)malloc(12);
    strcpy(eplace,factor()); // 调用因子分析函数生成表达式计算的第一项eplace
    while(oneWord -> categoryCode >= 23 && oneWord -> categoryCode <= 25) // '*'、'/'、'%'的种别码
    {
        strcpy(tt,oneWord -> value);
        oneWord = scaner(); // 获得一个新单词
        while(isLineBreak()); // 判断是否存在换行
        isLexicalError(); // 调用检测词法错误函数
        strcpy(ep2,factor()); // 调用因子分析函数生成表达式计算的第二项ep2
        strcpy(tp,newtemp()); // 调用newtemp产生临时变量tp存储计算结果
        emit(tp,eplace,tt,ep2); // 生成四元式送入四元式表
        strcpy(eplace,tp); // 将计算结果作为下一次表达式计算的第一项eplace
    }
    return eplace;
}

因子分析函数

char* factor()
{
    char *fplace;
    fplace = (char*)malloc(12);
    strcpy(fplace," ");
    if(oneWord -> categoryCode == 13) // 单词的种别码
    {
        strcpy(fplace,oneWord -> value);
        oneWord = scaner(); // 获得一个新单词
        isLexicalError(); // 调用检测词法错误函数
    }
    else if(oneWord -> categoryCode == 14) // 数字的种别码
    {
        itoa(sum,fplace,10);
        oneWord = scaner(); // 获得一个新单词
        isLexicalError(); // 调用检测词法错误函数
    }
    else if(oneWord -> categoryCode == 56) // '('的种别码
    {
        oneWord = scaner(); // 获得一个新单词
        while(isLineBreak()); // 判断是否存在换行
        isLexicalError(); // 调用检测词法错误函数
        fplace = expression(); // 调用(等号右边的)表达式分析函数
        if(oneWord -> categoryCode == 57) // ')'的种别码
        {
            oneWord = scaner(); // 获得一个新单词
            while(isLineBreak()); // 判断是否存在换行
            isLexicalError(); // 调用检测词法错误函数
        }
        else
        {
            cout << "missing ')' error in line " << rowNumber << "!" << endl;
            syntacticError = true;
        }
    }
    else
    {
        cout << "expression error in line " << rowNumber << "!" << endl;
        syntacticError = true;
    }
    return fplace;
}

如果文章内容出错或者您有更好的解决方法,欢迎到评论区指正和讨论!

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值