eval if statement, num2bool conversion
This commit is contained in:
parent
97a04bd1ce
commit
7ace1d6fe9
130
tokenize.l
130
tokenize.l
|
@ -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");
|
||||
}
|
||||
}
|
||||
|
||||
|
|
Loading…
Reference in New Issue