#include #include #include #include #include #include "lex.h" #include "common.h" #include "error.h" #include "logic.h" #include "gate.h" /** Static defs **************************************************************/ static FILE* fd; static struct token *cursor; static const char *filename; /** Helpers ******************************************************************/ #define EXPECT_AND_DISCARD_CRITICAL(type)\ do { \ EXPECT_CRITICAL(type) \ kerchunk(); \ } while (0); #define EXPECT_CRITICAL(type)\ do { \ if (expect(type)) { \ return 1; \ } \ } while (0); void emit(const char *fmt, ...) { va_list args; va_start(args, fmt); if (cursor) { fprintf(stderr, "%s at (%zd,%zd): ", filename, cursor->loc.line, cursor->loc.column); vfprintf(stderr, fmt, args); indicate_file_area(fd, cursor->loc.line, cursor->loc.column - cursor->loc.leading_whitespace_len, cursor->span); } else { fprintf(stderr, "%s: ", filename); vfprintf(stderr, fmt, args); } va_end(args); } static int expect(enum TOKEN_TYPE e) { const char *expected_desc = "(internal error)"; const char *observed_desc = "(internal error)"; if (!cursor || cursor->type != e) { expected_desc = get_token_description(e); if (cursor) { observed_desc = get_token_description(cursor->type); } else { observed_desc = "end of file"; } emit("Error: Expected %s, got %s\n", expected_desc, observed_desc); return 1; } return 0; } static void kerchunk() { if (cursor) { cursor = cursor->next; } } /** Parsers ******************************************************************/ int parse_bop(char *ident) { char *l = NULL; char *r = NULL; EXPECT_CRITICAL(TOK_IDENT); l = cursor->value; kerchunk(); EXPECT_CRITICAL(TOK_IDENT); r = cursor->value; kerchunk(); return gate_add(cursor->type, ident, l, r); } int parse_expr(void) { char *ident = NULL; EXPECT_AND_DISCARD_CRITICAL(TOK_EXPR); EXPECT_CRITICAL(TOK_IDENT); ident = cursor->value; kerchunk(); EXPECT_AND_DISCARD_CRITICAL(TOK_COLON); switch(cursor->type) { /* FIXME do some things */ case TOK_OR : /* fallthrough */ case TOK_AND: /* fallthrough */ case TOK_XOR: /* fallthrough */ case TOK_NOR: /* fallthrough */ case TOK_NAND: kerchunk(); parse_bop(ident); break; case TOK_NOT: kerchunk(); EXPECT_AND_DISCARD_CRITICAL(TOK_IDENT); /* FIXME don't discard */ break; default: emit("Error: Unexpected %s\n", get_token_description(cursor->type)); return 1; } return 0; } int parse(const char *fname, FILE *f, struct token *t) { fd = f; filename = fname; cursor = t; EXPECT_AND_DISCARD_CRITICAL(TOK_BEGIN); /* Eat leading EOL tokens */ while (cursor && cursor->type == TOK_EOL) { kerchunk(); } EXPECT_AND_DISCARD_CRITICAL(TOK_MODULE); EXPECT_CRITICAL(TOK_IDENT); emit("Debug: module is named %s\n", cursor->value); /* FIXME do something */ kerchunk(); EXPECT_AND_DISCARD_CRITICAL(TOK_EOL); while (cursor) { switch(cursor->type) { case TOK_EOL: kerchunk(); break; case TOK_INPUT: kerchunk(); expect(TOK_IDENT); gate_input_add(cursor->value); kerchunk(); break; case TOK_EXPR: if (parse_expr()) { return 1; } break; default: emit("Error: Unexpected %s\n", get_token_description(cursor->type)); return 1; } } return 0; }