diff --git a/tokenize.l b/tokenize.l index 2eff762..13508f5 100644 --- a/tokenize.l +++ b/tokenize.l @@ -1,7 +1,32 @@ /* llm - litle lisp machine: - * Author: Christian Barthel + * + * Copyright (c) 2019 Christian Barthel + * 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 @@ -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 ) -> boolean + * "str" Strings (streq ) -> boolean + * abc Symboles (symeq ) -> boolean + * 1234 Number/Integer (inv ) -> -num + * (add ) -> num + * (lt ) -> boolean + * (num2bool ) -> boolean + * + * Special Forms: * (def ..) ( )) + * Bind symbol in the current environment to + * the evaluated form. + * (lm ( ..) ( )) * (if ) * (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 ) */ +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 ) -> 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 ) -> 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"); } }