c_cpp 最小的Lisp!在C(WIP,将转到https://github.com/andy0130tw/epslisp)

Posted

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了c_cpp 最小的Lisp!在C(WIP,将转到https://github.com/andy0130tw/epslisp)相关的知识,希望对你有一定的参考价值。

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <ctype.h>

#define STACK_MAX 1024
#define DEFS_MAX  1024

#define eprintf(format, ...)  fprintf(stderr, format, ## __VA_ARGS__)

enum token_type {
    TOKEN_ILLEGAL = -1,
    TOKEN_PAREN_LEFT,
    TOKEN_PAREN_RIGHT,
    TOKEN__SYMBOL,
    TOKEN_DISPLAY,
    TOKEN_BEGIN,
    TOKEN_IF,
    TOKEN_DEFINE,
    TOKEN_LAMBDA,
    TOKEN_ARITH_PLUS,
    TOKEN_ARITH_MINUS,
    TOKEN_ARITH_LESS_THEN,
    TOKEN_COMMENT_START,
    TOKEN_VAR,
    TOKEN_NUM,
    TOKEN_EOF,
};

enum error_type {
    ERROR_DUMMY,
    ERROR_STACK_OVERFLOW,
    ERROR_ILLEGAL_CHAR,
    ERROR_MISSING_SPACE,
    ERROR_ILLEGAL_NUM,
    ERROR_UNEXPECTED_PAREN_RIGHT,
    ERROR_ALL
};

enum expr_type {
    EXPR_INT,
    EXPR_TUPLE
};

typedef struct _def {
    enum expr_type type;
    const char* name;
    void* value;
} def;

typedef struct _expr {
    enum expr_type type;
    unsigned int arity;
    struct _expr* args;
} expr;

static enum error_type errorInd;
static expr stack[STACK_MAX];
static unsigned int stack_top;
static def scope_defs[DEFS_MAX];
static def* def_stack[STACK_MAX];

static int cntline = 0;
static int cntchar = 0;

static enum token_type infer_keyword(const char* buf) {
    static struct {
        const char* k;
        enum token_type typ;
    } kwlookup[] = {
        { .k = "+", .typ = TOKEN_ARITH_PLUS },
        { .k = "-", .typ = TOKEN_ARITH_MINUS },
        { .k = "<", .typ = TOKEN_ARITH_LESS_THEN },

        { .k = "display", .typ = TOKEN_DISPLAY },
        { .k = "begin",   .typ = TOKEN_BEGIN },
        { .k = "if",      .typ = TOKEN_IF },
        { .k = "define",  .typ = TOKEN_DEFINE },
        { .k = "lambda",  .typ = TOKEN_LAMBDA },
    };
    static const int kwlen = sizeof(kwlookup) / sizeof(kwlookup[0]);

    for (int i = 0; i < kwlen; i++) {
        if (strcmp(buf, kwlookup[i].k) == 0) {
            return kwlookup[i].typ;
        }
    }
    return TOKEN_VAR;
}

static enum token_type readtok(char** buf, size_t* sz, FILE* src) {
    int c;
    size_t bufcount = 0;
    // inferred token type
    enum token_type t;

    while (c = fgetc(src), c >= 0) {
        if (!bufcount) cntchar++;
        switch (c) {
        case ' ': case '\t': case '\r':
            if (!bufcount) continue;
            break;
        case '\n':
            cntline++, cntchar = 0;
            if (!bufcount) continue;
            break;
        case '(':
            if (!bufcount) return TOKEN_PAREN_LEFT;
            break;
        case ')':
            if (!bufcount) return TOKEN_PAREN_RIGHT;
            break;
        case ';':
            if (!bufcount) return TOKEN_COMMENT_START;
            break;
        default:
            if (c < 32) {
                **buf = c;
                errorInd = ERROR_ILLEGAL_CHAR;
                return TOKEN_ILLEGAL;
            } else if (!bufcount) {
                if (isdigit(c)) {
                    t = TOKEN_NUM;
                } else {
                    t = TOKEN__SYMBOL;
                }
                (*buf)[bufcount++] = c;
                continue;
            }
        }

        if (t == TOKEN_NUM) {
            if (isdigit(c)) {
                (*buf)[bufcount++] = c;
                cntchar++;
            } else {
                if (c > 32 && c != ')') {
                    (*buf)[bufcount++] = c;
                    while (c = fgetc(src), c > 32 && c != '(' && c != ')') {
                        (*buf)[bufcount++] = c;
                        cntchar++;
                    }
                    (*buf)[bufcount++] = '\0';
                    errorInd = ERROR_ILLEGAL_NUM;
                    return TOKEN_ILLEGAL;
                } else {
                    ungetc(c, src);
                }
                (*buf)[bufcount] = '\0';
                return TOKEN_NUM;
            }
        } else if (t == TOKEN__SYMBOL) {
            if (c > 32 && c != '(' && c != ')') {
                (*buf)[bufcount++] = c;
                cntchar++;
            } else {
                if (c != '\n') {
                    ungetc(c, src);
                }
                if (c == '(') {
                    errorInd = ERROR_MISSING_SPACE;
                    return TOKEN_ILLEGAL;
                } else {
                    (*buf)[bufcount] = '\0';
                    return TOKEN__SYMBOL;
                }
            }
        }
    }
    return TOKEN_EOF;
}

static void reportError(enum error_type err, char* buf) {
    eprintf("Line %d, char %d, ERROR: ", cntline + 1, cntchar);
    switch (err) {
    case ERROR_STACK_OVERFLOW:
        eprintf("stack overflow (>%d)!!\n", STACK_MAX);
        exit(1);
        break;
    case ERROR_UNEXPECTED_PAREN_RIGHT:
        eprintf("unexpected right parenthesis!!\n");
        exit(1);
        break;
    case ERROR_ILLEGAL_NUM:
        eprintf("invalid integer literal [%s]!!\n", buf);
        // TODO: read until stack pop to empty
        break;
    case ERROR_MISSING_SPACE:
        eprintf("missing space between tokens!!\n");
        // TODO: read until stack pop to empty
        break;
    default:
        eprintf("unimplemented error...\n");
    }
}

int main() {
    enum token_type tok;
    size_t bufsize = 48;
    char* tok_buf = (char*) malloc(bufsize * sizeof(char));
    FILE* input = stdin;
    FILE* output = stdout;

    while ((tok = readtok(&tok_buf, &bufsize, input)) != TOKEN_EOF) {

        eprintf("%d:%d: ", cntline + 1, cntchar);
        switch (tok) {
        case TOKEN_PAREN_LEFT:
            eprintf("paren left\n");
            stack_top++;
            if (stack_top == STACK_MAX) {
                reportError(ERROR_STACK_OVERFLOW, NULL);
                break;
            }
            // enum token_type typ = infer_keyword(tok_buf);
            break;

        case TOKEN_PAREN_RIGHT:
            eprintf("paren right\n");
            if (stack_top == 0) {
                reportError(ERROR_UNEXPECTED_PAREN_RIGHT, NULL);
                break;
            }
            stack_top--;
            if (stack_top == 0) {
                eprintf("exec...\n");
            }
            break;

        case TOKEN_NUM:
            eprintf("num %d\n", atoi(tok_buf));
            break;

        case TOKEN__SYMBOL:
            if (infer_keyword(tok_buf) != TOKEN_VAR) {
                eprintf("a symbol [%s]\n", tok_buf);
                break;
            }

        case TOKEN_VAR:
            eprintf("var [%s]\n", tok_buf);
            break;

        case TOKEN_COMMENT_START: {
            char* comment_buf = NULL;
            size_t sz = 0;
            ssize_t comment_len = getline(&comment_buf, &sz, input);
            cntchar = 0; cntline++;
            comment_buf[comment_len - 1] = '\0';
            eprintf("comment [;%s]\n", comment_buf);
            free(comment_buf);
            break;
        }
        case TOKEN_ILLEGAL:
            eprintf("illegal token [%s]!!\n", tok_buf);
            reportError(errorInd, tok_buf);
            break;

        default:
            eprintf("unknown symbol [%s]!!\n", tok_buf);
            // errorInd = ERROR_ALL;
            // break;
        }
    }

    free(tok_buf);
    if (stack_top != 0) {
        eprintf("unexpected end of file QAQ\n");
        return 1;
    }
}

以上是关于c_cpp 最小的Lisp!在C(WIP,将转到https://github.com/andy0130tw/epslisp)的主要内容,如果未能解决你的问题,请参考以下文章

c_cpp wip_digitdisplay.ino

c_cpp 在c中打印类似字符串的lisp

c_cpp lisp.c

NSFetchedResultsController 部分索引将转到错误的行

使用 nginx 的 Keycloak 重定向 url 将转到 http 而不是 https

在调用以下函数时,控件将转到 try 块内的第一行,即 Class.forName 然后捕获块