1#include <stdio.h>2#include <errno.h>3#include <stdarg.h>4#include <string.h>5#include <stdlib.h>6#include <pthread.h>7#include <semaphore.h>89#include <sys/queue.h>1011#include "util.h"12#include "scanner.h"13#include "parser.h"1415#define EXPTXT(T, M) \16 do { if (T->type != TOK_VAR || strcmp(T->text, M)) \17 return error(T->line, "Expected '%s' got '%s'", M, T->text); \18 } while (0)1920statement *stmt(parser *p);21void freeexpr(expr *e);22expr *expression(parser *p);2324parser*25newpar(char *str)26{27 parser *par;2829 par = emalloc(sizeof(parser));30 par->scr = scanstr(str);31 par->max = 5 * 1024;32 par->cur = 0;33 par->buf = emalloc(par->max * sizeof(token));34 par->peektok = NULL;3536 for (int i = 0; i <= par->max; i++)37 par->buf[i] = NULL;3839 return par;40}4142void43freepar(parser *par)44{45 freescr(par->scr);46 if (par->peektok)47 free(par->peektok);4849 free(par->buf);50 free(par);51}5253void54reset(parser *par)55{56 for (int i = 0; i <= par->cur; i++)57 par->buf[i] = NULL;5859 par->cur = 0;60 if (par->peektok != NULL)61 par->buf[0] = par->peektok;62}6364void65backup(parser *par)66{67 par->cur = 0;68}6970token*71peek(parser *par)72{73 token *tok;7475 if (par->cur > par->max)76 reset(par); /* FIXME */7778 tok = par->buf[par->cur];79 if (tok == NULL) {80 tok = nxttok(par->scr);81 par->buf[par->cur] = tok;82 par->peektok = tok;83 } else {84 par->peektok = NULL;85 }8687 return tok;88}8990token*91next(parser *par)92{93 token *tok;9495 tok = peek(par);96 par->cur++;9798 return tok;99}100101statement*102newstmt(void)103{104 return emalloc(sizeof(statement));105}106107void108freestmts(statement **stmts)109{110 int i = 0;111112 if (!stmts) return;113 while (stmts[i])114 freestmt(stmts[i++]);115 free(stmts);116}117118void119freestmt(statement *stmt)120{121 if (!stmt) return;122123 switch (stmt->type) {124 case STMT_ERROR:125 free(stmt->d.error.msg);126 break;127 case STMT_DEFINE:128 freeexpr(stmt->d.define.exp);129 free(stmt->d.define.var);130 break;131 case STMT_ASSIGN:132 freeexpr(stmt->d.assign.exp);133 free(stmt->d.assign.var);134 break;135 case STMT_READ:136 free(stmt->d.read.var);137 break;138 case STMT_WRITE:139 freeexpr(stmt->d.write.exp);140 break;141 case STMT_COND:142 freeexpr(stmt->d.cond.cond);143 freestmts(stmt->d.cond.brn1);144 freestmts(stmt->d.cond.brn2);145 break;146 case STMT_LOOP:147 freeexpr(stmt->d.loop.cond);148 freestmts(stmt->d.loop.brn);149 break;150 }151152 free(stmt);153}154155statement*156define(char *var, expr *exp)157{158 statement *stmt;159160 stmt = newstmt();161 stmt->type = STMT_DEFINE;162 stmt->d.define.var = estrdup(var);163 stmt->d.define.exp = exp;164 return stmt;165}166167statement*168assign(char *var, expr *exp)169{170 statement *stmt;171172 stmt = newstmt();173 stmt->type = STMT_ASSIGN;174 stmt->d.assign.var = estrdup(var);175 stmt->d.assign.exp = exp;176 return stmt;177}178179statement*180newread(char *var)181{182 statement *stmt;183184 stmt = newstmt();185 stmt->type = STMT_READ;186 stmt->d.read.var = estrdup(var);187 return stmt;188}189190statement*191newwrite(expr *exp)192{193 statement *stmt;194195 stmt = newstmt();196 stmt->type = STMT_WRITE;197 stmt->d.write.exp = exp;198 return stmt;199}200201statement*202newcond(expr *cexp, statement **brn1, statement **brn2)203{204 statement *stmt;205206 stmt = newstmt();207 stmt->type = STMT_COND;208 stmt->d.cond.cond = cexp;209 stmt->d.cond.brn1 = brn1;210 stmt->d.cond.brn2 = brn2;211 return stmt;212}213214statement*215newloop(expr *cexp, statement **brn)216{217 statement *stmt;218219 stmt = newstmt();220 stmt->type = STMT_LOOP;221 stmt->d.loop.cond = cexp;222 stmt->d.loop.brn = brn;223 return stmt;224}225226statement*227error(int line, char *msg, ...)228{229 int slen;230 statement *stmt;231 va_list ap;232 char *dest;233234 va_start(ap, msg);235 slen = vsnprintf(NULL, 0, msg, ap);236 va_end(ap);237238 dest = emalloc(slen * sizeof(char));239240 va_start(ap, msg);241 vsnprintf(dest, slen, msg, ap);242 va_end(ap);243244 stmt = newstmt();245 stmt->type = STMT_ERROR;246 stmt->d.error.msg = dest;247 stmt->d.error.line = line;248 return stmt;249}250251expr*252newexpr(void)253{254 return emalloc(sizeof(expr));255}256257void258freeexpr(expr *exp)259{260 if (!exp) return;261262 switch (exp->type) {263 case EXP_LIT:264 /* Nothing to free here. */265 break;266 case EXP_VAR:267 free(exp->d.variable.var);268 break;269 case EXP_BIN:270 freeexpr(exp->d.operation.expr1);271 freeexpr(exp->d.operation.expr2);272 break;273 }274275 free(exp);276}277278expr*279literal(int num)280{281 expr *exp;282283 exp = newexpr();284 exp->type = EXP_LIT;285 exp->d.literal.num = num;286 return exp;287}288289expr*290variable(char *name)291{292 expr *exp;293294 exp = newexpr();295 exp->type = EXP_VAR;296 exp->d.variable.var = strdup(name);297 return exp;298}299300expr*301operation(binop op, expr *expr1, expr *expr2)302{303 expr *exp;304305 exp = newexpr();306 exp->type = EXP_BIN;307 exp->d.operation.op = op;308 exp->d.operation.expr1 = expr1;309 exp->d.operation.expr2 = expr2;310 return exp;311}312313expr*314factor(parser *par)315{316 expr *exp;317 token *tok;318319 tok = next(par);320 if (tok->type == TOK_DIG) {321 return literal(atoi(tok->text));322 } else if (tok->type == TOK_VAR) {323 return variable(tok->text);324 }325326 tok = next(par);327 if (tok->type == TOK_LBRACKET) {328 if (!(exp = expression(par)))329 return NULL;330331 tok = next(par);332 if (tok->type != TOK_RBRACKET)333 return NULL;334335 return exp;336 }337338 return NULL;339}340341expr*342term(parser *par)343{344 binop op;345 expr *fac1, *fac2;346 token *tok;347348 if (!(fac1 = factor(par)))349 return NULL;350351 tok = peek(par);352 switch (tok->type) {353 case TOK_MULTI:354 op = OP_MULTI;355 next(par);356 break;357 case TOK_DIVIDE:358 op = OP_DIVIDE;359 next(par);360 break;361 default:362 return fac1;363 }364365 if (!(fac2 = factor(par)))366 return NULL;367368 return operation(op, fac1, fac2);369}370371expr*372expression(parser *par)373{374 binop op;375 expr *term1, *term2;376 token *tok;377378 if (!(term1 = term(par)))379 return NULL;380381 tok = peek(par);382 switch (tok->type) {383 case TOK_PLUS:384 op = OP_PLUS;385 next(par);386 break;387 case TOK_MINUS:388 op = OP_MINUS;389 next(par);390 break;391 default:392 return term1;393 }394395 if (!(term2 = term(par)))396 return NULL;397398 return operation(op, term1, term2);399}400401statement**402cmdblock(parser *par, statement *err)403{404 int i = -1;405 token *tok;406 statement **cmds;407 size_t max = 512;408409 cmds = malloc(max * sizeof(statement));410 for (i = 0, tok = peek(par); tok != TOK_EOF;411 i++, tok = peek(par)) {412 if (i > max) {413 err->d.error.msg = estrdup("Exceeded maximum amount of cmdblock");414 err->d.error.line = 0;415 goto err;416 }417418 if ((cmds[i] = stmt(par)) && cmds[i]->type == STMT_ERROR) {419 err->d.error.msg = estrdup(cmds[i]->d.error.msg);420 err->d.error.line = cmds[i++]->d.error.line;421 goto err;422 }423424 tok = peek(par);425 if (tok->type == TOK_SEMICOLON)426 next(par);427 else428 break;429 }430431 if (i == -1) {432 err = error(-1, "Unexpected EOF");433 free(cmds);434 return NULL;435 }436437 cmds[++i] = NULL;438 return cmds;439440err:441 err->type = STMT_ERROR;442 cmds[i] = NULL;443 freestmts(cmds);444 return NULL;445}446447statement*448letstmt(parser *par)449{450 token *tok;451 char *var;452 expr *exp;453454 tok = next(par);455 EXPTXT(tok, "let");456457 tok = next(par);458 if (tok->type != TOK_VAR)459 return error(tok->line, "Expected variable after 'let'");460 else461 var = tok->text;462463 tok = next(par);464 if (tok->type != TOK_ASSIGN)465 return error(tok->line, "Expected ':=', got '%s'", tok->text);466467 if (!(exp = expression(par)))468 return error(tok->line, "Expected expression after ':='");469470 return define(var, exp);471}472473statement*474assignstmt(parser *par)475{476 token *tok;477 expr *val;478 char *var;479480 tok = next(par);481 if (tok->type != TOK_VAR)482 return error(tok->line, "Expected variable for assigment");483 else484 var = tok->text;485486 tok = next(par);487 if (tok->type != TOK_ASSIGN)488 return error(tok->line, "Expected ':=', got '%s'",489 tok->text);490491 if (!(val = expression(par)))492 return error(tok->line, "Expected expression after ':='");493494 return assign(var, val);495}496497statement*498readstmt(parser *par)499{500 token *tok;501502 tok = next(par);503 if (tok->type != TOK_QUESTION)504 return error(tok->line, "Expected '?' got '%s'",505 tok->text);506507 tok = next(par);508 if (tok->type != TOK_VAR)509 return error(tok->line, "Expected variable after operator");510511 return newread(tok->text);512}513514statement*515writestmt(parser *par)516{517 token *tok;518 expr *val;519520 tok = next(par);521 if (tok->type != TOK_EXCLAMATION)522 return error(tok->line, "Expected '!' got '%s'",523 tok->text);524525 if (!(val = expression(par)))526 return error(tok->line, "Expected expression after operator");527528 return newwrite(val);529}530531statement*532condstmt(parser *par)533{534 statement **cmds1, **cmds2, *err;535 token *tok;536 expr *cexp;537538 tok = next(par);539 EXPTXT(tok, "if");540541 if (!(cexp = expression(par)))542 return error(tok->line, "Expected conditional expression");543544 tok = next(par);545 EXPTXT(tok, "then");546547 err = newstmt();548 cmds1 = cmdblock(par, err);549 if (cmds1 == NULL) {550 freeexpr(cexp);551 return err;552 }553554 tok = next(par);555 if (tok->type != TOK_VAR || strcmp(tok->text, "else")) {556 free(err);557 freeexpr(cexp);558 freestmts(cmds1);559 return error(tok->line, "Expected '%s', got '%s'", "else", tok->text);560 }561562 cmds2 = cmdblock(par, err);563 if (cmds2 == NULL) {564 freestmts(cmds1);565 freeexpr(cexp);566 return err;567 } else {568 free(err);569 }570571 tok = next(par);572 EXPTXT(tok, "end");573574 return newcond(cexp, cmds1, cmds2);575}576577statement*578loopstmt(parser *par)579{580 token *tok;581 statement **cmds, *err;582 expr *cexp;583584 tok = next(par);585 EXPTXT(tok, "while");586587 if (!(cexp = expression(par)))588 return error(tok->line, "Expected conditional expression");589590 tok = next(par);591 EXPTXT(tok, "do");592593 err = newstmt();594 cmds = cmdblock(par, err);595 if (cmds == NULL) {596 freeexpr(cexp);597 return err;598 } else {599 free(err);600 }601602 tok = next(par);603 EXPTXT(tok, "end");604605 return newloop(cexp, cmds);606}607608statement*609stmt(parser *par)610{611 statement *val;612 statement *(*sfuncs[])(parser *p) = {613 letstmt,614 assignstmt,615 readstmt,616 writestmt,617 condstmt,618 loopstmt,619 };620 size_t funclen = sizeof(sfuncs) / sizeof(sfuncs[0]);621622 reset(par);623 for (int i = 0; i < funclen; i++) {624 val = (*sfuncs[i])(par);625 if (val->type != STMT_ERROR)626 break;627628 if (i + 1 < funclen) {629 freestmt(val);630 backup(par);631 }632 }633634 return val;635}636637statement**638parseprog(parser *par, statement *err)639{640 token *tok;641 size_t emlen;642 statement **cmds;643644 cmds = cmdblock(par, err);645 if (cmds == NULL) {646 freestmts(cmds);647 return NULL;648 }649650 tok = peek(par);651 if (tok->type != TOK_EOF) {652 err->type = STMT_ERROR;653 err->d.error.line = tok->line;654655 if (tok->type == TOK_ERROR) {656 err->d.error.msg = estrdup(tok->text);657 } else {658 emlen = 24 + strlen(tok->text);659 err->d.error.msg = emalloc(emlen * sizeof(char*));660 snprintf(err->d.error.msg, emlen - 1,661 "Expected ';', found '%s'", tok->text);662 err->d.error.msg[emlen] = '\0';663 }664665 freestmts(cmds);666 return NULL;667 }668669 return cmds;670}