add NAND, add boolean type, read form

- this commit adds the boolean type with the
	NAND operation (which is complete and other
	operations can be built by using NAND)
- read from now reads until an entire form
	has been entered.  line breaks, whitespace
	and tabs are allowed.
This commit is contained in:
Christian Barthel 2019-06-29 13:20:05 +02:00
parent 6f1ba0333f
commit 7f362af841
1 changed files with 78 additions and 32 deletions

View File

@ -48,7 +48,7 @@ enum yytokentype {
SYM = 261,
STR = 262,
EOL = 263,
QUOTE = 264
BOOL = 264
};
struct token* make_token(enum yytokentype, int, char*);
@ -60,8 +60,9 @@ char *yystr;
%%
"(" { return LPAR; }
")" { return RPAR; }
t { yylval = 1; return BOOL;}
nil { yylval = 0; return BOOL; }
[0-9]+ { yylval = atoi(yytext); return NUM; }
\n { return EOL; }
[ \t\n] { /* ignore white space */ }
\".*\" { return STR; }
[a-zA-Z][a-zA-Z0-9]* { return SYM; }
@ -70,14 +71,13 @@ char *yystr;
/*
* Goal: write LISP read-eval-print Loop and support
* @ Function
* 0,1 boolean (nand 0 1) -> boolean
* (eq 0 0) -> boolean
* @ Functions
* t,nil boolean (nand 0 1) -> boolean
* "str" Strings (streq str1 str2) -> boolean
* abc Symboles (symeq s1 s2) -> boolean
* 1234 Number/Integer [add,sub,div,mul,mod] -> num
* [lt, numeq] -> boolean
* [num2bool] -> boolean
* abc Symboles (symeq s1 s2) -> boolean
* 1234 Number/Integer [add,inv] -> num
* [lt] -> boolean
* [num-to-bool] -> boolean
*
* (def <var> <symbol,number,#function)
* (lambda (<symbol> ..) (<sym..> ))
@ -123,7 +123,7 @@ make_token(enum yytokentype type, int num, char* str)
if (t == NULL)
err(1, "malloc failed");
t->type = type;
if (type == NUM)
if (type == NUM || type == BOOL)
t->v.num = num;
else if (type == SYM || type == STR)
t->v.str = strdup(str);
@ -160,6 +160,7 @@ make_env(char *name, struct ast *a)
int token_is_num(struct token *t) {return t->type == NUM;}
int token_is_sym(struct token *t) {return t->type == SYM;}
int token_is_str(struct token *t) {return t->type == STR;}
int token_is_bool(struct token *t) {return t->type == BOOL;}
/* upon parsing a list of tokens like:
* "(" -> "def" -> "(" -> "b" -> ")" -> "c" -> ")"
@ -199,6 +200,9 @@ parse(struct token *t)
} else if (t->type == NUM) {
next = t->next;
return make_ast(AST_TOK, t);
} else if (t->type == BOOL) {
next = t->next;
return make_ast(AST_TOK, t);
} else if (t->type == SYM) {
next = t->next;
return make_ast(AST_TOK, t);
@ -237,6 +241,8 @@ eval_def(struct ast *a, struct env *e)
a = a->next; /* skrip `def` */
assert((a->next->type == AST_TOK &&
a->next->v.token->type== STR) ||
(a->next->type == AST_TOK &&
a->next->v.token->type == BOOL) ||
(a->next->type == AST_TOK &&
a->next->v.token->type == NUM) ||
(a->next->type == AST_LIST) ||
@ -249,7 +255,33 @@ eval_def(struct ast *a, struct env *e)
return NULL;
}
/* (add <ausdruck::NUM> <audsruck::NUM> */
/* (nand <ausdruck::bool> <audsruck::bool>) -> BOOL */
struct ast *
eval_nand(struct ast *a, struct env *e)
{
assert (a != NULL &&
a->next != NULL &&
a->next->next != NULL &&
a->next->next->next == NULL);
struct ast *op1 = eval(a->next, e);
struct ast *op2 = eval(a->next->next, e);
assert (op1 != NULL &&
op1->type == AST_TOK &&
op1->v.token->type == BOOL &&
op2 != NULL &&
op2->type == AST_TOK &&
op2->v.token->type == BOOL );
return make_ast(AST_TOK,
make_token(BOOL,
!(
op1->v.token->v.num &
op2->v.token->v.num) ,
NULL));
}
/* (add <ausdruck::NUM> <audsruck::NUM>) -> NUM */
struct ast *
eval_add(struct ast *a, struct env *e)
{
@ -274,16 +306,18 @@ eval_add(struct ast *a, struct env *e)
NULL));
}
/* inv <ausdruck::NUM> */
/* (inv <ausdruck::NUM>) -> NUM */
struct ast *
eval_inv(struct ast *a, struct env *e)
{
assert(a != NULL &&
a->next != NULL);
a->next != NULL &&
a->next->next == NULL);
struct ast *op = eval(a->next, e);
assert(op != NULL &&
op->type == AST_TOK &&
op->v.token->type == NUM);
op->v.token->type == NUM &&
op->next == NULL);
return make_ast(AST_TOK,
make_token(NUM,
0 -
@ -302,6 +336,8 @@ eval_sym(struct ast *a, struct env *e)
return eval_inv(a, e);
} else if (strcmp(a->v.token->v.str, "add") == 0) {
return eval_add(a, e);
} else if (strcmp(a->v.token->v.str, "nand") == 0) {
return eval_nand(a, e);
} else if (strcmp(a->v.token->v.str, "q") == 0) {
//return make_ast(AST_QUOTE, a->next);
return a->next;
@ -330,6 +366,8 @@ eval(struct ast *a, struct env *e)
return eval_sym(a, e);
else if (token_is_str(a->v.token))
return make_ast(AST_TOK, a->v.token);
else if (token_is_bool(a->v.token))
return make_ast(AST_TOK, a->v.token);
case AST_LIST:
return eval(a->v.list, e);
default:
@ -354,39 +392,47 @@ pr(struct ast *a)
printf("%s\n", a->v.token->v.str);
else if (a->v.token->type == SYM)
printf("%s\n", a->v.token->v.str);
else if (a->v.token->type == BOOL) {
if (a->v.token->v.num)
printf("t\n");
else
printf("nil\n");
}
}
}
int main(void)
struct token*
read_form()
{
int tok;
int tok, open = 0;
struct token *t, *u = NULL, *start = NULL;
struct env default_env = { 0 }, *env;
env = &default_env;
env->name = "";
while((tok = yylex())) {
/* read token and create list */
if (tok == LPAR) open++;
else if (tok == RPAR) open--;
t = make_token(tok, yylval, yytext);
if (start == NULL) start = t;
if (u == NULL) u = t;
else u->next = t;
u = t;
/* if EOL is reached, parse and evaluate form: */
if (t->type == EOL) {
struct token *x = start;
// while (x != NULL) {debug_token(x, 0); x = x->next;}
/* struct ast *tl = parse(start); */
/* eval(tl); */
pr(eval(parse(start), env));
//debug_ast(tl, 1);
/* start anew: */
start = NULL;
if (!open) {
return start;
}
}
exit(0);
}
int main(void)
{
struct env default_env = { 0 }, *env;
env = &default_env;
env->name = "__dummy";
while (1)
pr(eval(parse(read_form()), env));
return 0;
}