題目
中國文化博大精深,從倉頡造字開始,漢字一直流傳到了今天。我們在感嘆漢字的源遠流長時,也不禁感慨,為什么沒有一門使用漢字編程的語言?
漢字真的不能編程嗎?最近文言文編程火了一把,吾有一數。曰三。名之曰「甲」。
這朴實無華的變量定義無疑不是幾千年來中華文化的發展中一朵奇葩。
今天小王同學想,文言文能編程那白話文呢?他找到了你,讓你幫幫他。
編程要求
編寫一個程序,輸入滿足以下語法要求的一段文字,輸出運行后的結果。
變量定義:整數 錢包 等於 零
運算(加法):錢包 增加 四
運算(減法):錢包 減少 四
輸出:看看 錢包
樣例
輸入:
整數 錢包 等於 零
錢包 增加 四
錢包 減少 三
看看 錢包
輸出:
一
思考過程
- 翻譯
- 運行
- 變量儲存
代碼組成
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 != '\n' && i < lim - 1)
s[i++] = (char) c;
s[i] = '\0';
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\n", 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 != '\n' && i < lim - 1)
s[i++] = (char) c;
s[i] = '\0';
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\n", 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;
}