中间代码生成程序C语言,中间代码生成实验报告

实验程序由c语言完成,在Turboc 2.0环境中调试通过。

语义分析程序的基本做法是对文法中的每个产生式分别编写一个语义分析子程序,当程序语法部分进行推倒或规约时,就分别调用各自的语义分析程序。当语法分析结束时,语义分析也就结束了。

在本实验程序中,当语法分析部分识别出语法正确的句子时,就进入content函数(当语法分析识别出不正确的句子时,不进入content函数,也就是不进行语义分析),然后根据句子的类型进行分类,进入不同的语义处理部分。

对于赋值语句,关键是产生正确的处理算术表达式E的四元式。程序中的ec函数的功能就是产生算术表达式的四元式,在ec函数中使用了两个栈idshed,opshed,分别是算术表达式的数据栈和符号栈。每次提取一个数字和一个算符,然后将算符与与栈顶算符进行优先级比较,优先级高则将单前数字和算符进栈,低或者相等的话则将当前栈顶元素进行合并,产生四元式。直至整个算术表达式结束。其中还有一些细节问题,具体的做法可以参看程序。

对于实验给定的if语句的文法格式,条件判断式C只中可能是>或者<=两种关系,不可能是布尔表达式,这样程序就简单的多了。

通过ec函数可以产生条件判断式C中的E的四元式,然后只要加上转向四元式就可以了。本实验程序中只给出真出口的转向四元式,没有给出假出口的转向四元式,这在实际中是不可以的,但在本实验中,实际上是对每条独立的语句进行语法分析,给出假出口转向四元式实际上意义不大,而且假出口转向语句的转移目标必须要到整个语句分析结束以后才可以知道,这样就要建立栈,然后回填,这样会使程序复杂很多,所以没有加上假出口转向四元式。

对于while语句,具体的做法和if语句差不多,所不同的是当while语句结束时,要多出一条无条件转向四元式,重新转到条件判断式C的第一条四元式。当要产生无条件转向四元式时,它的转向目标C的第一条四元式已经产生了,所以具体的做起来是不太困难的。只要记下当前while中的C的第一条四元式的位置,填上就可以了。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
这里提供一个简单的中间代码生成器,使用C语言实现。该中间代码生成器可以将输入的算术表达式转换为三地址码。 代码如下: ```c #include <stdio.h> #include <string.h> #include <stdlib.h> #define MAX_EXPR_LEN 100 // 定义运算符优先级 int priority(char op) { switch (op) { case '+': case '-': return 1; case '*': case '/': return 2; case '(': case ')': return 0; default: printf("Error: unsupported operator %c\n", op); exit(1); } } // 将中缀表达式转换为后缀表达式 void infix2postfix(char *expr, char *postfix) { int i, j, len; char op_stack[MAX_EXPR_LEN]; int top = -1; len = strlen(expr); j = 0; for (i = 0; i < len; i++) { char ch = expr[i]; if (ch >= '0' && ch <= '9') { while (i < len && expr[i] >= '0' && expr[i] <= '9') { postfix[j++] = expr[i++]; } postfix[j++] = ' '; i--; } else if (ch == '(') { op_stack[++top] = ch; } else if (ch == ')') { while (top >= 0 && op_stack[top] != '(') { postfix[j++] = op_stack[top--]; postfix[j++] = ' '; } if (top >= 0 && op_stack[top] == '(') { top--; } else { printf("Error: unmatched parentheses\n"); exit(1); } } else if (ch == '+' || ch == '-' || ch == '*' || ch == '/') { while (top >= 0 && priority(op_stack[top]) >= priority(ch)) { postfix[j++] = op_stack[top--]; postfix[j++] = ' '; } op_stack[++top] = ch; } else { printf("Error: invalid character %c\n", ch); exit(1); } } while (top >= 0) { if (op_stack[top] == '(') { printf("Error: unmatched parentheses\n"); exit(1); } postfix[j++] = op_stack[top--]; postfix[j++] = ' '; } postfix[j] = '\0'; } // 生成三地址码 void gen_3addr_code(char *postfix) { char op_stack[MAX_EXPR_LEN]; int op_top = -1; char var_stack[MAX_EXPR_LEN]; int var_top = -1; int i, len; len = strlen(postfix); for (i = 0; i < len; i++) { char ch = postfix[i]; if (ch >= '0' && ch <= '9') { int val = 0; while (i < len && postfix[i] >= '0' && postfix[i] <= '9') { val = val * 10 + (postfix[i] - '0'); i++; } i--; char var[10]; sprintf(var, "t%d", ++var_top); var_stack[++var_top] = var[0]; printf("%s = %d\n", var, val); } else if (ch == ' ') { // do nothing } else { char op[10]; sprintf(op, "%c", ch); op_stack[++op_top] = op[0]; if (op_top >= 1 && var_top >= 1) { char var1[10], var2[10], result[10]; sprintf(var1, "%c", var_stack[var_top - 1]); sprintf(var2, "%c", var_stack[var_top]); sprintf(result, "t%d", ++var_top); var_stack[var_top - 1] = result[0]; var_top--; printf("%s = %s %c %s\n", result, var1, op_stack[op_top], var2); op_top--; } } } } int main() { char expr[MAX_EXPR_LEN]; printf("Please enter an arithmetic expression: "); scanf("%s", expr); char postfix[MAX_EXPR_LEN]; infix2postfix(expr, postfix); printf("Postfix expression: %s\n", postfix); gen_3addr_code(postfix); return 0; } ``` 实验报告: 1. 实验目的 本次实验的目的是通过编写一个中间代码生成器来深入了解编译原理中的一些基本概念和技术,如中缀表达式、后缀表达式、运算符优先级、三地址码等。 2. 实验内容 本次实验的主要内容是通过输入一个算术表达式,将其转换为后缀表达式,并生成相应的三地址码。 3. 实验过程 本次实验的实现过程可以分为以下几个步骤: (1)定义运算符优先级 在本次实验中,我们需要将算术表达式转换为后缀表达式,因此需要定义运算符优先级。具体实现中,我们可以使用一个函数来实现,如下所示: ```c int priority(char op) { switch (op) { case '+': case '-': return 1; case '*': case '/': return 2; case '(': case ')': return 0; default: printf("Error: unsupported operator %c\n", op); exit(1); } } ``` 该函数根据不同的运算符返回相应的优先级。 (2)将中缀表达式转换为后缀表达式 在定义了运算符优先级之后,我们可以使用一个函数来将中缀表达式转换为后缀表达式。具体实现中,我们可以使用一个栈来保存运算符,遍历中缀表达式中的每个字符,根据不同的情况来进行处理。具体实现可以参考下面的代码: ```c void infix2postfix(char *expr, char *postfix) { int i, j, len; char op_stack[MAX_EXPR_LEN]; int top = -1; len = strlen(expr); j = 0; for (i = 0; i < len; i++) { char ch = expr[i]; if (ch >= '0' && ch <= '9') { while (i < len && expr[i] >= '0' && expr[i] <= '9') { postfix[j++] = expr[i++]; } postfix[j++] = ' '; i--; } else if (ch == '(') { op_stack[++top] = ch; } else if (ch == ')') { while (top >= 0 && op_stack[top] != '(') { postfix[j++] = op_stack[top--]; postfix[j++] = ' '; } if (top >= 0 && op_stack[top] == '(') { top--; } else { printf("Error: unmatched parentheses\n"); exit(1); } } else if (ch == '+' || ch == '-' || ch == '*' || ch == '/') { while (top >= 0 && priority(op_stack[top]) >= priority(ch)) { postfix[j++] = op_stack[top--]; postfix[j++] = ' '; } op_stack[++top] = ch; } else { printf("Error: invalid character %c\n", ch); exit(1); } } while (top >= 0) { if (op_stack[top] == '(') { printf("Error: unmatched parentheses\n"); exit(1); } postfix[j++] = op_stack[top--]; postfix[j++] = ' '; } postfix[j] = '\0'; } ``` 该函数中,我们首先定义了一个运算符栈 `op_stack` 和一个栈顶指针 `top`,然后遍历输入的中缀表达式中的每个字符。如果当前字符是数字,则将其加入后缀表达式中;如果当前字符是左括号,则将其压入运算符栈中;如果当前字符是右括号,则将运算符栈中的元素出栈并加入后缀表达式中,直到遇到左括号;如果当前字符是运算符,则将运算符栈中的元素出栈并加入后缀表达式中,直到运算符栈为空或者栈顶元素的优先级小于当前运算符的优先级,然后将当前运算符压入运算符栈中。最后,将运算符栈中的所有元素出栈并加入后缀表达式中。 (3)生成三地址码 在将中缀表达式转换为后缀表达式之后,我们可以使用一个函数来生成相应的三地址码。具体实现中,我们可以使用两个栈:一个栈用来保存运算符,一个栈用来保存变量。遍历后缀表达式中的每个字符,根据不同的情况来进行处理。具体实现可以参考下面的代码: ```c void gen_3addr_code(char *postfix) { char op_stack[MAX_EXPR_LEN]; int op_top = -1; char var_stack[MAX_EXPR_LEN]; int var_top = -1; int i, len; len = strlen(postfix); for (i = 0; i < len; i++) { char ch = postfix[i]; if (ch >= '0' && ch <= '9') { int val = 0; while (i < len && postfix[i] >= '0' && postfix[i] <= '9') { val = val * 10 + (postfix[i] - '0'); i++; } i--; char var[10]; sprintf(var, "t%d", ++var_top); var_stack[++var_top] = var[0]; printf("%s = %d\n", var, val); } else if (ch == ' ') { // do nothing } else { char op[10]; sprintf(op, "%c", ch); op_stack[++op_top] = op[0]; if (op_top >= 1 && var_top >= 1) { char var1[10], var2[10], result[10]; sprintf(var1, "%c", var_stack[var_top - 1]); sprintf(var2, "%c", var_stack[var_top]); sprintf(result, "t%d", ++var_top); var_stack[var_top - 1] = result[0]; var_top--; printf("%s = %s %c %s\n", result, var1, op_stack[op_top], var2); op_top--; } } } } ``` 该函数中,我们首先定义了一个运算符栈 `op_stack` 和一个栈顶指针 `op_top`,以及一个变量栈 `var_stack` 和一个栈顶指针 `var_top`。然后遍历输入的后缀表达式中的每个字符。如果当前字符是数字,则将其转换为一个临时变量,并将其存入变量栈中;如果当前字符是运算符,则将其存入运算符栈中。如果此时运算符栈中的元素个数大于等于2,并且变量栈中的元素个数大于等于2,则从变量栈中弹出两个元素作为操作数,从运算符栈中弹出一个元素作为运算符,生成一个新的临时变量并将其存入变量栈中,同时输出一条三地址码。 4. 实验结果 以输入表达式 `2 + 3 * 4 - 5 / 6` 为例,输出的后缀表达式为 `2 3 4 * + 5 6 / -`,生成的三地址码为: ``` t1 = 3 * 4 t2 = 2 + t1 t3 = 5 / 6 t4 = t2 - t3 ``` 5. 实验总结 本次实验通过编写一个中间代码生成器,深入了解了编译原理中的一些基本概念和技术,如中缀表达式、后缀表达式、运算符优先级、三地址码等。本次实验还可以进一步拓展,例如可以实现语法分析器、词法分析器等,进一步加深对编译原理的理解。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值