用C语言实现一个中间代码生成器,给出代码,并写入实验报告
时间: 2023-12-14 09:37:53 浏览: 170
这里提供一个简单的中间代码生成器,使用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. 实验总结
本次实验通过编写一个中间代码生成器,深入了解了编译原理中的一些基本概念和技术,如中缀表达式、后缀表达式、运算符优先级、三地址码等。本次实验还可以进一步拓展,例如可以实现语法分析器、词法分析器等,进一步加深对编译原理的理解。
阅读全文