eval if statement, num2bool conversion

This commit is contained in:
Christian Barthel 2019-07-02 23:10:55 +02:00
parent 97a04bd1ce
commit 7ace1d6fe9
1 changed files with 106 additions and 24 deletions

View File

@ -1,7 +1,32 @@
/* llm - litle lisp machine:
* Author: Christian Barthel <bch@online.de>
*
* Copyright (c) 2019 Christian Barthel <bch@online.de>
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*
*
* Compile: flex tokenize.l
* cc lex.yy.c -lfl
* cc lex.yy.c -lfl
*/
%{
#include <assert.h>
@ -11,7 +36,7 @@
struct token;
struct token {
int type;
union {
union {
char *str;
int num;
} v;
@ -47,7 +72,7 @@ enum yytokentype {
RPAR = 260,
SYM = 261,
STR = 262,
EOL = 263,
EOL = 263,
BOOL = 264
};
@ -58,29 +83,36 @@ char *yystr;
%}
%%
"(" { return LPAR; }
")" { return RPAR; }
t { yylval = 1; return BOOL;}
nil { yylval = 0; return BOOL; }
[0-9]+ { yylval = atoi(yytext); return NUM; }
[ \t\n] { /* ignore white space */ }
\".*\" { return STR; }
"(" { return LPAR; }
")" { return RPAR; }
t { yylval = 1; return BOOL;}
nil { yylval = 0; return BOOL; }
[0-9]+ { yylval = atoi(yytext); return NUM; }
[ \t\n] { /* ignore white space */ }
\".*\" { return STR; }
[a-zA-Z][a-zA-Z0-9]* { return SYM; }
. { err(1, "invalid symbol: %s\n", yytext); }
. { err(1, "invalid symbol: %s\n", yytext); }
%%
/*
* Goal: write LISP read-eval-print Loop and support
* @ Functions
* t,nil boolean (nand 0 1) -> boolean
* "str" Strings (streq str1 str2) -> boolean
* abc Symboles (symeq s1 s2) -> boolean
* 1234 Number/Integer [add,inv] -> num
* [lt] -> boolean
* [num-to-bool] -> boolean
* Goal: evaluate simple LISP forms in an
* read-eval-print stylized loop. supports:
*
* Data types:
* # Functions
* t,nil boolean (nand <bool> <bool>) -> boolean
* "str" Strings (streq <string> <string>) -> boolean
* abc Symboles (symeq <sym> <sym>) -> boolean
* 1234 Number/Integer (inv <num>) -> -num
* (add <num> <num>) -> num
* (lt <num> <num>) -> boolean
* (num2bool <num>) -> boolean
*
* Special Forms:
* (def <var> <symbol,number,#function)
* (lambda (<symbol> ..) (<sym..> ))
* Bind symbol <var> in the current environment to
* the evaluated form.
* (lm (<symbol> ..) (<sym..> ))
* (if <bool> <body> <else>)
* (quote a) -> a
*/
@ -120,12 +152,12 @@ make_token(enum yytokentype type, int num, char* str)
{
struct token *t =
(struct token*) calloc(1, sizeof(struct token));
if (t == NULL)
if (t == NULL)
err(1, "malloc failed");
t->type = type;
if (type == NUM || type == BOOL)
if (type == NUM || type == BOOL)
t->v.num = num;
else if (type == SYM || type == STR)
else if (type == SYM || type == STR)
t->v.str = strdup(str);
return t;
}
@ -170,6 +202,7 @@ int token_is_internal(struct token *t) {
else if (strcmp(t->v.str, "lt") == 0) return 1;
else if (strcmp(t->v.str, "nand") == 0) return 1;
else if (strcmp(t->v.str, "q") == 0) return 1;
else if (strcmp(t->v.str, "num2bool") == 0) return 1;
else return 0;
}
@ -267,6 +300,29 @@ eval_def(struct ast *a, struct env *e)
return NULL;
}
/* (if <cond:bool> <expression> <expression>) */
struct ast *
eval_if(struct ast *a, struct env *e)
{
a = a->next;
assert(a != NULL && a->next != NULL);
struct ast *condition = eval(a, e);
assert(condition != NULL &&
condition->type == AST_TOK &&
condition->v.token->type == BOOL);
assert(a->next != NULL &&
a->next->next != NULL);
if (condition->v.token->v.num == 1)
return eval(a->next, e);
else
return eval(a->next->next, e);
}
/* (nand <ausdruck::bool> <audsruck::bool>) -> BOOL */
struct ast *
eval_nand(struct ast *a, struct env *e)
@ -362,6 +418,24 @@ eval_inv(struct ast *a, struct env *e)
NULL));
}
/* (num2bool <ausdruck::NUM>) -> bool */
struct ast *
eval_num2bool(struct ast *a, struct env *e)
{
assert(a != 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->next == NULL);
return make_ast(AST_TOK,
make_token(BOOL,
op->v.token->v.num != 0,
NULL));
}
struct ast *
eval_internal_sym(struct ast *a, struct env *e)
{
@ -369,6 +443,7 @@ eval_internal_sym(struct ast *a, struct env *e)
return eval_def(a, e);
else if (strcmp(a->v.token->v.str, "lm") == 0) {
} else if (strcmp(a->v.token->v.str, "if") == 0) {
return eval_if(a, e);
} else if (strcmp(a->v.token->v.str, "inv") == 0) {
return eval_inv(a, e);
} else if (strcmp(a->v.token->v.str, "add") == 0) {
@ -380,6 +455,8 @@ eval_internal_sym(struct ast *a, struct env *e)
} else if (strcmp(a->v.token->v.str, "q") == 0) {
//return make_ast(AST_QUOTE, a->next);
return a->next;
} else if (strcmp(a->v.token->v.str, "num2bool") == 0) {
return eval_num2bool(a, e);
}
return NULL;
}
@ -446,6 +523,11 @@ pr(struct ast *a)
else
printf("nil\n");
}
break;
case AST_LIST:
printf("#fn\n");
default:
err(1, "don't know how to print");
}
}