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)的主要内容,如果未能解决你的问题,请参考以下文章
NSFetchedResultsController 部分索引将转到错误的行