目录
0x01 背景
《C语言大学教程-第八版》(《C How to Program》)391页,第十二章作业,专题:创建自己的编译器
在练习题7.27至练习题7.29中,我们介绍了Simpletron机器语言(Simpletron Machine Language,SML),还实现了一个Simpletron计算机模拟器来运行采用SML编写的程序。在练习题12.25至练习题12.29中,将创建一个将采用高级语言编写的程序转换成Simpletron机器语言程序的编译器。这个专题将程序设计的全过程“捆绑在一起”。我们将用新的高级语言来编写一些程序,用我们创建的这个编译器来编译这些程序,然后用在练习题7.28中创建的Simpletron计算机模拟器来运行这些程序
0x02 SML语法
-
代码格式
行号 代码 35 rem add y to total
-
用
(空格)
,\t
,\n
,\0
进行分隔,每个符号间都需要分隔符65 let t = ( ( 3 - 1 ) * ( 2 - t ) ) / ( 2 ^ 3 )
-
不区分大小写
-
定义关键字
-
rem
注释,例:10 rem add y to total
-
input
定义变量,例:10 INPUT x,y
-
if
、goto
判断跳转,例:20 if y == x goto 60
-
goto
无条件跳转,例:50 goto 20
-
let
变量赋值,例:50 let t = y
,50 let t = t + y
-
print
输出变量,例:50 print x
-
end
程序结束,例50 end
-
for
,to
,step
,next
for循环,step
可以省略,默认步长1
,例:50 for x to 10 step 2 ... 80 next
-
gets
,puts
输入\输出字符串,例:45 gets s 10 50 puts s 10
-
gosub
,return
跳转指定地址\返回指定地址,例:65 gosub 75 95 print t 99 end 75 let t = t + 2 80 return 95
-
0x03 应用
源码:
05 rem test
10 for x = 0 to 10 step 2
11 rem 这里x会输出3次
15 print x
20 if x == 6 goto 30
25 next
26 rem 输入y
30 input y
31 rem 输出刚刚输入的y
35 print y
65 gosub 75
66 rem 输出重新计算的y
95 print y
96 end
97 rem 重新计算y
75 let y = ( ( y + 10 ) / ( 10 - x ) ) * ( 2 ^ 3 )
80 return 95
编译过程:
sml.txt文件:
+2098
+3098
+2197
+2199
+2099
+3196
+4216
+2099
+3095
+2194
+2199
+1199
+2099
+3193
+4216
+4004
+1092
+1192
+4021
+1192
+4300
+2092
+3096
+2190
+2096
+3199
+2189
+2090
+3289
+2188
+2095
+3591
+2187
+2088
+3387
+2186
+2192
+4019
+0000
+0000
+0000
+0000
+0000
+0000
+0000
+0000
+0000
+0000
+0000
+0000
+0000
+0000
+0000
+0000
+0000
+0000
+0000
+0000
+0000
+0000
+0000
+0000
+0000
+0000
+0000
+0000
+0000
+0000
+0000
+0000
+0000
+0000
+0000
+0000
+0000
+0000
+0000
+0000
+0000
+0000
+0000
+0000
+0000
+0000
+0000
+0000
+0000
+0000
+0000
+0000
+0000
+0003
+0000
+0006
+0000
+0002
+0010
+0000
+0000
+0000
-9999
执行
0x04 SML_C实现
sml_compiler.h
#pragma once
/*
* SML编译器
*/
#include <stdio.h>
#include <stdlib.h>
#include <math.h>
#define SIZE 1000
#define FLAG -9999
// 输入/输出操作
// 从终端将一个字读到内存指定单元中
#define READ 10
// 将内存指定单元中的一个字写到终端
#define WRITE 11
// 回车换行
#define CRLF 12
// 输入字符串
#define INSTRING 13
// 输出字符串
#define OUTSTRING 14
// 载入/存储操作
// 将指定单元中的一个字载入累加器
#define LOAD 20
// 从累加器将一个字存放回内存指定单元中
#define STORE 21
// 算术运算操作
// 将内存中指定单元中的一个字域累加器中的字相加,结果留在累加器中
#define ADD 30
// 将累加器中的字减去内存指定单元中的一个字,结果留在累加器中
#define SUBTRACT 31
// 将累加器中的字除以内存指定单元中的一个字,结果留在累加器中
#define DIVIDE 32
// 将累加器中的字乘以内存指定单元中的一个字,结果留在累加器中
#define MUTIPLY 33
// 求模,结果放在累加器中
#define MODE 34
// 求幂,结果放在累加器中
#define POWER 35
// 控制操作的转移
// 转移到内存指定单元
#define BRANCH 40
// 如果累加器为负数,则转移到内存指定单元
#define BRANCHNGE 41
// 如果累加器为零,则转移到内存指定单元
#define BRANCHZERO 42
// 停机,即程序完成了它的任务
#define HALT 43
// map文件句柄
FILE* map_file_ptr;
// map文件名
#define MAP_FILE_NAME "map_file.txt"
//用有100元素的一维数组 memory 来模拟 Simpletron 的内存
int memory[SIZE] = { 0 };
// 使用变量 accumulator来表示累加器寄存器
int accumulator = 0;
// 使用变量 instructionCounter来跟踪包含正在执行的指令的内存位置
int instructionCounter = 0;
// 使用变量 operationCode来说明当前正在执行的操作, 也就是命令字的左边2位
int operation_code = 0;
// 使用变量 operand来指出当前指令所操作的内存位置,命令的右两位
int operand = 0;
// 不要直接从内存执行指令。而是将要执行的下一条指令从内存转移到变量 instructionRegister中
// 然后“取掉”左边的2位,并将它们放置在变量 operationCode中,“取掉”右边的2位,并将它们放置在 Operand中。
int instruction_register = 0;
// 指令计数器
int num = 0;
// debug flag debug模式默认关闭
int debug = 0;
// 下一条指令
void next_instruction();
// 执行指令
int do_instruction();
// 打印内存
void dump();
// 读取 sml指令
int read_file(int n, char* file_name);
// 打印程序头
void print_head();
// 打印到 map文件中
void print_to_map(char* message, int code);
// 除零错误
int err_zero(int operand);
// 累加器溢出
int err_accumulator(int accumulator);
// 操作码错误
int err_operand_code(int operation_code);
// 换行
void new_line();
// 输入字符串
void in_str();
// 输出字符串
void out_str();
sml_compiler.c
#include "sml_compiler.h"
/*程序开始*/
int main(void)
{
// 存放指令字符串数组
char code_array[CODESIZE] = { 0 };
// 没有解析数组初始化全部为-1
for (int i = 0; i < TABLESIZE; i++)
{
un_analyze_array[i] = -1;
}
// 第一次编译,填充符号表,指令表
first_compile(code_array);
// 打印指令数组
// print_sml(sml, SMLSIZE);
// 打印符号表
print_symbol_table(symbol_table, TABLESIZE);
// 填充第一次编译未能处理的符号给填充上
for (int i = 0; i < SMLSIZE && compile_flag == 1; i++)
{
if (un_analyze_array[i] != -1)
{
sml[i] += search_symbol_table(un_analyze_array[i], TABLESIZE, LINE_SYMBOL);
}
}
// 指令结束语句
sml[SMLSIZE - 1] = -9999;
print_sml(sml, SMLSIZE);
// 将SML指令写入文件
write_file(sml);
return 0;//程序结束
}//main函数结束
//===============================================================================================
// 将SML指令写入文件
void write_file(int sml[SMLSIZE])
{
FILE* fptr;
char fname[30];
printf("写入指令的文件名:");
gets_s(fname, 30);
if ((fptr = fopen(fname, "w")) == NULL)
printf("打开文件失败!\n");
else
{
for (int i = 0; i < SMLSIZE; i++)
{
fprintf(fptr, "%+05d\n", sml[i]);
}
}
}
// 指令计数器检查
bool instruct_check(void)
{
if (instruct_counter > SMLSIZE)
{
// 停止编译
printf("\n指令溢出错误:指令数大于内存,溢出!停止编译。\n");
compile_flag = 0;
return false;
}
else
return true;
}
//第一次编译
void first_compile(char* code_array)
{
// 源文件句柄
FILE* fptr;
// 文件名
char file_name[20];
// 读取行数计数器
int line = 0;
printf("输入 simple程序文件名:");
// gets_s()只从标准输入(通常是键盘)中读取数据,长度20个字符
gets_s(file_name, 20);
// 打开文件
if ((fptr = fopen(file_name, "r")) == NULL)
{
printf("文件打开失败。\n");
}
// 获取一行代码
fgets(code_array, CODESIZE - 1, fptr);
// 转小写
up_to_low(code_array, CODESIZE);
// 生成符号表
create_symbol_table(code_array);
while (!feof(fptr) && compile_flag == 1)
{
// 数组清零
memset(code_array, 0, sizeof(code_array));
// 获取一行代码
fgets(code_array, CODESIZE - 1, fptr);
line++;
//将代码中的大写字母改成小写字母
up_to_low(code_array, CODESIZE);
// 如果是 for语句
if (strstr(code_array, FOR_CODE) != NULL)
{
// 查找 for语句循环结束后的跳转地址
for_goto_line = search_for_goto_line(fptr, line);
if (for_goto_line == -1) {
printf("语法错误:for语句缺少 next语句。\n");
compile_flag = 0;
}
}
// 生成符号表及SML指令
create_symbol_table(code_array);
}
// 关闭文件
fclose(fptr);
}
//查找 for语句循环结束后的跳转地址
int search_for_goto_line(FILE* fptr, int line)
{
int count = 0;
int line_code = 0;
char s[CODESIZE] = { 0 };
// 将文件内位置指针移至开头
rewind(fptr);
// 获取一行代码
fgets(s, CODESIZE - 1, fptr);
while (!feof(fptr))
{
count++;
if (count == line)
{
while (!feof(fptr))
{
// 获取一行代码
fgets(s, CODESIZE - 1, fptr);
if (strstr(s, NEXT_CODE) != NULL)
{
// 获取一行代码
fgets(s, CODESIZE - 1, fptr);
// 获取到 next语句下一行行号
line_code = atoi(s);
// 文件内部位置指针返回到调用时的位置
count = 0;
// 将文件内位置指针移至开头
rewind(fptr);
while (!feof(fptr))
{
// 获取一行代码
fgets(s, CODESIZE - 1, fptr);
if (count == line)
{
return line_code;
}
count++;
}
}
}
}
fgets(s, CODESIZE - 1, fptr);//获取一行代码
}
return -1;//未找到
}
// 大写转小写字母
void up_to_low(char* code, int size)
{
for (int i = 0; i < size; i++)
{
// 判断是字母
if (isalpha(code[i]))
// 全部转小写
code[i] = tolower(code[i]);
}
}
// 生成符号表和SML指令
// codeArray: 一行代码字符串
void create_symbol_table(char* one_line_code)
{
// 一行代码分解出的指令数组
char code_spilt_array[CODESIZE][CODESIZE] = { 0 }; //分解数组
// 分解字符串的个数
int code_split_array_len = 0;
// 一行代码符号表填充完成标识
int fill_over_flag = 1;
char infix[INFIXSIZE] = { 0 };//中缀表达式记录数组
// 一行代码的备份
char one_line_code_copy[CODESIZE] = { 0 };
// 指令语句复制
strcpy(one_line_code_copy, one_line_code);
// 一行代码分解后字符的个数
code_split_array_len = strtok_string(code_spilt_array, one_line_code, SPLIT_OPERATOR);
// 解析语句
for (int code_index = 0; code_index < code_split_array_len && fill_over_flag == 1; code_index++)
{
//第1个字符串
if (code_index == 0)
{
//行号入符号表处理
line_symbol_process(code_spilt_array, code_index);
}
else
{
// 判断指令是不是关键字
if (keywords(code_spilt_array[code_index]))
{
// 是关键字
// 判断指令是不是注释
if (rem_code(code_spilt_array, code_index)) {
// 是注释,退出一行的循环
fill_over_flag = 0;
}
else
{
if (strcmp(code_spilt_array[code_index], INPUT_CODE) == 0) {
// 如果是 input指令
fill_over_flag = input_code(code_spilt_array, code_index);
}
if (strcmp(code_spilt_array[code_index], IF_CODE) == 0)
{
// 如果是if指令
// 在符号表中找 if关键字后面的变量
if (search_symbol_table(code_spilt_array[code_index + 1][0], TABLESIZE, VARIABLE_SYMBOL) == -1) {
// 符号表中未找到“if”指令后的变量
// 单字符变量名入符号表
symbol_table[table_counter].symbol = code_spilt_array[code_index + 1][0];
// 类型
symbol_table[table_counter].type = VARIABLE_SYMBOL;
// 地址
symbol_table[table_counter].location = sml_up_count;
// 符号表计数器加1
table_counter++;
// 高位数据计数器减一
sml_up_count--;
// 生成SML指令
fill_over_flag = if_goto_code(code_spilt_array, code_index);
}
else
{
//如果符号表中找到“if”指令后的变量,无需插入符号表
fill_over_flag = if_goto_code(code_spilt_array, code_index);
}
}// if指令结束
if (strcmp(code_spilt_array[code_index], LET_CODE) == 0)
{
// 如果是 let指令
if (search_symbol_table(code_spilt_array[code_index + 1][0], TABLESIZE, VARIABLE_SYMBOL) == -1) {
// 符号表中未找到"let"指令后的变量名x
// 单字符变量名入符号表
symbol_table[table_counter].symbol = code_spilt_array[code_index + 1][0];
// 类型
symbol_table[table_counter].type = VARIABLE_SYMBOL;
symbol_table[table_counter].location = sml_up_count;
// 记录 let左操作数变量的内存位置
let_variable_location = sml_up_count;
sml_up_count--;
// 符号表计数器加1
table_counter++;
// 判断 let x =
if (code_spilt_array[code_index + 2][0] == ASSIGNMENT_OPERATOR)
{
//第二次编译 let指令
let_code(code_spilt_array, code_index, code_split_array_len);
//获取中缀表达式
process_infix(infix, one_line_code_copy);
}
// 退出循环
fill_over_flag = 0;
}
else
{
// 符号表中找到"let"指令后的变量名x
// 记录 let左操作数变量的内存位置
let_variable_location = search_symbol_table(code_spilt_array[code_index + 1][0], TABLESIZE, VARIABLE_SYMBOL);
if (code_spilt_array[code_index + 2][0] == ASSIGNMENT_OPERATOR)
{
// 解析 let表达式
let_code(code_spilt_array, code_index, code_split_array_len);
// 处理中缀表达式
process_infix(infix, one_line_code_copy);
}
else {
printf("let指令后缺少\'=\'运算符。\n");
// 停止编译
compile_flag = 0;
}
fill_over_flag = 0;
}//let指令后第1个变量解析结束
}// let指令解析结束
if (strcmp(code_spilt_array[code_index], GOTO_CODE) == 0)
{
// goto指令处理
fill_over_flag = goto_code(code_spilt_array, code_index);
}
if (strcmp(code_spilt_array[code_index], PRINT_CODE) == 0)
{
//print指令处理
fill_over_flag = print_code(code_spilt_array, code_index);
}
if (strcmp(code_spilt_array[code_index], END_CODE) == 0)
{
// end指令处理
fill_over_flag = end_code(code_spilt_array, code_index);
}
if (strcmp(code_spilt_array[code_index], GOSUB_CODE) == 0)
{
//gosub 下一条指令地址,待填充,但是内存位置当前是可以确定的
return_address = instruct_counter + 1;
//gosub 指令处理
fill_over_flag = gosub_code(code_spilt_array, code_index);
}
if (strcmp(code_spilt_array[code_index], RETURN_CODE) == 0)
{
// SML return指令
sml[instruct_counter] = BRANCH * 100 + return_address;
instruct_counter++;
instruct_check();
sml_low_count++;
fill_over_flag = 0;
}
if (strcmp(code_spilt_array[code_index], FOR_CODE) == 0)
{
// for指令处理
fill_over_flag = for_code(code_spilt_array, code_index);
}
if (strcmp(code_spilt_array[code_index], NEXT_CODE) == 0)
{
// 直接跳转到 for_return_address的地址
sml[instruct_counter] = BRANCH * 100 + for_return_address;
instruct_counter++;
instruct_check();
sml_low_count++;
fill_over_flag = 0;
}
if (strcmp(code_spilt_array[code_index], GETS_CODE) == 0)
{
// gets语句处理
fill_over_flag = gets_code(code_spilt_array, code_index);
}
if (strcmp(code_spilt_array[code_index], PUTS_CODE) == 0)
{
// puts语句处理
fill_over_flag = puts_code(code_spilt_array, code_index);
}
}//非rem指令解析结束
}
else {
// 单行指令只有行号,错误
printf("语法错误:指令关键字错误。\n");
// 停止编译
compile_flag = 0;
}//指令关键字解析结束
}//其他字符串解析结束
}
}
//行号入符号表处理
void line_symbol_process(char code_spilt_array[][CODESIZE], int n)
{
// 是第一个行号,并且是数字类型
if (isdigit(code_spilt_array[n][0]))
{
// tablecount:符号表计数器
// symbol是符号
symbol_table[table_counter].symbol = atoi(code_spilt_array[n]);
// L是定义的行号类型
symbol_table[table_counter].type = LINE_SYMBOL;
// 在内存中的地址
symbol_table[table_counter].location = sml_low_count;
// 符号表计数器+1
table_counter++;
}
// 如果第一个指令是@,for循环标识
else if (code_spilt_array[n][0] = AT_SYMBOL)
{
// 行号
symbol_table[table_counter].symbol = code_spilt_array[n][0];
// F符号
symbol_table[table_counter].type = FOR_STMBOL;
// 在内存中的地址
symbol_table[table_counter].location = sml_low_count;
table_counter++;
}
else {
printf("语法错误:缺少行号。\n");
compile_flag = 0;//停止编译
}
}
// rem指令处理
bool rem_code(char code_spilt_array[][CODESIZE], int n)
{
// 判断是不是注释
if (strcmp(code_spilt_array[n], REM_CODE) == 0)
// 是注释
return true;
// 不是注释
return false;
}
//input指令处理
int input_code(char code_spilt_array[][CODESIZE], int n)
{
int guard = 1;
// input指令后面跟的就是参数
input_parameters_parse(code_spilt_array[n + 1]);
guard = 0;//退出循环
return guard;
}
// 参数解析
void input_parameters_parse(char* parameters)
{
int parameter_size;
char parameter_split_array[CODESIZE][CODESIZE] = { 0 };//分解参数数组
/*参数检查*/
if (strlen(parameters) == 0)
{
printf("语法错误:缺少参数!\n");
compile_flag = 0;//停止编译
}
else
{
// 判断参数逗号分隔符
for (unsigned int i = 0; i < strlen(parameters); i++)
{
if ((i % 2) != 0)
{
if (parameters[i] != ',') {
printf("语法错误:参数间的分隔符请使用\',\'分隔符!\n");
compile_flag = 0;//停止编译
}
}
}
}
// 分解参数列表
parameter_size = strtok_string(parameter_split_array, parameters, " ,\t\n\0");
for (int i = 0; i < parameter_size; i++)
{
/*处理符号表-符号表中未找到*/
if (search_symbol_table(parameter_split_array[i][0], TABLESIZE, VARIABLE_SYMBOL) == -1) {
// 符号表中未找到
// 单字符变量名入符号表
symbol_table[table_counter].symbol = parameter_split_array[i][0];
// 类型
symbol_table[table_counter].type = VARIABLE_SYMBOL;
symbol_table[table_counter].location = sml_up_count;
// 生成SML指令
// 将参数加载到内存中
sml[instruct_counter] = READ * 100 + symbol_table[table_counter].location;
sml_up_count--;
table_counter++;
sml_low_count++;
instruct_counter++;
instruct_check();
}
else
{
// 如果符号表中已经存在
// SML指令
sml[instruct_counter] = READ * 100 + search_symbol_table(parameter_split_array[i][0], TABLESIZE, VARIABLE_SYMBOL);
sml_up_count--;
table_counter++;
sml_low_count++;
instruct_counter++;
instruct_check();
}
}
}
int if_goto_code(char code_spilt_array[][CODESIZE], int n)
{
int guard = 1;
// 第一步加y加载到累加器中
// SML指令
sml[instruct_counter] = LOAD * 100 + search_symbol_table(code_spilt_array[n + 1][0], TABLESIZE, VARIABLE_SYMBOL);
instruct_counter++;
sml_low_count++;
instruct_check();
// 第二部 if语句处理
// todo ylc 只处理“==”,其他大于小于情况暂未处理
// todo ylc 复杂二维表达式没有处理
// todo ylc bool类型的符号没有处理
if (is_relational_operators(code_spilt_array[n + 2]) == 1)
{
if (isdigit(code_spilt_array[n + 3][0]))
{
//如果是数字符
if (search_symbol_table(atoi(code_spilt_array[n + 3]), TABLESIZE, CONSTANT_SYMBOL) != -1) {
// 没有找到常量值
sml[instruct_counter] = SUBTRACT * 100 + search_symbol_table(atoi(code_spilt_array[n + 3]), TABLESIZE, CONSTANT_SYMBOL);//SML指令
instruct_counter++;
instruct_check();
sml_low_count++;
}
else
{
// 未找到“==”运算符后的变量
// 常量值入符号表
symbol_table[table_counter].symbol = atoi(code_spilt_array[n + 3]);
// 类型
symbol_table[table_counter].type = CONSTANT_SYMBOL;
symbol_table[table_counter].location = sml_up_count;
// 常量值存入内存
// 整数常量存入内存
sml[sml_up_count] = atoi(code_spilt_array[n + 3]);
sml_up_count--;
// SML指令
sml[instruct_counter] = SUBTRACT * 100 + symbol_table[table_counter].location;
instruct_counter++;
instruct_check();
sml_low_count++;
table_counter++;
}
}
else
{
// 单字变量符
if (search_symbol_table(code_spilt_array[n + 3][0], TABLESIZE, VARIABLE_SYMBOL) != -1) {
// 找到变量'x'
sml[instruct_counter] = SUBTRACT * 100 + search_symbol_table(code_spilt_array[n + 3][0], TABLESIZE, VARIABLE_SYMBOL);//SML指令
instruct_counter++;
instruct_check();
sml_low_count++;
}
else
{
// 未找到“==”运算符后的变量
symbol_table[table_counter].symbol = code_spilt_array[n + 3][0];
symbol_table[table_counter].type = VARIABLE_SYMBOL;
symbol_table[table_counter].location = sml_up_count;
sml[instruct_counter] = SUBTRACT * 100 + symbol_table[table_counter].location;
instruct_counter++;
instruct_check();
sml_low_count++;
table_counter++;
}
}
}
// 第三步 goto语句处理
if (strcmp(code_spilt_array[n + 4], GOTO_CODE) == 0)
{
if (search_symbol_table(atoi(code_spilt_array[n + 5]), TABLESIZE, LINE_SYMBOL) != -1)
{
// 符号表中找到
sml[instruct_counter] = HALT * 100 + atoi(code_spilt_array[n + 5]);
instruct_counter++;
instruct_check();
sml_low_count++;
}
else
{
sml[instruct_counter] = BRANCHZERO * 100 + 00;
// goto的地址不确定,第二次编译的时候处理
un_analyze_array[instruct_counter] = atoi(code_spilt_array[n + 5]);
instruct_counter++;
instruct_check();
sml_low_count++;
}
}
else {
printf("语法错误:缺少 goto指令。\n");
compile_flag = 0;//停止编译
}
guard = 0;//退出循环
return guard;
}
// let指令处理
void let_code(char code_spilt_array[][CODESIZE], int code_index, int code_spilt_array_size)
{
// 处理表达式-表达式所有符号入符号表
// n 是 let的位置,n+1是赋值左值的位置,n+2是'='的位置
for (int j = code_index + 3; j < code_spilt_array_size; j++)
{
if (isalpha(code_spilt_array[j][0]))
{ //如果首字符是字符: let x = y
if (search_symbol_table(code_spilt_array[j][0], TABLESIZE, VARIABLE_SYMBOL) == -1)
{
//符号表中未找到
symbol_table[table_counter].symbol = code_spilt_array[code_index + 1][0];
symbol_table[table_counter].type = VARIABLE_SYMBOL;
symbol_table[table_counter].location = sml_up_count;
sml_up_count--;
table_counter++;
}
}
else if (isdigit(code_spilt_array[j][0]))
{
//如果首字符是数字 let x = 1 + 2
if (search_symbol_table(atoi(code_spilt_array[j]), TABLESIZE, CONSTANT_SYMBOL) == -1)
{
symbol_table[table_counter].symbol = atoi(code_spilt_array[j]);
symbol_table[table_counter].type = CONSTANT_SYMBOL;
symbol_table[table_counter].location = sml_up_count;
sml[sml_up_count] = atoi(code_spilt_array[j]);
sml_up_count--;
table_counter++;
}
}
}
}
//获取 infix中缀表达式
void process_infix(char* infix, char* s)
{
//将表达式中缀转换为后缀表示法
int j = 0;
//查找'='
while (s[j] != ASSIGNMENT_OPERATOR)
{
j++;
}
strcpy(infix, &s[j + 1]);
// 将结尾的换行符替换为空字符
j = 0;
while (infix[j] != '\n') {
j++;
}
infix[j] = NULL_CHAR;
//表达式转换及计数
infix_to_postfix(infix);
}
//goto指令处理
int goto_code(char code_spilt_array[][CODESIZE], int code_index)
{
int guard = 1;
int addr = atoi(code_spilt_array[code_index + 1]);
if (search_symbol_table(addr, TABLESIZE, LINE_SYMBOL) != -1)
{
// SML指令
sml[instruct_counter] = BRANCH * 100 + search_symbol_table(addr, TABLESIZE, LINE_SYMBOL);
//指令计数器加1
instruct_counter++;
//指令计数器检查
instruct_check();
//低位数据计数器加1
sml_low_count++;
}
else//符号表中未找到
{
// 可能是往下跳,还没有编译到,放到未处理中,后续处理
// SML指令
sml[instruct_counter] = BRANCH * 100 + 00;
un_analyze_array[instruct_counter] = addr;
instruct_counter++;
instruct_check();
sml_low_count++;
}
guard = 0;
return guard;
}
// print指令处理
int print_code(char code_spilt_array[][CODESIZE], int code_index)
{
int guard = 1;
int parameter_array_len;
char parameter_array[CODESIZE][CODESIZE] = { 0 };
// 参数检查
if (strlen(code_spilt_array[code_index + 1]) == 0)
{
printf("语法错误:缺少参数!\n");
compile_flag = 0;//停止编译
}
else
{
// 判断参数逗号分隔符
for (unsigned int i = 0; i < strlen(code_spilt_array[code_index + 1]); i++)
{
if ((i % 2) != 0)
{
if (code_spilt_array[code_index + 1][i] != ',') {
printf("语法错误:参数间的分隔符请使用\',\'分隔符!\n");
compile_flag = 0;//停止编译
}
}
}
}
// 分解参数列表
parameter_array_len = strtok_string(parameter_array, code_spilt_array[code_index + 1], " ,\t\n\0");
for (int i = 0; i < parameter_array_len; i++)
{
if (search_symbol_table(parameter_array[i][0], TABLESIZE, VARIABLE_SYMBOL) != -1)
{
// 符号表中找到
// SML指令
sml[instruct_counter] = WRITE * 100 + search_symbol_table(parameter_array[i][0], TABLESIZE, VARIABLE_SYMBOL);
//指令计数器加1
instruct_counter++;
//指令计数器检查
instruct_check();
//低位数据计数器加1
sml_low_count++;
}
else
{
//符号表中未找到
printf("语法错误!该变量不存在。\n");
compile_flag = 0;//停止编译
}
}
guard = 0;//退出循环
return guard;
}
// end指令处理
int end_code(char code_spilt_array[][CODESIZE], int n)
{
int guard = 1;
sml[instruct_counter] = HALT * 100 + 00;
instruct_counter++;
instruct_check();
sml_low_count++;
guard = 0;//退出循环
return guard;
}
//gosub 指令处理
int gosub_code(char code_spilt_array[][CODESIZE], int code_index)
{
int guard = 1;
// 符号表中找到
int addr = atoi(code_spilt_array[code_index + 1]);
if (search_symbol_table(addr, TABLESIZE, LINE_SYMBOL) != -1)
{
//SML指令
sml[instruct_counter] = BRANCH * 100 + search_symbol_table(addr, TABLESIZE, LINE_SYMBOL);
instruct_counter++;
instruct_check();
sml_low_count++;
}
else
{
//符号表中未找到
sml[instruct_counter] = BRANCH * 100 + 00;
un_analyze_array[instruct_counter] = addr;
instruct_counter++;
instruct_check();
sml_low_count++;
}
guard = 0;//退出循环
return guard;
}
// forCode指令处理
// for x = 2 to 10 step 2
int for_code(char code_spilt_array[][CODESIZE], int code_index)
{
int guard = 1;
// 接收翻译后的语句
char translation[CODESIZE] = { 0 };
char x;
// 2 || 10 || 2
int value;
// 第1步:语法检查
for_grammar_check(code_spilt_array, code_index);
// 第2步:翻译语句 x = 2
// x
x = code_spilt_array[code_index + 1][0];
// 2
value = atoi(code_spilt_array[code_index + 3]);
// @为 for语句标记符,'\n'符合 let解析条件
// @ let x = 2\n
sprintf(translation, "%c%s%c%s%d%s%d%c", AT_SYMBOL, " let ", x, " = ", 0, " + ", value, '\n');
// printf("%s\n", translation);
// 生成符号表及SML指令
create_symbol_table(translation);
// 第3步:翻译语句 to 10
// next循环标号地址,返回时会再次跳转到该行指令
for_return_address = instruct_counter;
// 10
value = atoi(code_spilt_array[code_index + 5]);
// @ if x == 10 goto for_return_address
sprintf(translation, "%c%s%c%s%d%s%d", AT_SYMBOL, " if ", x, " == ", value, " goto ", for_goto_line);
// printf("%s\n", translation);
// 生成符号表及SML指令
create_symbol_table(translation);
// 第4步:翻译 step 2语句
if (strcmp(code_spilt_array[7], STEP_CODE) == 0)
{
// 含有step关键字
value = atoi(code_spilt_array[code_index + 7]);//2
// 写入数组,@为for语句标记符
// @ let x = x + 2\n
sprintf(translation, "%c%s%c%s%c%s%d%c", AT_SYMBOL, " let ", x, " = ", x, " + ", value, '\n');
}
else//没有 step关键字
{
value = 1;//默认 step = 1
// @ let x = x + 2\n
sprintf(translation, "%c%s%c%s%c%s%d%c", '@', " let ", x, " = ", x, " + ", value, '\n');//写入数组,@为for语句标记符
}
// printf("%s\n", translation);
//生成符号表及SML指令
create_symbol_table(translation);
guard = 0;
return guard;
}
//gets 输入字符串语句处理
int gets_code(char code_spilt_array[][CODESIZE], int code_index)
{
int guard = 1;
// 先计算分配字符串所需的内存空间
int str_len = atoi(code_spilt_array[code_index + 2]);
if (search_symbol_table(str_len, TABLESIZE, CONSTANT_SYMBOL) == -1)
{
//符号表中未找到
//整数值入符号表
symbol_table[table_counter].symbol = code_spilt_array[code_index + 2][0];
symbol_table[table_counter].type = CONSTANT_SYMBOL;
symbol_table[table_counter].location = sml_up_count;
sml_up_count--;
table_counter++;
}
// 字符串预留内存空间
sml_up_count -= atoi(code_spilt_array[code_index + 2]);
// 符号表中未找到
if (search_symbol_table(code_spilt_array[code_index + 1][0], TABLESIZE, STRING_SYMBOL) == -1)
{
symbol_table[table_counter].symbol = code_spilt_array[code_index + 1][0];
symbol_table[table_counter].type = STRING_SYMBOL;
symbol_table[table_counter].location = sml_up_count;
sml_up_count--;
table_counter++;
}
// sml指令
sml[instruct_counter] = INSTRING * 100 + search_symbol_table(code_spilt_array[code_index + 1][0], TABLESIZE, STRING_SYMBOL);
instruct_counter++;
instruct_check();
sml_low_count++;
guard = 0;
return guard;
}
//puts输出字符串语句处理
int puts_code(char code_spilt_array[][CODESIZE], int code_index)
{
int guard = 1;
// 要显示的字符串结尾添加空字符
sml[search_symbol_table(code_spilt_array[code_index + 1][0], TABLESIZE, STRING_SYMBOL) + atoi(code_spilt_array[code_index + 2])] = '\0';
// SML指令 第1个字节为长度,第2个字节开始
sml[instruct_counter] = OUTSTRING * 100 + search_symbol_table(code_spilt_array[code_index + 1][0], TABLESIZE, STRING_SYMBOL);
instruct_counter++;
instruct_check();
sml_low_count++;
guard = 0;
return guard;
}
// for语句语法错误检查,step关键字不检查
void for_grammar_check(char code_spilt_array[][CODESIZE], int code_index)
{
if (isalpha(code_spilt_array[2][0]) == 0) {
printf("语法错误:变量定义错误!\n");
compile_flag = 0;
}
if (code_spilt_array[3][0] != '=') {
printf("语法错误:\'=\'缺失!\n");
compile_flag = 0;
}
if (strcmp(code_spilt_array[5], "to") != 0) {
printf("语法错误:缺少关键字to!\n");
compile_flag = 0;
}
if (isdigit(code_spilt_array[6][0]) == 0) {
printf("语法错误:变量定义错误!\n");
compile_flag = 0;
}
}
//判断是否是运算符
int is_relational_operators(char* s)
{
if (strcmp(s, EQ_RELATION) == 0)
return 1;
if (strcmp(s, GE_RELATION) == 0)
return 2;
if (strcmp(s, LE_RELATION) == 0)
return 3;
if (strcmp(s, GT_RELATION) == 0)
return 4;
if (strcmp(s, LT_RELATION) == 0)
return 5;
return -1;
}
// 查找符号变量或常量的内存位置
int search_symbol_table(int value, int size, char c)
{
for (int i = 0; i < size; i++)
{
// 符号的值相同,符号的类型相同
if (symbol_table[i].symbol == value && symbol_table[i].type == c)
// 返回符号的内存位置
return symbol_table[i].location;
}
return -1;//未找到
}
// 判断是否指令关键字
bool keywords(char* s)
{
if (strcmp(s, REM_CODE) == 0)
return true;
if (strcmp(s, INPUT_CODE) == 0)
return true;
if (strcmp(s, LET_CODE) == 0)
return true;
if (strcmp(s, PRINT_CODE) == 0)
return true;
if (strcmp(s, GOTO_CODE) == 0)
return true;
if (strcmp(s, IF_CODE) == 0)
return true;
if (strcmp(s, END_CODE) == 0)
return true;
if (strcmp(s, GOSUB_CODE) == 0)
return true;
if (strcmp(s, RETURN_CODE) == 0)
return true;
if (strcmp(s, FOR_CODE) == 0)
return true;
if (strcmp(s, NEXT_CODE) == 0)
return true;
if (strcmp(s, GETS_CODE) == 0)
return true;
if (strcmp(s, PUTS_CODE) == 0)
return true;
if (strcmp(s, TO_CODE) == 0)
return true;
if (strcmp(s, STEP_CODE) == 0)
return true;
return false;
}
// 分解字符串并保存字符串数组
int strtok_string(char result_array[][INFIXSIZE], char* s, char* separator)
{
// 循环标识
char* token;
int split_size = 0; //计数器
// 第一次分解
token = strtok(s, separator);
while (token != NULL)
{
// 分解的子串放入结果数组
strcpy(result_array[split_size++], token);
// 继续分解其他子串
token = strtok(NULL, separator);
}
return split_size;
}
// 打印SML数组
void print_sml(int* s, int size)
{
printf("\nSML内存:\n");
for (int i = 0; i < size; i++)
{
printf("%+05d%c", s[i], ((i + 1) % 10) == 0 ? '\n' : ' ');
}
putchar('\n');
}
// 打印符号表
void print_symbol_table(TableEntry* s, int size)
{
printf("\n符号表:\n");
printf("\n%s\t\t%s\t\t%s\n", "符号", "类型", "位置");
for (int i = 0; i < size; i++)
{
if ((isalpha(s[i].symbol) && ((s[i].type == 'V') || (s[i].type == 'S'))) || s[i].symbol == '@')
printf("\'%c\'\t\t", s[i].symbol);
else
printf("%2d\t\t", s[i].symbol);
printf("%c\t\t%02d\n", s[i].type, s[i].location);
}
putchar('\n');
}
// 表达式转换及计数
void infix_to_postfix(char* infix)
{
// 链表节点指针初始化
StackNodePtr startPtr = NULL;
// 后缀表达式记录数组
char postfix_array[INFIXSIZE][INFIXSIZE] = { 0 };
// 分解数组
char split_infix[INFIXSIZE][INFIXSIZE] = { 0 };
// 临时字符
char tmp_ch;
// 字符个数
int split_infix_size = 0;
// 计数器
int i = 0;
// 后缀表达式字符串个数
int postfix_array_size = 0;
// 计算结果
int result = 0;
/*将左括号压入堆栈*/
tmp_ch = LEFT_BRACKETS;
// 将左括号压入栈
push(&startPtr, tmp_ch);
// 输出栈,测试
// print_stack(startPtr);
// 在 infix末尾追加')'
tmp_ch = RIGHT_BRACKETS;
while (infix[i] != NULL_CHAR)
// 移到 infix结尾
i++;
// 插入' '
infix[i] = SPACE_CHAR;
// 插入')'
infix[i + 1] = tmp_ch;
// 补上空字符
infix[i + 2] = NULL_CHAR;
// printf("%s\n", infix);
// 到这里,infix就只剩右值
// 分解文本并保存字符串数组
split_infix_size = strtok_string(split_infix, infix, SPLIT_OPERATOR);
// 将中缀表达式转换为后缀符号
do_infix_to_postfix(&startPtr, split_infix, split_infix_size, postfix_array);
// 输出,测试
// print_stack(startPtr);
// for (int i = 0; i < split_infix_size; i++)
// {
// printf("%s ", postfix_array[i]);
// }
// printf("\n");
// 计算转换后的后缀表达式字符串个数
while (postfix_array[postfix_array_size][0] != '\0')
{
postfix_array_size++;
}
result = postfix_to_sml(&startPtr, postfix_array, postfix_array_size);
// printf("表达式的结果 = %d\n", result);
}
//==========================================================================================
// 表达式中缀转后缀表示方法
// 将一个节点插入到栈顶
void push(StackNodePtr* topPtr, int value)
{
// 指向新节点的指针
StackNodePtr newPtr;
// 创建新节点
newPtr = malloc(sizeof(StackNode));
/*在栈顶插入节点*/
if (newPtr != NULL)
{
newPtr->data = value;
newPtr->nextPtr = *topPtr;
// 栈顶替换
*topPtr = newPtr;
}
else
printf("%c插入失败,没有足够的内存。\n", value);
}
// 从栈顶删除一个节点
int pop(StackNodePtr* topPtr)
{
// 临时节点的指针
StackNodePtr tempPtr;
// 节点值
int popValue;
tempPtr = *topPtr;
popValue = (*topPtr)->data;
*topPtr = (*topPtr)->nextPtr;
free(tempPtr);
return popValue;
}
// 判断堆栈是否为空
int is_empty(StackNodePtr sPtr)
{
return sPtr == NULL;
}
//输出堆栈
void print_stack(StackNodePtr topPtr)
{
/*如果堆栈为空*/
if (topPtr == NULL)
printf("堆栈为空。\n\n");
else
{
printf("堆栈:\n");
while (topPtr != NULL)
{
printf("%c--> ", topPtr->data);
// 下一个节点
topPtr = topPtr->nextPtr;
}
// 打印结尾NULL
printf("NULL\n\n");
}
}
// 将中缀表达式转换为后缀表达式
void do_infix_to_postfix(StackNodePtr* topPtr, const char split_infix[][INFIXSIZE],
const int split_infix_size, char postfix[][INFIXSIZE])
{
//postfix数组下标
int postfix_index = 0;
// 栈第判空
if (!is_empty(*topPtr))
{
for (int i = 0; i < split_infix_size; i++)
{
if (isdigit(split_infix[i][0]))
{
// 如果是数字
strcpy(postfix[postfix_index], split_infix[i]);
postfix_index++;
}
if (isalpha(split_infix[i][0]))
{
// 如果是单字符变量名
strcpy(postfix[postfix_index], split_infix[i]);
postfix_index++;
}
if (split_infix[i][0] == LEFT_BRACKETS)
// 如果是左括号
push(topPtr, split_infix[i][0]);
if (is_operator(split_infix[i][0]))
{
// 如果是运算符
if (is_operator((*topPtr)->data))
{
// 如果堆栈栈顶是运算符
if (precedence(split_infix[i][0]) <= precedence((*topPtr)->data))
{
postfix[postfix_index][0] = pop(topPtr);
postfix_index++;
push(topPtr, split_infix[i][0]);
}
else
push(topPtr, split_infix[i][0]);
}
else //栈顶不是运算符
push(topPtr, split_infix[i][0]);
}
if (split_infix[i][0] == RIGHT_BRACKETS)
{
//如果是右括号
while ((*topPtr)->data != LEFT_BRACKETS)
{
postfix[postfix_index][0] = pop(topPtr);
postfix_index++;
}
pop(topPtr);
}
}
}
else
printf("堆栈为空。\n");
}
//确定是否为运算符
int is_operator(char c)
{
// todo ylc 暂时只判断这6中运算符的优先级
switch (c) {
case ADD_OPERATOR:
case SUB_OPERATOR:
case MUL_OPERATOR:
case DIV_OPERATOR:
case MODEL_OPERATOR:
case POWER_OPERATOR:
return 1;
default:
return 0;
}
}
//确定运算符优先级
int precedence(char opreator)
{
switch (opreator) {
case ADD_OPERATOR:
case SUB_OPERATOR:
return 13;
case MUL_OPERATOR:
case DIV_OPERATOR:
case MODEL_OPERATOR:
return 12;
case POWER_OPERATOR:
return 6;
default:
return 0;
}
}
//==========================================================================================
//计算后缀表达式
int postfix_to_sml(StackNodePtr* topPtr, char postfix_array[][INFIXSIZE], int postfix_array_size)
{
int i = 0;
int operand1_addr = 0;
int operand2_addr = 0;
int result_addr = 0;
for (i = 0; i < postfix_array_size; i++)
{
if (isdigit(postfix_array[i][0]))
{
// 如果是数字符,压入内存
int constant = atoi(postfix_array[i]);
if (constant > 9999 || constant < -9999)
{
printf("语法错误:常量值溢出错误!常量整数值在-9999~+9999之间。\n");
compile_flag = 0;
}
// 在前面已经进行了符号填充,肯定能找到
// 返回符号表中存储的内存位置
int temp = search_symbol_table(constant, TABLESIZE, CONSTANT_SYMBOL);
push(topPtr, temp);//入栈
}
else if (islower(postfix_array[i][0]))
{
// 如果是小写单字符,压入其对应的内存位置
// 返回符号表中存储的内存位置
int temp = search_symbol_table(postfix_array[i][0], TABLESIZE, VARIABLE_SYMBOL);
// 入栈
push(topPtr, temp);
}
else
{
// 运算符
if (!is_empty(*topPtr))
// 第2个操作数
operand2_addr = pop(topPtr);
else
printf("堆栈为空.\n");
if (!is_empty(*topPtr))
// 第1个操作数,注意顺序
operand1_addr = pop(topPtr);
else
printf("堆栈为空.\n");
// 生成 sml指令,并压入内存
result_addr = binary_expression_to_sml(operand1_addr, operand2_addr, postfix_array[i][0]);
// 将存储结果的地址压入堆栈
push(topPtr, result_addr);
}
}
// 返回表达式计算结果
result_addr = pop(topPtr);
// 将累加器的值保存至=左侧操作数
// 在进行数学运算时,倒数第二步都是进行计算,在最后一步将计算结果的值存入内存后返回地址
// 倒数第二步还隐藏了一个动作,运算结果存在累加器中
// 到这里时,累加器里的值就是最后的结果
// 编写指令将结果的值放入到左操作数的内存地址中
sml[instruct_counter] = STORE * 100 + let_variable_location;
//指令计数器加1
instruct_counter++;
//指令计数器检查
instruct_check();
//低位数据计数器加1
sml_low_count++;
return result_addr;
}
// 计算表达式op1 operator op2
int binary_expression_to_sml(int op1_addr, int op2_addr, char operator)
{
// 计算结果的内存位置
int result_addr = 0;
// 加法
if (operator == ADD_OPERATOR) {
// SML指令,加载到累加器中
sml[instruct_counter] = LOAD * 100 + op1_addr;
// 指令计数器加1
instruct_counter++;
// 指令计数器检查
instruct_check();
// 低位数据计数器加1
sml_low_count++;
// SML指令,加指令
sml[instruct_counter] = ADD * 100 + op2_addr;
// 指令计数器加1
instruct_counter++;
// 指令计数器检查
instruct_check();
// 低位数据计数器加1
sml_low_count++;
// SML指令,结果存入到内存
sml[instruct_counter] = STORE * 100 + sml_up_count;
// 指令计数器加1
instruct_counter++;
// 指令计数器检查
instruct_check();
// 低位数据计数器加1
sml_low_count++;
// 计算结果
result_addr = sml_up_count;
}
// 减法
if (operator == SUB_OPERATOR) {
sml[instruct_counter] = LOAD * 100 + op1_addr;
instruct_counter++;
instruct_check();
sml_low_count++;
sml[instruct_counter] = SUBTRACT * 100 + op2_addr;
instruct_counter++;
instruct_check();
sml_low_count++;
sml[instruct_counter] = STORE * 100 + sml_up_count;
instruct_counter++;
instruct_check();
sml_low_count++;
result_addr = sml_up_count;
}
// 乘法
if (operator == MUL_OPERATOR) {
sml[instruct_counter] = LOAD * 100 + op1_addr;
instruct_counter++;
instruct_check();
sml_low_count++;
sml[instruct_counter] = MULTIPLY * 100 + op2_addr;
instruct_counter++;
instruct_check();
sml_low_count++;
sml[instruct_counter] = STORE * 100 + sml_up_count;
instruct_counter++;
instruct_check();
sml_low_count++;
result_addr = sml_up_count;
}
// 除法
if (operator == DIV_OPERATOR) {
sml[instruct_counter] = LOAD * 100 + op1_addr;
instruct_counter++;
instruct_check();
sml_low_count++;
sml[instruct_counter] = DIVIDE * 100 + op2_addr;
instruct_counter++;
instruct_check();
sml_low_count++;
sml[instruct_counter] = STORE * 100 + sml_up_count;
instruct_counter++;
instruct_check();
sml_low_count++;
result_addr = sml_up_count;
}
// 取模
if (operator == MODEL_OPERATOR) {
sml[instruct_counter] = LOAD * 100 + op1_addr;
instruct_counter++;
instruct_check();
sml_low_count++;
sml[instruct_counter] = MODE * 100 + op2_addr;
instruct_counter++;
instruct_check();
sml_low_count++;
sml[instruct_counter] = STORE * 100 + sml_up_count;
instruct_counter++;
instruct_check();
sml_low_count++;
result_addr = sml_up_count;
}
// 求幂
if (operator == POWER_OPERATOR) {
sml[instruct_counter] = LOAD * 100 + op1_addr;
instruct_counter++;
instruct_check();
sml_low_count++;
sml[instruct_counter] = POWER * 100 + op2_addr;
instruct_counter++;
instruct_check();
sml_low_count++;
sml[instruct_counter] = STORE * 100 + sml_up_count;
instruct_counter++;
instruct_check();
sml_low_count++;
result_addr = sml_up_count;
}
sml_up_count--;
return result_addr;
}
0x05 总结
更深刻的理解计算机软件实现原理与JVM实现原理
标签:code,counter,instruct,编译器,sml,简单,table,array From: https://www.cnblogs.com/ylc0x01/p/17476211.html