SongZihuan 5 anni fa
commit
ea292d02f4
14 ha cambiato i file con 464 aggiunte e 0 eliminazioni
  1. 18 0
      .vscode/c_cpp_properties.json
  2. 29 0
      .vscode/launch.json
  3. 13 0
      .vscode/settings.json
  4. 19 0
      .vscode/tasks.json
  5. 2 0
      README.md
  6. 5 0
      exception.h
  7. BIN
      lex
  8. 162 0
      lex.c
  9. BIN
      test
  10. 30 0
      test.c
  11. BIN
      token
  12. 27 0
      token.h
  13. BIN
      yacc
  14. 159 0
      yacc.c

+ 18 - 0
.vscode/c_cpp_properties.json

@@ -0,0 +1,18 @@
+{
+    "configurations": [
+        {
+            "name": "Linux",
+            "includePath": [
+                "${workspaceFolder}/**",
+                "/usr/include/linux",
+                "/usr/include/c++/9.3.0/tr1"
+            ],
+            "defines": [],
+            "compilerPath": "/usr/bin/gcc",
+            "cStandard": "c11",
+            "cppStandard": "c++17",
+            "intelliSenseMode": "gcc-x64"
+        }
+    ],
+    "version": 4
+}

+ 29 - 0
.vscode/launch.json

@@ -0,0 +1,29 @@
+{
+    // 使用 IntelliSense 了解相关属性。 
+    // 悬停以查看现有属性的描述。
+    // 欲了解更多信息,请访问: https://go.microsoft.com/fwlink/?linkid=830387
+    "version": "0.2.0",
+    "configurations": [
+        {
+            "name": "gcc - 生成和调试活动文件",
+            "type": "cppdbg",
+            "request": "launch",
+            "program": "${fileDirname}/${fileBasenameNoExtension}",
+            "args": [],
+            "stopAtEntry": false,
+            "cwd": "${workspaceFolder}",
+            "environment": [],
+            "externalConsole": false,
+            "MIMode": "gdb",
+            "setupCommands": [
+                {
+                    "description": "为 gdb 启用整齐打印",
+                    "text": "-enable-pretty-printing",
+                    "ignoreFailures": true
+                }
+            ],
+            "preLaunchTask": "gcc build active file",
+            "miDebuggerPath": "/usr/bin/gdb"
+        }
+    ]
+}

+ 13 - 0
.vscode/settings.json

@@ -0,0 +1,13 @@
+{
+    "files.associations": {
+        "inttypes.h": "c",
+        "cstdio": "c",
+        "sstream": "c",
+        "cstdlib": "c",
+        "exception.h": "c",
+        "token.h": "c",
+        "setjmp.h": "c",
+        "fstream": "c",
+        "string.h": "c"
+    }
+}

+ 19 - 0
.vscode/tasks.json

@@ -0,0 +1,19 @@
+{
+    "tasks": [
+        {
+            "type": "shell",
+            "label": "gcc build active file",
+            "command": "/usr/bin/gcc",
+            "args": [
+                "-g",
+                "${file}",
+                "-o",
+                "${fileDirname}/${fileBasenameNoExtension}"
+            ],
+            "options": {
+                "cwd": "/usr/bin"
+            }
+        }
+    ],
+    "version": "2.0.0"
+}

+ 2 - 0
README.md

@@ -0,0 +1,2 @@
+# 基于C的计算器
+```手动实现语法分析器和词法分析器```

+ 5 - 0
exception.h

@@ -0,0 +1,5 @@
+#include<setjmp.h>
+#define try if(setjmp(env) == 0)  
+#define except else  
+#define raise longjmp(env,1)
+jmp_buf env;

BIN
lex


+ 162 - 0
lex.c

@@ -0,0 +1,162 @@
+#include<stdio.h>
+#include<string.h>
+#include"token.h"
+#include <ctype.h>
+#define debug 0
+
+#define is_NUM 1
+#define no_NUM 0
+#define is_STOP 2
+
+FILE *fp = NULL;
+
+typedef enum NUM_TYPE{
+    START=0,
+    INT=1,
+    DOT=2,
+    DOUBLE=3,
+} NUM_TYPE;
+
+Token token;
+char str=' ';
+
+int get_char_back = 0;
+
+void get_char(){
+    if (get_char_back){  // 回退
+        get_char_back = 0;
+    }
+    else{
+        str = fgetc(fp);
+    }
+}
+
+void unget_char(){
+    get_char_back = 1;
+}
+
+void exit(int);
+// int isdigit(char);
+double atof(char *);
+
+void get_token(Token *token){
+    static int is_number = no_NUM;
+    token->type = NULL_TOKEN;
+    memset(token->str,0,sizeof(MAX_TOKEN_WIDTH));
+    token->NUMBER = 0;
+    NUM_TYPE num_type = START;  // 数字输入默认情况
+
+    for (int num=0;;num += 1)
+    {
+        get_char();  // 取得一个输入的字符
+        token->str[num] = str;
+        if ((num_type == INT)&&(str == '.')){  // 小数点
+            if (num_type == INT){
+                num_type++;
+                continue;
+            }
+        }
+        else if ((num_type == DOT)&&(isdigit(str))){  // 小数点到小数
+            num_type++;
+            continue;
+            }
+        if (num_type != START){
+            if (isdigit(str)){  // 整数或者小数
+                continue;
+            }
+            else{
+                token->str[num] = '\0';
+                is_number = is_NUM;
+                unget_char();
+                token->NUMBER = atof(token->str);
+                return ;
+            }
+        }
+
+        if (str == ' '){
+            token->str[num] = '\0';
+            num -= 1;  //num要减少一位,否则就会空出来 
+            continue;
+        }
+        else if ((num_type == START)&&(isdigit(str))){  // 开始写入数字
+            token->type=NUM;  // 数字模式
+            num_type++;
+            continue;
+        }
+        else if (str == '+'){
+            token->type=ADD;
+            is_number = no_NUM;
+            return;
+        }
+        else if (str == '-'){
+            if (is_number != is_NUM){  // 上一个不是数字,这个是负数
+                token->type=NUM;  // 数字模式
+                num_type++;
+                continue;
+            }
+            else{
+                token->type=SUB;
+                is_number = no_NUM;
+                return;
+            }
+        }
+        else if (str == '*'){
+            token->type=MUL;
+            is_number = no_NUM;
+            return;
+        }
+        else if (str == '/'){
+            token->type=DIV;
+            is_number = no_NUM;
+            return;
+        }
+        else if (str == '('){
+            token->type=LB;
+            is_number = no_NUM;
+            return;
+        }
+        else if (str == ')'){
+            token->type=RB;
+            is_number = no_NUM;
+            return;
+        }
+        else if ((str == '\n')|| (str == ';')){  // 停止
+            if (is_number == is_STOP){
+                token->type=NULL_TOKEN;
+                return;
+            }
+            token->type=STOP;
+            token->str[0] = ' ';
+            is_number = is_STOP;
+            return;
+        }
+        else if (str = '\\'){  // 多行
+            token->type=NULL_TOKEN;
+            token->str[0] = ' ';
+            is_number = is_STOP;
+            return;
+        }
+        else{  // 停止
+            token->type=EXIT;
+            token->str[0] = ' ';
+            is_number = no_NUM;
+            return;
+        }
+    }
+    
+}
+
+// #ifdef 0
+// void debug_get_token(){
+//     get_token(&token);
+//     printf("type = %d, str = %s, NUMBER = %f\n", token.type, token.str, token.NUMBER);
+// }
+
+// int main(){
+//     fp = stdin;
+//     while(1){
+//     debug_get_token();
+//     }
+//     return 0;
+// }
+// #endif

BIN
test


+ 30 - 0
test.c

@@ -0,0 +1,30 @@
+#include<stdio.h>
+#include<setjmp.h>
+#define try if(setjmp(env) == 0)  
+#define except else  
+#define raise() longjmp(env,1)
+jmp_buf env;
+
+void fuck(){
+    raise();
+}
+
+int main(int argc,char *argv[]){
+    FILE *fe;
+    // /home/songzihuan/test
+    if (argc == 2){
+        printf(argv[1]);
+        FILE *fp = fopen(argv[1], "r");
+        atexit(&close);
+    }
+    else{
+        fp = stdin;
+    }
+    fe= fopen(argv[1], "r");
+    char a;
+    a = fgetc(fe);
+    putchar(a);
+    fclose(fe);
+
+    return 0;
+}

BIN
token


+ 27 - 0
token.h

@@ -0,0 +1,27 @@
+#include<stdio.h>
+#define MAX_TOKEN_WIDTH 16
+
+// token的类型
+typedef enum
+{
+    NULL_TOKEN,
+    NUM,
+    ADD,
+    SUB,
+    MUL,
+    DIV,
+    END,
+    LB,  // 括号:brackets,LB是左(left)括号
+    RB,  // 右(right)括号
+    STOP,
+    EXIT,
+} token_type;
+
+
+typedef struct
+{
+    token_type type;
+    double NUMBER;
+    char str[MAX_TOKEN_WIDTH];
+} Token;
+

BIN
yacc


+ 159 - 0
yacc.c

@@ -0,0 +1,159 @@
+#include <stdio.h>
+#include"lex.c"
+#include<setjmp.h>
+
+// Token old_token;
+int need_TOOKEN = 1;
+int jup_number = 0;
+
+void safe_get_token(Token *token){
+    if (need_TOOKEN){
+        while (1)
+        {
+            get_token(token);
+            if (token->type != NULL_TOKEN){  // 忽略空语句
+                break;
+            }
+        }
+    }
+    else{
+        need_TOOKEN = 1;
+    }
+}
+
+void unget_token(){
+    need_TOOKEN = 0;
+}
+
+double base(int jmp, jmp_buf *self_env){
+    double polynomial();  // 声明
+
+    safe_get_token(&token);
+    if (token.type == NUM){
+        return token.NUMBER;
+    }
+    else if (token.type == LB){  // 遇到括号
+        double value = polynomial();
+        safe_get_token(&token);
+        if (token.type = RB){  // 右括号
+            return value;
+        }
+        longjmp(*self_env, jmp);
+    }
+    else{
+        longjmp(*self_env, jmp);
+    }
+}
+
+double term(int jmp, jmp_buf *self_env){
+    jmp_buf env;
+    jup_number = setjmp(env);
+    if (jup_number == 1){
+        unget_token();
+        goto returnZero;
+    }
+    else if (jup_number == 2){
+        unget_token();
+        goto returnV1;
+    }
+
+    double v1 = base(1, &env);
+    while (1){
+        safe_get_token(&token);
+        if (token.type == MUL){
+            double v2 = base(2, &env);
+            v1 *= v2;
+        }
+        else if (token.type == DIV){
+            double v2 = base(2, &env);
+            v1 /= v2;
+        }
+        else{
+            unget_token();
+            break;
+        }
+    }
+    returnV1:return v1;
+
+    returnZero:longjmp(*self_env, jmp);
+}
+
+double polynomial(int jmp, jmp_buf *self_env){
+    jmp_buf env;
+    jup_number = setjmp(env);
+    if (jup_number == 1){
+        unget_token();
+        goto returnZero;
+    }
+    else if (jup_number == 2){
+        unget_token();
+        goto returnV1;
+    }
+
+    double v1 = term(1, &env);
+    while (1){
+        safe_get_token(&token);
+        if (token.type == ADD){
+            double v2 = term(2, &env);
+            v1 += v2;
+        }
+        else if (token.type == SUB){
+            double v2 = term(2, &env);
+            v1 -= v2;
+        }
+        else{
+            unget_token();
+            break;
+        }
+    }
+    returnV1:return v1;
+
+    returnZero:longjmp(*self_env, jmp);
+}
+
+double expression(){  // 收集STOP的
+    jmp_buf env;
+    jup_number = setjmp(env);
+    if (jup_number == 1){
+        safe_get_token(&token);
+        if (token.type == EXIT){
+            puts("Bye bye!");
+            exit(1);
+        }
+        return 0;
+    }
+
+    double v1 = polynomial(1, &env);
+
+    safe_get_token(&token);
+    if ((token.type != STOP) && (token.type != EXIT)){
+        unget_token();
+        }
+    return v1;
+}
+
+void show_answer(){
+    while (token.type != EXIT){
+        printf("answer = %f\n", expression());
+    }
+}
+
+void close(){
+    fclose(fp);
+}
+
+int main(int argc,char *argv[]){
+    int atexit (void (*function) (void));
+
+    if (argc == 2){
+        printf("from %s >>>\n", argv[1]);
+        fp = fopen(argv[1], "r");
+        atexit(&close);
+    }
+    else{
+        fp = stdin;
+        fflush(fp);
+    }
+    show_answer();
+    return 0;
+}