关键词搜索

源码搜索 ×
×

用 C 语言开发一门编程语言 — 引用表达式解析器

发布2023-03-14浏览1957次

详情内容

目录

前言

通过开发一门类 Lisp 的编程语言来理解编程语言的设计思想,本实践来自著名的《Build Your Own Lisp》。

  • 代码实现:https://github.com/JmilkFan/Lispy

前文列表

用 C 语言开发一门编程语言 — 交互式解析器l
用 C 语言开发一门编程语言 — 语法解析器运行原理
用 C 语言开发一门编程语言 — 波兰表达式解析器
用 C 语言开发一门编程语言 — 表达式存储器
用 C 语言开发一门编程语言 — 符号表达式解析器

引用表达式

前面实现的符号表达式解析器,使得 Lispy 可以从解析并以树型结构的形式来存储用户输入的 Symbols(符号)。

接下来,我们继续实现引用表达式(Quoted Expression,Q-Expression),用于为某些 Symbols 赋予特殊的含义,使其可以成为一个变量、一个关键字、甚至是一个函数。

引用表达式解析器

Q-Expression 语法解析实现

Q-Expression 的语法和 S-Expression 非常相似,唯一的不同是 Q-Expression 被包裹在大括号 {} 中,而 S-Expression 包裹在小括号 () 中,Q-Expression 的语法规则如下:

mpc_parser_t* Number = mpc_new("number");
mpc_parser_t* Symbol = mpc_new("symbol");
mpc_parser_t* Sexpr  = mpc_new("sexpr");
mpc_parser_t* Qexpr  = mpc_new("qexpr");
mpc_parser_t* Expr   = mpc_new("expr");
mpc_parser_t* Lispy  = mpc_new("lispy");

mpca_lang(MPCA_LANG_DEFAULT,
  "                                                    \
    number : /-?[0-9]+/ ;                              \
    symbol : '+' | '-' | '*' | '/' ;                   \
    sexpr  : '(' <expr>* ')' ;                         \
    qexpr  : '{' <expr>* '}' ;                         \
    expr   : <number> | <symbol> | <sexpr> | <qexpr> ; \
    lispy  : /^/ <expr>* /$/ ;                         \
  ",
  Number, Symbol, Sexpr, Qexpr, Expr, Lispy);

mpc_cleanup(6, Number, Symbol, Sexpr, Qexpr, Expr, Lispy);

    Q-Expression 存储器实现

    由于 Q-Expression 和 S-Expression 的形式基本一致,所以它们内部实现也大致是相同的。

    首先,添加表示 Q-Expression 的新类型:

    enum { LVAL_ERR, LVAL_NUM, LVAL_SYM, LVAL_SEXPR, LVAL_QEXPR };
    
    • 1

    然后,添加一个构造函数:

    /* A pointer to a new empty Qexpr lval */
    lval* lval_qexpr(void) {
      lval* v = malloc(sizeof(lval));
      v->type = LVAL_QEXPR;
      v->count = 0;
      v->cell = NULL;
      return v;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8

    继续改造析构函数和打印函数:

    void lval_del(lval* v) {
    
      switch (v->type) {
        case LVAL_NUM: break;
        case LVAL_ERR: free(v->err); break;
        case LVAL_SYM: free(v->sym); break;
    
        /* If Qexpr or Sexpr then delete all elements inside */
        case LVAL_QEXPR:
        case LVAL_SEXPR:
          for (int i = 0; i < v->count; i++) {
            lval_del(v->cell[i]);
          }
          /* Also free the memory allocated to contain the pointers */
          free(v->cell);
        break;
      }
    
      free(v);
    }
    
    
    void lval_print(lval* v) {
      switch (v->type) {
        case LVAL_NUM:   printf("%li", v->num); break;
        case LVAL_ERR:   printf("Error: %s", v->err); break;
        case LVAL_SYM:   printf("%s", v->sym); break;
        case LVAL_SEXPR: lval_expr_print(v, '(', ')'); break;
        case LVAL_QEXPR: lval_expr_print(v, '{', '}'); break;
      }
    }
    
      20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31

    读取并存储 S-Expression

    改造 lval_read 读取函数,使其可以正确读取并存储 Q-Expression AST(抽象语法树):

    if (strstr(t->tag, "qexpr"))  { x = lval_qexpr(); }
    
    • 1

    在 lval_read 中添加一下代码识别花括号:

    if (strcmp(t->children[i]->contents, "(") == 0) { continue; }
    if (strcmp(t->children[i]->contents, ")") == 0) { continue; }
    if (strcmp(t->children[i]->contents, "}") == 0) { continue; }
    if (strcmp(t->children[i]->contents, "{") == 0) { continue; }
    
    • 1
    • 2
    • 3
    • 4

    注意,因为 Q-Expression 没有任何求值方式,所以无需添加求值逻辑。

    实现在 Q-Expression 使用的关键字函数

    在前面,我们实现了对 Q-Expression 输入的读取、解析和存储。后续,我们继续实现 5 个 Q-Expression 函数,为 Q-Expression 提供更多样的操作类型。

    1. Head(取头)函数:接受一个 Q-Expression,返回一个包含其首元素的新 Q-Expression。
    2. Tail(去头取尾)函数:接受一个 Q-Expression,返回一个包含除了首元素之外其他所有元素的新 Q-Expression。
    3. Join(连接)函数:接受若干个 Q-Expression,返回一个将它们连接在一起的新 Q-Expression。
    4. List(列表)函数:用于接收若干个 S-Expression,返回一个包含了所有参数的新 Q-Expression。
    5. Eval(运算)函数:接受一个 Q-Expression,将其看做一个 S-Expression,并执行运算处理。

    如同我们前面加的数学运算符一样,这些新的操作符也需要加入到 symbol 语法规则中:

    mpca_lang(MPCA_LANG_DEFAULT,
      "                                                        \
        number : /-?[0-9]+/ ;                                  \
        symbol : \"list\" | \"head\" | \"tail\"                \
               | \"join\" | \"eval\" | '+' | '-' | '*' | '/' ; \
        sexpr  : '(' <expr>* ')' ;                             \
        qexpr  : '{' <expr>* '}' ;                             \
        expr   : <number> | <symbol> | <sexpr> | <qexpr> ;     \
        lispy  : /^/ <expr>* /$/ ;                             \
      ",
      Number, Symbol, Sexpr, Qexpr, Expr, Lispy)
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11

    Head 函数

    Head(取头)函数,用于接受一个 Q-Expression,返回一个包含其首元素的 Q-Expression。

    lval* builtin_head(lval* a) {
    
      /* 保证输入的参数只有一个。*/
      if (a->count != 1) {
        lval_del(a);
        return lval_err("Function 'head' passed too many arguments!");
      }
    
      /* 保证输入的类型为 Q-Expression。*/
      if (a->cell[0]->type != LVAL_QEXPR) {
        lval_del(a);
        return lval_err("Function 'head' passed incorrect types!");
      }
    
      /* 保证输入的 Q-Expression 不为空。*/
      if (a->cell[0]->count == 0) {
        lval_del(a);
        return lval_err("Function 'head' passed {}!");
      }
    
      /* Otherwise take first argument */
      lval* v = lval_take(a, 0);
    
      /* 重复执行 pop 和 delete,直到数组为空。 */
      while (v->count > 1) { lval_del(lval_pop(v, 1)); }
      return v;
    }
    
      20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27

    Tail 函数

    Tail(去头取尾)函数,用于接受一个 Q-Expression,返回一个包含除了首元素之外其他所有元素的新 Q-Expression。

    lval* builtin_tail(lval* a) {
      /* Check Error Conditions */
      if (a->count != 1) {
        lval_del(a);
        return lval_err("Function 'tail' passed too many arguments!");
      }
    
      if (a->cell[0]->type != LVAL_QEXPR) {
        lval_del(a);
        return lval_err("Function 'tail' passed incorrect types!");
      }
    
      if (a->cell[0]->count == 0) {
        lval_del(a);
        return lval_err("Function 'tail' passed {}!");
      }
    
      /* Take first argument */
      lval* v = lval_take(a, 0);
    
      /* 只需要 pop 并 delete 第一个数组元素,剩余元素组成的数组则为我们所需要的。*/
      lval_del(lval_pop(v, 0));
      return v;
    }
    
      20
    • 21
    • 22
    • 23
    • 24

    使用宏来优化实现

    虽然上述实现的 head 和 tail 函数能够实现我们所需要的功能,但是代码难懂且长。有大段的代码是进行错误处理,使得真正逻辑的实现部分不那么明显。要解决这个问题,我们可以使用 C 语言的宏函数来实现断言(Assert)功能。

    宏函数取名为 l-assert(Lispy Assert)具有 3 个参数:

    1. args(待清理对象参数)
    2. cond(条件判断参数)
    3. err(错误参数)
    #define LASSERT(args, cond, err) \
      if (!(cond)) { lval_del(args); return lval_err(err); }
    
    • 1
    • 2

    如此的,我们就可以通过宏函数来生成真正的函数代码了。

    lval* builtin_head(lval* a) {
      LASSERT(a, a->count == 1,
        "Function 'head' passed too many arguments!");
      LASSERT(a, a->cell[0]->type == LVAL_QEXPR,
        "Function 'head' passed incorrect type!");
      LASSERT(a, a->cell[0]->count != 0,
        "Function 'head' passed {}!");
    
      lval* v = lval_take(a, 0);
      while (v->count > 1) { lval_del(lval_pop(v, 1)); }
      return v;
    }
    
    lval* builtin_tail(lval* a) {
      LASSERT(a, a->count == 1,
        "Function 'tail' passed too many arguments!");
      LASSERT(a, a->cell[0]->type == LVAL_QEXPR,
        "Function 'tail' passed incorrect type!");
      LASSERT(a, a->cell[0]->count != 0,
        "Function 'tail' passed {}!");
    
      lval* v = lval_take(a, 0);
      lval_del(lval_pop(v, 0));
      return v;
    }
    
      20
    • 21
    • 22
    • 23
    • 24
    • 25

    Join 函数

    Join(连接)函数,用于接受若干个 Q-Expression,返回一个将它们连接在一起的新 Q-Expression。

    /**
     * lval_join 函数
     * 将 y 中元素依次弹出,并添加进 x 中,将它们拼接起来,然后将 y 删除,返回 x。
     */
    lval* lval_join(lval* x, lval* y) {
    
      /* For each cell in 'y' add it to 'x' */
      while (y->count) {
        x = lval_add(x, lval_pop(y, 0));
      }
    
      /* Delete the empty 'y' and return 'x' */
      lval_del(y);
      return x;
    }
    
    lval* builtin_join(lval* a) {
    
      /* 首先确保所有的参数都是 Q-Expression。*/
      for (int i = 0; i < a->count; i++) {
        LASSERT(a, a->cell[i]->type == LVAL_QEXPR,
          "Function 'join' passed incorrect type.");
      }
    
      lval* x = lval_pop(a, 0);
    
      while (a->count) {
        x = lval_join(x, lval_pop(a, 0));
      }
    
      lval_del(a);
      return x;
    }
    
      20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33

    List 函数

    List(列表)函数,用于接收若干个 S-Expression,返回一个包含了所有参数的新 Q-Expression。

    lval* builtin_list(lval* a) {
      a->type = LVAL_QEXPR;
      return a;
    }
    
    • 1
    • 2
    • 3
    • 4

    Eval函数

    Eval(运算)函数,用于接受一个 Q-Expression,将其看做一个 S-Expression,并使用 lval_eval 函执行运算处理。

    lval* builtin_eval(lval* a) {
      LASSERT(a, a->count == 1,
        "Function 'eval' passed too many arguments!");
      LASSERT(a, a->cell[0]->type == LVAL_QEXPR,
        "Function 'eval' passed incorrect type!");
    
      lval* x = lval_take(a, 0);
      x->type = LVAL_SEXPR;
      return lval_eval(x);
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10

    函数路由器实现

    最后,还需要一个函数路由器,用于根据提供的 “函数别名“ 来调用相应的真实函数。

    lval* builtin(lval* a, char* func) {
      if (strcmp("list", func) == 0) { return builtin_list(a); }
      if (strcmp("head", func) == 0) { return builtin_head(a); }
      if (strcmp("tail", func) == 0) { return builtin_tail(a); }
      if (strcmp("join", func) == 0) { return builtin_join(a); }
      if (strcmp("eval", func) == 0) { return builtin_eval(a); }
      if (strstr("+-/*", func)) { return builtin_op(a, func); }
      lval_del(a);
      return lval_err("Unknown Function!");
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10

    同时修改早先 lval_eval_sexpr 函数来调用新的 buildin:

    /* Call builtin with operator */
    lval* result = builtin(v, f->sym);
    lval_del(f);
    return result;
    
    • 1
    • 2
    • 3
    • 4

    源代码

    #include <stdio.h>
    #include <stdlib.h>
    #include "mpc.h"
    
    #define LASSERT(args, cond, err) \
        if (!(cond)) { lval_del(args); return lval_err(err); }
    
    #ifdef _WIN32
    #include <string.h>
    
    static char buffer[2048];
    
    char *readline(char *prompt) {
        fputs(prompt, stdout);
        fgets(buffer, 2048, stdin);
    
        char *cpy = malloc(strlen(buffer) + 1);
    
        strcpy(cpy, buffer);
        cpy[strlen(cpy) - 1] = '\0';
    
        return cpy;
    }
    
    void add_history(char *unused) {}
    
    #else
    
    #ifdef __linux__
    #include <readline/readline.h>
    #include <readline/history.h>
    #endif
    
    #ifdef __MACH__
    #include <readline/readline.h>
    #endif
    
    #endif
    
    /* Create Enumeration of Possible lval Types */
    enum {
        LVAL_NUM,
        LVAL_ERR,
        LVAL_SYM,
        LVAL_SEXPR,
        LVAL_QEXPR
    };
    
    /* Declare New lval Struct */
    typedef struct lval {
        int type;
        long num;
    
        /* Count and Pointer to a list of "lval*" */
        struct lval** cell;
        int count;
    
        /* Error and Symbol types have some string data */
        char *err;
        char *sym;
    } lval;
    
    /* Construct a pointer to a new Number lval */
    lval *lval_num(long x) {
        lval *v = malloc(sizeof(lval));
        v->type = LVAL_NUM;
        v->num = x;
        return v;
    }
    
    /* Construct a pointer to a new Error lval */
    lval *lval_err(char *msg) {
        lval *v = malloc(sizeof(lval));
        v->type = LVAL_ERR;
        v->err = malloc(strlen(msg) + 1);
        strcpy(v->err, msg);
        return v;
    }
    
    /* Construct a pointer to a new Symbol lval */
    lval *lval_sym(char *sym) {
        lval *v = malloc(sizeof(lval));
        v->type = LVAL_SYM;
        v->sym = malloc(strlen(sym) + 1);
        strcpy(v->sym, sym);
        return v;
    }
    
    /* A pointer to a new empty Sexpr lval */
    lval *lval_sexpr(void) {
        lval *v = malloc(sizeof(lval));
        v->type = LVAL_SEXPR;
        v->count = 0;
        v->cell = NULL;
        return v;
    }
    
    /* A pointer to a new empty Qexpr lval */
    lval *lval_qexpr(void) {
        lval *v = malloc(sizeof(lval));
        v->type = LVAL_QEXPR;
        v->count = 0;
        v->cell = NULL;
        return v;
    }
    
    
    void lval_del(lval *v) {
        switch (v->type) {
            /* Do nothing special for number type */
            case LVAL_NUM:
                break;
    
            /* For Err or Sym free the string data */
            case LVAL_ERR:
                free(v->err);
                break;
            case LVAL_SYM:
                free(v->sym);
                break;
    
            /* If Qexpr or Sexpr then delete all elements inside */
            case LVAL_QEXPR:
            case LVAL_SEXPR:
                for (int i = 0; i < v->count; i++) {
                    lval_del(v->cell[i]);
                }
                /* Also free the memory allocated to contain the pointers */
                free(v->cell);
                break;
        }
        /* Free the memory allocated for the "lval" struct itself */
        free(v);
    }
    
    lval *lval_add(lval *v, lval *x) {
        v->count++;
        v->cell = realloc(v->cell, sizeof(lval*) * v->count);
        v->cell[v->count-1] = x;
        return v;
    }
    
    lval *lval_read_num(mpc_ast_t *t) {
        errno = 0;
        long x = strtol(t->contents, NULL, 10);
        return errno != ERANGE
            ? lval_num(x)
            : lval_err("invalid number");
    }
    
    lval *lval_read(mpc_ast_t *t) {
         /* If Symbol or Number return conversion to that type */
        if (strstr(t->tag, "number")) {
            return lval_read_num(t);
        }
        if (strstr(t->tag, "symbol")) {
            return lval_sym(t->contents);
        }
    
        /* If root (>) or sexpr then create empty list */
        lval *x = NULL;
        if (strcmp(t->tag, ">") == 0) {
            x = lval_sexpr();
        }
        if (strstr(t->tag, "sexpr"))  {
            x = lval_sexpr();
        }
        if (strstr(t->tag, "qexpr")) {
            x = lval_qexpr();
        }
    
        /* Fill this list with any valid expression contained within */
        for (int i = 0; i < t->children_num; i++) {
            if (strcmp(t->children[i]->contents, "(") == 0) { continue; }
            if (strcmp(t->children[i]->contents, ")") == 0) { continue; }
            if (strcmp(t->children[i]->contents, "}") == 0) { continue; }
            if (strcmp(t->children[i]->contents, "{") == 0) { continue; }
            if (strcmp(t->children[i]->tag,  "regex") == 0) { continue; }
            x = lval_add(x, lval_read(t->children[i]));
        }
        return x;
    }
    
    void lval_print(lval *v);
    
    void lval_expr_print(lval *v, char open, char close) {
        putchar(open);
        for (int i = 0; i < v->count; i++) {
    
            /* Print Value contained within */
            lval_print(v->cell[i]);
    
            /* Don't print trailing space if last element */
            if (i != (v->count-1)) {
                putchar(' ');
            }
        }
        putchar(close);
    
    }
    
    /* Print an "lval*" */
    void lval_print(lval *v) {
        switch (v->type) {
            case LVAL_NUM:   printf("%li", v->num); break;
            case LVAL_ERR:   printf("Error: %s", v->err); break;
            case LVAL_SYM:   printf("%s", v->sym); break;
            case LVAL_SEXPR: lval_expr_print(v, '(', ')'); break;
            case LVAL_QEXPR: lval_expr_print(v, '{', '}'); break;
        }
    }
    
    /* Print an "lval" followed by a newline */
    void lval_println(lval *v) {
        lval_print(v);
        putchar('\n');
    }
    
    lval *lval_pop(lval *v, int i) {
    
        /* Find the item at "i" */
        lval *x = v->cell[i];
    
        /* Shift memory after the item at "i" over the top */
        memmove(&v->cell[i], &v->cell[i+1],
                sizeof(lval*) * (v->count-i-1));
    
        /* Decrease the count of items in the list */
        v->count--;
    
        /* Reallocate the memory used */
        v->cell = realloc(v->cell, sizeof(lval*) * v->count);
        return x;
    }
    
    lval *lval_take(lval *v, int i) {
        lval *x = lval_pop(v, i);
        lval_del(v);
        return x;
    }
    
    lval *builtin_op(lval *a, char *op) {
    
        /* Ensure all arguments are numbers */
        for (int i = 0; i < a->count; i++) {
            if (a->cell[i]->type != LVAL_NUM) {
                lval_del(a);
                return lval_err("Cannot operate on non-number!");
            }
        }
    
        /* Pop the first element */
        lval *x = lval_pop(a, 0);
    
        /* If no arguments and sub then perform unary negation */
        if ((strcmp(op, "-") == 0) && a->count == 0) {
            x->num = -x->num;
        }
    
        /* While there are still elements remaining */
        while (a->count > 0) {
            /* Pop the next element */
            lval *y = lval_pop(a, 0);
    
            if (strcmp(op, "+") == 0) { x->num += y->num; }
            if (strcmp(op, "-") == 0) { x->num -= y->num; }
            if (strcmp(op, "*") == 0) { x->num *= y->num; }
            if (strcmp(op, "/") == 0) {
                if (y->num == 0) {
                    lval_del(x);
                    lval_del(y);
                    x = lval_err("Division By Zero!");
                    break;
                }
                x->num /= y->num;
            }
            lval_del(y);
        }
        lval_del(a);
        return x;
    }
    
    lval *lval_eval(lval *v);
    lval *builtin(lval* a, char* func);
    
    lval *lval_eval_sexpr(lval *v) {
        /* Evaluate Children */
        for (int i = 0; i < v->count; i++) {
            v->cell[i] = lval_eval(v->cell[i]);
        }
    
        /* Error Checking */
        for (int i = 0; i < v->count; i++) {
            if (v->cell[i]->type == LVAL_ERR) {
                return lval_take(v, i);
            }
        }
    
        /* Empty Expression */
        if (v->count == 0) { return v; }
    
        /* Single Expression */
        if (v->count == 1) { return lval_take(v, 0); }
    
        /* Ensure First Element is Symbol */
        lval *f = lval_pop(v, 0);
    
        if (f->type != LVAL_SYM) {
            lval_del(f);
            lval_del(v);
    
            return lval_err("S-expression Does not start with symbol!");
        }
    
         /* Call builtin with operator */
        lval *result = builtin(v, f->sym);
        lval_del(f);
        return result;
    }
    
    lval *lval_eval(lval *v) {
        /* Evaluate Sexpressions */
        if (v->type == LVAL_SEXPR) {
            return lval_eval_sexpr(v);
        }
    
        /* All other lval types remain the same */
        return v;
    }
    
    lval *builtin_head(lval *a) {
        LASSERT(a, a->count == 1,
                "Function 'head' passed too many arguments!");
        LASSERT(a, a->cell[0]->type == LVAL_QEXPR,
                "Function 'head' passed incorrect type!");
        LASSERT(a, a->cell[0]->count != 0,
                "Function 'head' passed {}!");
    
        /* Otherwise take first argument */
        lval *v = lval_take(a, 0);
    
        /* Delete all elements that are not head and return */
        while (v->count > 1) {
            lval_del(lval_pop(v, 1));
        }
    
        return v;
    }
    
    lval *builtin_tail(lval *a) {
        LASSERT(a, a->count == 1,
                "Function 'tail' passed too many arguments!");
        LASSERT(a, a->cell[0]->type == LVAL_QEXPR,
                "Function 'tail' passed incorrect type!");
        LASSERT(a, a->cell[0]->count != 0,
                "Function 'tail' passed {}!");
    
        /* Take first argument */
        lval *v = lval_take(a, 0);
    
        /* Delete first element and return */
        lval_del(lval_pop(v, 0));
    
        return v;
    
    }
    
    lval *builtin_list(lval *a) {
        a->type = LVAL_QEXPR;
        return a;
    }
    
    lval *builtin_eval(lval *a) {
        LASSERT(a, a->count == 1,
                "Function 'eval' passed too many arguments!");
        LASSERT(a, a->cell[0]->type == LVAL_QEXPR,
                "Function 'eval' passed incorrect type!");
    
        lval *x = lval_take(a, 0);
        x->type = LVAL_SEXPR;
        return lval_eval(x);
    }
    
    lval *lval_join(lval *x, lval *y) {
    
        /* For each cell in 'y' add it to 'x' */
        while (y->count) {
             x = lval_add(x, lval_pop(y, 0));
        }
    
        /* Delete the empty 'y' and return 'x' */
        lval_del(y);
        return x;
    }
    
    lval *builtin_join(lval *a) {
        for (int i = 0; i < a->count; i++) {
            LASSERT(a, a->cell[i]->type == LVAL_QEXPR,
                    "Function 'join' passed incorrect type.");
        }
    
        lval *x = lval_pop(a, 0);
    
        while (a->count) {
            x = lval_join(x, lval_pop(a, 0));
        }
    
        lval_del(a);
        return x;
    }
    
    lval *builtin(lval* a, char* func) {
        if (strcmp("list", func) == 0) { return builtin_list(a); }
        if (strcmp("head", func) == 0) { return builtin_head(a); }
        if (strcmp("tail", func) == 0) { return builtin_tail(a); }
        if (strcmp("join", func) == 0) { return builtin_join(a); }
        if (strcmp("eval", func) == 0) { return builtin_eval(a); }
        if (strstr("+-/*", func)) { return builtin_op(a, func); }
        lval_del(a);
        return lval_err("Unknown Function!");
    
    }
    
    int main(int argc, char *argv[]) {
    
        /* Create Some Parsers */
        mpc_parser_t *Number   = mpc_new("number");
        mpc_parser_t* Symbol   = mpc_new("symbol");
        mpc_parser_t* Sexpr    = mpc_new("sexpr");
        mpc_parser_t *Qexpr    = mpc_new("qexpr");
        mpc_parser_t *Expr     = mpc_new("expr");
        mpc_parser_t *Lispy    = mpc_new("lispy");
    
        /* Define them with the following Language */
        mpca_lang(MPCA_LANG_DEFAULT,
                "                                                       \
                number   : /-?[0-9]+/ ;                                 \
                symbol   : \"list\" | \"head\" | \"tail\"               \
                         | \"join\" | \"eval\"                          \
                         | '+' | '-' | '*' | '/' ;                      \
                sexpr    : '(' <expr>* ')' ;                            \
                qexpr    : '{' <expr>* '}' ;                            \
                expr     : <number> | <symbol> | <sexpr> | <qexpr> ;    \
                lispy    : /^/ <expr>* /$/ ;                            \
                ",
                Number, Symbol, Sexpr, Qexpr, Expr, Lispy);
    
        puts("Lispy Version 0.1");
        puts("Press Ctrl+c to Exit\n");
    
        while(1) {
            char *input = NULL;
    
            input = readline("lispy> ");
            add_history(input);
    
            /* Attempt to parse the user input */
            mpc_result_t r;
    
            if (mpc_parse("<stdin>", input, Lispy, &r)) {
                /* On success print and delete the AST */
                lval *x = lval_eval(lval_read(r.output));
                lval_println(x);
                lval_del(x);
                mpc_ast_delete(r.output);
            } else {
                /* Otherwise print and delete the Error */
                mpc_err_print(r.error);
                mpc_err_delete(r.error);
            }
    
            free(input);
    
        }
    
        /* Undefine and delete our parsers */
        mpc_cleanup(6, Number, Symbol, Sexpr, Qexpr, Expr, Lispy);
    
        return 0;
    }
    
      20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
    • 63
    • 64
    • 65
    • 66
    • 67
    • 68
    • 69
    • 70
    • 71
    • 72
    • 73
    • 74
    • 75
    • 76
    • 77
    • 78
    • 79
    • 80
    • 81
    • 82
    • 83
    • 84
    • 85
    • 86
    • 87
    • 88
    • 89
    • 90
    • 91
    • 92
    • 93
    • 94
    • 95
    • 96
    • 97
    • 98
    • 99
    • 100
    • 101
    • 102
    • 103
    • 104
    • 105
    • 106
    • 107
    • 108
    • 109
    • 110
    • 111
    • 112
    • 113
    • 114
    • 115
    • 116
    • 117
    • 118
    • 119
    • 120
    • 121
    • 122
    • 123
    • 124
    • 125
    • 126
    • 127
    • 128
    • 129
    • 130
    • 131
    • 132
    • 133
    • 134
    • 135
    • 136
    • 137
    • 138
    • 139
    • 140
    • 141
    • 142
    • 143
    • 144
    • 145
    • 146
    • 147
    • 148
    • 149
    • 150
    • 151
    • 152
    • 153
    • 154
    • 155
    • 156
    • 157
    • 158
    • 159
    • 160
    • 161
    • 162
    • 163
    • 164
    • 165
    • 166
    • 167
    • 168
    • 169
    • 170
    • 171
    • 172
    • 173
    • 174
    • 175
    • 176
    • 177
    • 178
    • 179
    • 180
    • 181
    • 182
    • 183
    • 184
    • 185
    • 186
    • 187
    • 188
    • 189
    • 190
    • 191
    • 192
    • 193
    • 194
    • 195
    • 196
    • 197
    • 198
    • 199
    • 200
    • 201
    • 202
    • 203
    • 204
    • 205
    • 206
    • 207
    • 208
    • 209
    • 210
    • 211
    • 212
    • 213
    • 214
    • 215
    • 216
    • 217
    • 218
    • 219
    • 220
    • 221
    • 222
    • 223
    • 224
    • 225
    • 226
    • 227
    • 228
    • 229
    • 230
    • 231
    • 232
    • 233
    • 234
    • 235
    • 236
    • 237
    • 238
    • 239
    • 240
    • 241
    • 242
    • 243
    • 244
    • 245
    • 246
    • 247
    • 248
    • 249
    • 250
    • 251
    • 252
    • 253
    • 254
    • 255
    • 256
    • 257
    • 258
    • 259
    • 260
    • 261
    • 262
    • 263
    • 264
    • 265
    • 266
    • 267
    • 268
    • 269
    • 270
    • 271
    • 272
    • 273
    • 274
    • 275
    • 276
    • 277
    • 278
    • 279
    • 280
    • 281
    • 282
    • 283
    • 284
    • 285
    • 286
    • 287
    • 288
    • 289
    • 290
    • 291
    • 292
    • 293
    • 294
    • 295
    • 296
    • 297
    • 298
    • 299
    • 300
    • 301
    • 302
    • 303
    • 304
    • 305
    • 306
    • 307
    • 308
    • 309
    • 310
    • 311
    • 312
    • 313
    • 314
    • 315
    • 316
    • 317
    • 318
    • 319
    • 320
    • 321
    • 322
    • 323
    • 324
    • 325
    • 326
    • 327
    • 328
    • 329
    • 330
    • 331
    • 332
    • 333
    • 334
    • 335
    • 336
    • 337
    • 338
    • 339
    • 340
    • 341
    • 342
    • 343
    • 344
    • 345
    • 346
    • 347
    • 348
    • 349
    • 350
    • 351
    • 352
    • 353
    • 354
    • 355
    • 356
    • 357
    • 358
    • 359
    • 360
    • 361
    • 362
    • 363
    • 364
    • 365
    • 366
    • 367
    • 368
    • 369
    • 370
    • 371
    • 372
    • 373
    • 374
    • 375
    • 376
    • 377
    • 378
    • 379
    • 380
    • 381
    • 382
    • 383
    • 384
    • 385
    • 386
    • 387
    • 388
    • 389
    • 390
    • 391
    • 392
    • 393
    • 394
    • 395
    • 396
    • 397
    • 398
    • 399
    • 400
    • 401
    • 402
    • 403
    • 404
    • 405
    • 406
    • 407
    • 408
    • 409
    • 410
    • 411
    • 412
    • 413
    • 414
    • 415
    • 416
    • 417
    • 418
    • 419
    • 420
    • 421
    • 422
    • 423
    • 424
    • 425
    • 426
    • 427
    • 428
    • 429
    • 430
    • 431
    • 432
    • 433
    • 434
    • 435
    • 436
    • 437
    • 438
    • 439
    • 440
    • 441
    • 442
    • 443
    • 444
    • 445
    • 446
    • 447
    • 448
    • 449
    • 450
    • 451
    • 452
    • 453
    • 454
    • 455
    • 456
    • 457
    • 458
    • 459
    • 460
    • 461
    • 462
    • 463
    • 464
    • 465
    • 466
    • 467
    • 468
    • 469
    • 470
    • 471
    • 472
    • 473
    • 474
    • 475
    • 476
    • 477
    • 478
    • 479
    • 480

    编译

    gcc -g -std=c99 -Wall main.c mpc.c -lreadline -lm -o main
    
    • 1

    运行:

    Lispy Version 0.1
    Press Ctrl+c to Exit
    
    lispy> head {1 2 3}
    {1}
    
    lispy> tail {1 2 3}
    {2 3}
    
    lispy> join {1 2 3} {4 5 6}
    {1 2 3 4 5 6}
    
    lispy> list {1 2 3} {4 5 6}
    {{1 2 3} {4 5 6}}
    
    lispy> eval {+ 1 2 3}
    6
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17

    相关技术文章

    点击QQ咨询
    开通会员
    返回顶部
    ×
    微信扫码支付
    微信扫码支付
    确定支付下载
    请使用微信描二维码支付
    ×

    提示信息

    ×

    选择支付方式

    • 微信支付
    • 支付宝付款
    确定支付下载