题目
中国文化博大精深,从仓颉造字开始,汉字一直流传到了今天。我们在感叹汉字的源远流长时,也不禁感慨,为什么没有一门使用汉字编程的语言?
汉字真的不能编程吗?最近文言文编程火了一把,吾有一數。曰三。名之曰「甲」。
这朴实无华的变量定义无疑不是几千年来中华文化的发展中一朵奇葩。
今天小王同学想,文言文能编程那白话文呢?他找到了你,让你帮帮他。
编程要求
编写一个程序,输入满足以下语法要求的一段文字,输出运行后的结果。
变量定义:整数 钱包 等于 零
运算(加法):钱包 增加 四
运算(减法):钱包 减少 四
输出:看看 钱包
样例
输入:
整数 钱包 等于 零
钱包 增加 四
钱包 减少 三
看看 钱包
输出:
一
思考过程
- 翻译
- 运行
- 变量储存
代码组成
16个函数,4个结构体,1个枚举,6个全局常量,7和宏。
TOKEN枚举
TOKEN枚举用来记录,所有的关键字种类。
typedef enum TOKEN {
VAR,
EQU,
LOOK,
DESC,
ADD,
NUM,
NAME
} TOKEN;
分别有,整数,等于,增加,减少,看看,数字,和变量名字 这7种标识符。
Var类
Var类用于储存变量的名字,其实这个类可以用一个char*代替,这么写因为我这个结构体原来还有点东西,后面被删除了。
typedef struct Var {
char *name;
} Var;
Line类
Line类用于储存一行转化后的token和其他信息。
typedef struct Line {
TOKEN *words;
int num;
char *name;
} Line;
Cell类
Cell类用于储存输入的文字和一个指向正在识别的文字的指针。
typedef struct Cell {
char *str;
int point;
} Cell;
VM类
Vm类用于保存运行环境。
typedef struct VM {
int *memory;
Var *vars;
} VM;
3个初始化函数
VM *init_vm(int max_memory) {
VM *vm = (VM *) malloc(sizeof(VM));
vm->memory = (int *) malloc(max_memory * sizeof(int));
vm->vars = (Var *) malloc(max_memory * sizeof(Var));
memset(vm->memory, 0, max_memory * sizeof(int));
memset(vm->vars, 0, max_memory * sizeof(Var));
return vm;
}
Cell *new_cell(char *str) {
Cell *cell = (Cell *) malloc(sizeof(Cell));
cell->point = 0;
cell->str = str;
return cell;
}
Line *new_line(int max_words) {
Line *line = (Line *) malloc(sizeof(Line));
line->words = (TOKEN *) malloc(max_words * sizeof(TOKEN));
line->name = (char *) malloc(WORD_NAME_LENGTH * sizeof(char));
return line;
}
一个输入工具
int read_line(char *s, int lim) {
int c, i;
i = 0;
while ((c = getchar()) != EOF && c != '
' && i < lim - 1)
s[i++] = (char) c;
s[i] = ' ';
return i;
}
字符串->TOKEN工具
bool eat(Cell *cell, const char *word) {
for (int i = 0; i < strlen(word); ++i) {
if (cell->str[cell->point + i] != word[i]) {
return false;
}
}
cell->point += (int)strlen(word);
return true;
}
void eat_blank(Cell *cell) {
while (eat(cell, (char *) " "));
}
int eat_num(Cell *cell) {
int this_num[3] = {0};
int ret = 0;
int flag = true;
for (int i = 0; i < NUM_LENGTH; i++) {
if (eat(cell, base_num[i])) {
flag = false;
this_num[0] = i;
break;
}
}
for (int i = 0; i < NUM_LENGTH; i++) {
if (eat(cell, base_num[i])) {
flag = false;
this_num[1] = i;
break;
}
}
for (int i = 0; i < NUM_LENGTH; i++) {
if (eat(cell, base_num[i])) {
flag = false;
this_num[2] = i;
break;
}
}
if (this_num[2]==0){
if (this_num[0]==10){
ret = this_num[1]+this_num[0];
}
else if (this_num[1]==0){
ret = this_num[0];
}
}
else if (this_num[2]<10&&this_num[0]<10&&this_num[1]==10){
ret = this_num[2]+this_num[0]*10;
}
return flag ? -1 : ret;
}
char *eat_name(Cell *cell) {
char *this_name = (char *) malloc(WORD_NAME_LENGTH * sizeof(char));
char c;
for (int i = 0; i < WORD_NAME_LENGTH; ++i) {
if ((c = cell->str[cell->point + i]) == ' ') {
this_name[i] = 0;
break;
} else {
this_name[i] = c;
}
}
cell->point += (int)strlen(this_name);
return this_name;
}
字符串->Line
Line *parser(Cell *cell) {
Line *line = new_line(WORD_NUM_LENGTH);
int now = 0;
eat_blank(cell);
while (cell->point < strlen(cell->str) && now < WORD_NUM_LENGTH) {
int this_num = 0;
char *this_name;
if (eat(cell, zs)) {
line->words[now++] = VAR;
} else if (eat(cell, dy)) {
line->words[now++] = EQU;
} else if (eat(cell, js)) {
line->words[now++] = DESC;
} else if (eat(cell, zj)) {
line->words[now++] = ADD;
} else if (eat(cell, kk)) {
line->words[now++] = LOOK;
} else if ((this_num = eat_num(cell)) != -1) {
line->words[now++] = NUM;
line->num = this_num;
} else if (strlen(this_name = eat_name(cell)) != 0) {
line->words[now++] = NAME;
line->name = this_name;
}
eat_blank(cell);
}
return line;
}
输入函数
Line *get_line() {
char *str = (char *) malloc(WORD_NAME_LENGTH * sizeof(char));
int read = read_line(str, WORD_NAME_LENGTH);
return read == 0 ? NULL : parser(new_cell(str));
}
数字转化成字符串
char *int2str(int num) {
char *str = (char *) malloc(NUM_LENGTH * sizeof(char));
int point = 0;
if (num > 10) {
for (int i = 0; i < strlen(base_num[num / 10]); ++i) {
str[point++] = base_num[num / 10][i];
}
for (int i = 0; i < strlen(base_num[10]); ++i) {
str[point++] = base_num[10][i];
}
for (int i = 0; i < strlen(base_num[num % 10]); ++i) {
str[point++] = base_num[num % 10][i];
}
} else if (num == 10) {
for (int i = 0; i < strlen(base_num[num]); ++i) {
str[point++] = base_num[num][i];
}
} else if (num >= 0) {
for (int i = 0; i < strlen(base_num[num]); ++i) {
str[point++] = base_num[num][i];
}
}
str[point] = 0;
return str;
}
运行函数
void run_var(VM *vm, Line *line) {
if (line->words[0] == VAR && line->words[1] == NAME && line->words[2] == EQU && line->words[3] == NUM &&
line->name) {
for (int i = 0; i < VAR_NUM; ++i) {
if (vm->vars[i].name == NULL || strcmp(vm->vars[i].name, line->name) == 0) {
vm->vars[i].name = line->name;
vm->memory[i] = line->num;
break;
}
}
}
}
void run_add(VM *vm, Line *line) {
if (line->words[0] == NAME && line->words[1] == ADD && line->words[2] == NUM && line->name) {
for (int i = 0; i < VAR_NUM; ++i) {
if (vm->vars[i].name != NULL && strcmp(vm->vars[i].name, line->name) == 0) {
vm->memory[i] += line->num;
break;
}
}
}
}
void run_desc(VM *vm, Line *line) {
if (line->words[0] == NAME && line->words[1] == DESC && line->words[2] == NUM && line->name) {
for (int i = 0; i < VAR_NUM; ++i) {
if (vm->vars[i].name != NULL && strcmp(vm->vars[i].name, line->name) == 0) {
vm->memory[i] -= line->num;
break;
}
}
}
}
void run_look(VM *vm, Line *line) {
if (line->words[0] == LOOK && line->words[1] == NAME && line->name) {
for (int i = 0; i < VAR_NUM; ++i) {
if (vm->vars[i].name != NULL && strcmp(vm->vars[i].name, line->name) == 0) {
printf("%s
", int2str(vm->memory[i]));
break;
}
}
}
}
void run_line(VM *vm, Line *line) {
run_var(vm, line);
run_add(vm, line);
run_desc(vm, line);
run_look(vm, line);
}
主函数
int main() {
VM *vm = init_vm(VAR_NUM);
while (true) {
Line *line = get_line();
if (line == NULL) {
break;
} else {
run_line(vm, line);
}
}
return 0;
}
完整代码
#include<stdio.h>
#include<malloc.h>
#include<string.h>
const char *zs = "整数";
const char *dy = "等于";
const char *kk = "看看";
const char *js = "减少";
const char *zj = "增加";
const char *base_num[11] = {"零", "一", "二", "三", "四", "五", "六", "七", "八", "九", "十"};
#define WORD_NAME_LENGTH (64)
#define NUM_LENGTH (11)
#define WORD_NUM_LENGTH (4)
#define VAR_NUM (32)
#define true (1)
#define false (0)
#define bool int
typedef enum TOKEN {
VAR,
EQU,
LOOK,
DESC,
ADD,
NUM,
NAME
} TOKEN;
typedef struct Var {
char *name;
} Var;
typedef struct Line {
TOKEN *words;
int num;
char *name;
} Line;
typedef struct Cell {
char *str;
int point;
} Cell;
typedef struct VM {
int *memory;
Var *vars;
} VM;
VM *init_vm(int max_memory) {
VM *vm = (VM *) malloc(sizeof(VM));
vm->memory = (int *) malloc(max_memory * sizeof(int));
vm->vars = (Var *) malloc(max_memory * sizeof(Var));
memset(vm->memory, 0, max_memory * sizeof(int));
memset(vm->vars, 0, max_memory * sizeof(Var));
return vm;
}
Cell *new_cell(char *str) {
Cell *cell = (Cell *) malloc(sizeof(Cell));
cell->point = 0;
cell->str = str;
return cell;
}
Line *new_line(int max_words) {
Line *line = (Line *) malloc(sizeof(Line));
line->words = (TOKEN *) malloc(max_words * sizeof(TOKEN));
line->name = (char *) malloc(WORD_NAME_LENGTH * sizeof(char));
return line;
}
int read_line(char *s, int lim) {
int c, i;
i = 0;
while ((c = getchar()) != EOF && c != '
' && i < lim - 1)
s[i++] = (char) c;
s[i] = ' ';
return i;
}
bool eat(Cell *cell, const char *word) {
for (int i = 0; i < strlen(word); ++i) {
if (cell->str[cell->point + i] != word[i]) {
return false;
}
}
cell->point += (int)strlen(word);
return true;
}
void eat_blank(Cell *cell) {
while (eat(cell, (char *) " "));
}
int eat_num(Cell *cell) {
int this_num[3] = {0};
int ret = 0;
int flag = true;
for (int i = 0; i < NUM_LENGTH; i++) {
if (eat(cell, base_num[i])) {
flag = false;
this_num[0] = i;
break;
}
}
for (int i = 0; i < NUM_LENGTH; i++) {
if (eat(cell, base_num[i])) {
flag = false;
this_num[1] = i;
break;
}
}
for (int i = 0; i < NUM_LENGTH; i++) {
if (eat(cell, base_num[i])) {
flag = false;
this_num[2] = i;
break;
}
}
if (this_num[2]==0){
if (this_num[0]==10){
ret = this_num[1]+this_num[0];
}
else if (this_num[1]==0){
ret = this_num[0];
}
}
else if (this_num[2]<10&&this_num[0]<10&&this_num[1]==10){
ret = this_num[2]+this_num[0]*10;
}
return flag ? -1 : ret;
}
char *eat_name(Cell *cell) {
char *this_name = (char *) malloc(WORD_NAME_LENGTH * sizeof(char));
char c;
for (int i = 0; i < WORD_NAME_LENGTH; ++i) {
if ((c = cell->str[cell->point + i]) == ' ') {
this_name[i] = 0;
break;
} else {
this_name[i] = c;
}
}
cell->point += (int)strlen(this_name);
return this_name;
}
Line *parser(Cell *cell) {
Line *line = new_line(WORD_NUM_LENGTH);
int now = 0;
eat_blank(cell);
while (cell->point < strlen(cell->str) && now < WORD_NUM_LENGTH) {
int this_num = 0;
char *this_name;
if (eat(cell, zs)) {
line->words[now++] = VAR;
} else if (eat(cell, dy)) {
line->words[now++] = EQU;
} else if (eat(cell, js)) {
line->words[now++] = DESC;
} else if (eat(cell, zj)) {
line->words[now++] = ADD;
} else if (eat(cell, kk)) {
line->words[now++] = LOOK;
} else if ((this_num = eat_num(cell)) != -1) {
line->words[now++] = NUM;
line->num = this_num;
} else if (strlen(this_name = eat_name(cell)) != 0) {
line->words[now++] = NAME;
line->name = this_name;
}
eat_blank(cell);
}
return line;
}
Line *get_line() {
char *str = (char *) malloc(WORD_NAME_LENGTH * sizeof(char));
int read = read_line(str, WORD_NAME_LENGTH);
return read == 0 ? NULL : parser(new_cell(str));
}
char *int2str(int num) {
char *str = (char *) malloc(NUM_LENGTH * sizeof(char));
int point = 0;
if (num > 10) {
for (int i = 0; i < strlen(base_num[num / 10]); ++i) {
str[point++] = base_num[num / 10][i];
}
for (int i = 0; i < strlen(base_num[10]); ++i) {
str[point++] = base_num[10][i];
}
for (int i = 0; i < strlen(base_num[num % 10]); ++i) {
str[point++] = base_num[num % 10][i];
}
} else if (num == 10) {
for (int i = 0; i < strlen(base_num[num]); ++i) {
str[point++] = base_num[num][i];
}
} else if (num >= 0) {
for (int i = 0; i < strlen(base_num[num]); ++i) {
str[point++] = base_num[num][i];
}
}
str[point] = 0;
return str;
}
void run_var(VM *vm, Line *line) {
if (line->words[0] == VAR && line->words[1] == NAME && line->words[2] == EQU && line->words[3] == NUM &&
line->name) {
for (int i = 0; i < VAR_NUM; ++i) {
if (vm->vars[i].name == NULL || strcmp(vm->vars[i].name, line->name) == 0) {
vm->vars[i].name = line->name;
vm->memory[i] = line->num;
break;
}
}
}
}
void run_add(VM *vm, Line *line) {
if (line->words[0] == NAME && line->words[1] == ADD && line->words[2] == NUM && line->name) {
for (int i = 0; i < VAR_NUM; ++i) {
if (vm->vars[i].name != NULL && strcmp(vm->vars[i].name, line->name) == 0) {
vm->memory[i] += line->num;
break;
}
}
}
}
void run_desc(VM *vm, Line *line) {
if (line->words[0] == NAME && line->words[1] == DESC && line->words[2] == NUM && line->name) {
for (int i = 0; i < VAR_NUM; ++i) {
if (vm->vars[i].name != NULL && strcmp(vm->vars[i].name, line->name) == 0) {
vm->memory[i] -= line->num;
break;
}
}
}
}
void run_look(VM *vm, Line *line) {
if (line->words[0] == LOOK && line->words[1] == NAME && line->name) {
for (int i = 0; i < VAR_NUM; ++i) {
if (vm->vars[i].name != NULL && strcmp(vm->vars[i].name, line->name) == 0) {
printf("%s
", int2str(vm->memory[i]));
break;
}
}
}
}
void run_line(VM *vm, Line *line) {
run_var(vm, line);
run_add(vm, line);
run_desc(vm, line);
run_look(vm, line);
}
int main() {
VM *vm = init_vm(VAR_NUM);
while (true) {
Line *line = get_line();
if (line == NULL) {
break;
} else {
run_line(vm, line);
}
}
return 0;
}