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:
|
/* 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
|
* Compile: flex tokenize.l
|
||||||
* cc lex.yy.c -lfl
|
* cc lex.yy.c -lfl
|
||||||
*/
|
*/
|
||||||
%{
|
%{
|
||||||
#include <assert.h>
|
#include <assert.h>
|
||||||
|
@ -11,7 +36,7 @@
|
||||||
struct token;
|
struct token;
|
||||||
struct token {
|
struct token {
|
||||||
int type;
|
int type;
|
||||||
union {
|
union {
|
||||||
char *str;
|
char *str;
|
||||||
int num;
|
int num;
|
||||||
} v;
|
} v;
|
||||||
|
@ -47,7 +72,7 @@ enum yytokentype {
|
||||||
RPAR = 260,
|
RPAR = 260,
|
||||||
SYM = 261,
|
SYM = 261,
|
||||||
STR = 262,
|
STR = 262,
|
||||||
EOL = 263,
|
EOL = 263,
|
||||||
BOOL = 264
|
BOOL = 264
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -58,29 +83,36 @@ char *yystr;
|
||||||
%}
|
%}
|
||||||
|
|
||||||
%%
|
%%
|
||||||
"(" { return LPAR; }
|
"(" { return LPAR; }
|
||||||
")" { return RPAR; }
|
")" { return RPAR; }
|
||||||
t { yylval = 1; return BOOL;}
|
t { yylval = 1; return BOOL;}
|
||||||
nil { yylval = 0; return BOOL; }
|
nil { yylval = 0; return BOOL; }
|
||||||
[0-9]+ { yylval = atoi(yytext); return NUM; }
|
[0-9]+ { yylval = atoi(yytext); return NUM; }
|
||||||
[ \t\n] { /* ignore white space */ }
|
[ \t\n] { /* ignore white space */ }
|
||||||
\".*\" { return STR; }
|
\".*\" { return STR; }
|
||||||
[a-zA-Z][a-zA-Z0-9]* { return SYM; }
|
[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
|
* Goal: evaluate simple LISP forms in an
|
||||||
* @ Functions
|
* read-eval-print stylized loop. supports:
|
||||||
* 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
|
|
||||||
*
|
*
|
||||||
|
* 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)
|
* (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>)
|
* (if <bool> <body> <else>)
|
||||||
* (quote a) -> a
|
* (quote a) -> a
|
||||||
*/
|
*/
|
||||||
|
@ -120,12 +152,12 @@ make_token(enum yytokentype type, int num, char* str)
|
||||||
{
|
{
|
||||||
struct token *t =
|
struct token *t =
|
||||||
(struct token*) calloc(1, sizeof(struct token));
|
(struct token*) calloc(1, sizeof(struct token));
|
||||||
if (t == NULL)
|
if (t == NULL)
|
||||||
err(1, "malloc failed");
|
err(1, "malloc failed");
|
||||||
t->type = type;
|
t->type = type;
|
||||||
if (type == NUM || type == BOOL)
|
if (type == NUM || type == BOOL)
|
||||||
t->v.num = num;
|
t->v.num = num;
|
||||||
else if (type == SYM || type == STR)
|
else if (type == SYM || type == STR)
|
||||||
t->v.str = strdup(str);
|
t->v.str = strdup(str);
|
||||||
return t;
|
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, "lt") == 0) return 1;
|
||||||
else if (strcmp(t->v.str, "nand") == 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, "q") == 0) return 1;
|
||||||
|
else if (strcmp(t->v.str, "num2bool") == 0) return 1;
|
||||||
else return 0;
|
else return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -267,6 +300,29 @@ eval_def(struct ast *a, struct env *e)
|
||||||
return NULL;
|
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 */
|
/* (nand <ausdruck::bool> <audsruck::bool>) -> BOOL */
|
||||||
struct ast *
|
struct ast *
|
||||||
eval_nand(struct ast *a, struct env *e)
|
eval_nand(struct ast *a, struct env *e)
|
||||||
|
@ -362,6 +418,24 @@ eval_inv(struct ast *a, struct env *e)
|
||||||
NULL));
|
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 *
|
struct ast *
|
||||||
eval_internal_sym(struct ast *a, struct env *e)
|
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);
|
return eval_def(a, e);
|
||||||
else if (strcmp(a->v.token->v.str, "lm") == 0) {
|
else if (strcmp(a->v.token->v.str, "lm") == 0) {
|
||||||
} else if (strcmp(a->v.token->v.str, "if") == 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) {
|
} else if (strcmp(a->v.token->v.str, "inv") == 0) {
|
||||||
return eval_inv(a, e);
|
return eval_inv(a, e);
|
||||||
} else if (strcmp(a->v.token->v.str, "add") == 0) {
|
} 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) {
|
} else if (strcmp(a->v.token->v.str, "q") == 0) {
|
||||||
//return make_ast(AST_QUOTE, a->next);
|
//return make_ast(AST_QUOTE, a->next);
|
||||||
return a->next;
|
return a->next;
|
||||||
|
} else if (strcmp(a->v.token->v.str, "num2bool") == 0) {
|
||||||
|
return eval_num2bool(a, e);
|
||||||
}
|
}
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
@ -446,6 +523,11 @@ pr(struct ast *a)
|
||||||
else
|
else
|
||||||
printf("nil\n");
|
printf("nil\n");
|
||||||
}
|
}
|
||||||
|
break;
|
||||||
|
case AST_LIST:
|
||||||
|
printf("#fn\n");
|
||||||
|
default:
|
||||||
|
err(1, "don't know how to print");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue