spl

systems programming language
git clone http://frotz.net/git/spl.git
Log | Files | Refs | README | LICENSE

compiler0.c (36519B)


      1 // Copyright 2022, Brian Swetland <swetland@frotz.net>
      2 // Licensed under the Apache License, Version 2.0.
      3 
      4 #include <stdio.h>
      5 #include <stdlib.h>
      6 #include <stdarg.h>
      7 #include <stdint.h>
      8 #include <stdbool.h>
      9 #include <string.h>
     10 
     11 #include <fcntl.h>
     12 #include <unistd.h>
     13 
     14 // builtin types
     15 #define nil 0
     16 typedef uint32_t u32;
     17 typedef int32_t i32;
     18 typedef uint8_t u8;
     19 
     20 typedef uint32_t token_t;
     21 
     22 void error(const char *fmt, ...);
     23 
     24 // ------------------------------------------------------------------
     25 // structures
     26 
     27 typedef struct String String;
     28 typedef struct Symbol Symbol;
     29 typedef struct Scope Scope;
     30 typedef struct Type Type;
     31 
     32 struct String {
     33 	String *next;
     34 	u32 len;
     35 	char text[0];
     36 };
     37 
     38 struct Symbol {
     39 	Symbol *next;
     40 	String *name;
     41 	Type *type;
     42 	u32 kind;
     43 };
     44 enum {
     45 	SYMBOL_VAR,
     46 	SYMBOL_FLD, // struct field
     47 	SYMBOL_PTR, // struct *field
     48 	SYMBOL_DEF, // enum
     49 	SYMBOL_FN,
     50 };
     51 
     52 struct Scope {
     53 	Scope *parent;
     54 	Symbol *first;
     55 	Symbol *last;
     56 	u32 kind;
     57 };
     58 enum {
     59 	SCOPE_GLOBAL,
     60 	SCOPE_FUNC,
     61 	SCOPE_BLOCK,
     62 	SCOPE_LOOP,
     63 	SCOPE_STRUCT,
     64 };
     65 
     66 struct Type {
     67 	Type *next;
     68 	String *name;
     69 	Type *of;        // for: slice, array, ptr
     70 	Symbol *fields;  // for: struct
     71 	u32 kind;
     72 	u32 count;       // for: arrays
     73 };
     74 enum {
     75 	TYPE_VOID,
     76 	TYPE_BOOL,
     77 	TYPE_U8,
     78 	TYPE_U32,
     79 //	TYPE_NIL,
     80 //	TYPE_POINTER,
     81 	TYPE_ARRAY,
     82 	TYPE_SLICE,
     83 	TYPE_STR,
     84 	TYPE_STRUCT,
     85 //	TYPE_FUNC,
     86 	TYPE_ENUM,
     87 	TYPE_UNDEFINED,
     88 };
     89 
     90 typedef struct Ctx Ctx;
     91 
     92 // ------------------------------------------------------------------
     93 // compiler global context
     94 
     95 struct Ctx {
     96 	const char* filename;  // filename of active source
     97 	const char* outname;   // base name for output files
     98 	int fd;
     99 
    100 	FILE *fp_decl;         // output files
    101 	FILE *fp_type;
    102 	FILE *fp_impl;
    103 
    104 	int nl_decl;           // flag to update #line
    105 	int nl_type;
    106 	int nl_impl;
    107 
    108 	u8 iobuffer[1024];     // scanner file io buffer
    109 	u32 ionext;
    110 	u32 iolast;
    111 
    112 	u32 linenumber;        // line number of most recent line
    113 	u32 lineoffset;        // position of start of most recent line
    114 	u32 byteoffset;        // position of the most recent character
    115 	u32 flags;
    116 	u32 cc;                // scanner: next character
    117 
    118 	token_t tok;           // most recent token
    119 	u32 num;               // used for tNUM
    120 	char tmp[256];         // used for tIDN, tSTR;
    121 	String *ident;         // used for tIDN
    122 
    123 	String *stringlist;    // all strings
    124 	Type *typelist;        // all types
    125 
    126 	Scope *scope;          // scope stack
    127 	Scope *fn;             // args of active function being parsed
    128 
    129 	Scope global;
    130 
    131 	String *idn_if;        // identifier strings
    132 	String *idn_fn;
    133 	String *idn_for;
    134 	String *idn_var;
    135 	String *idn_nil;
    136 	String *idn_new;
    137 	String *idn_case;
    138 	String *idn_else;
    139 	String *idn_enum;
    140 	String *idn_true;
    141 	String *idn_break;
    142 	String *idn_while;
    143 	String *idn_false;
    144 	String *idn_switch;
    145 	String *idn_struct;
    146 	String *idn_return;
    147 	String *idn_continue;
    148 
    149 	Type *type_void;       // base types
    150 	Type *type_bool;
    151 	Type *type_str;
    152 	Type *type_u32;
    153 	Type *type_i32;
    154 	Type *type_u8;
    155 
    156 	char *outptr;
    157 	char outbuf[4096];
    158 };
    159 
    160 Ctx ctx;
    161 
    162 // ------------------------------------------------------------------
    163 
    164 String *string_make(const char* text, u32 len) {
    165 	// obviously this wants to be a hash table
    166 	String *str = ctx.stringlist;
    167 	while (str != nil) {
    168 		if ((str->len == len) && (memcmp(text, str->text, len) == 0)) {
    169 			return str;
    170 		}
    171 		str = str->next;
    172 	}
    173 
    174 	str = malloc(sizeof(String) + len + 1);
    175 	str->len = len;
    176 	memcpy(str->text, text, len);
    177 	str->text[len] = 0;
    178 	str->next = ctx.stringlist;
    179 	ctx.stringlist = str;
    180 
    181 	return str;
    182 }
    183 
    184 Scope *scope_push(u32 kind) {
    185 	Scope *scope = malloc(sizeof(Scope));
    186 	scope->first = nil;
    187 	scope->last = nil;
    188 	scope->parent = ctx.scope;
    189 	scope->kind = kind;
    190 	ctx.scope = scope;
    191 	return scope;
    192 }
    193 
    194 Scope *scope_pop(void) {
    195 	Scope *scope = ctx.scope;
    196 	ctx.scope = scope->parent;
    197 	return scope;
    198 }
    199 
    200 Scope *scope_find(u32 scope_kind) {
    201 	Scope *scope = ctx.scope;
    202 	while (scope != nil) {
    203 		if (scope->kind == scope_kind) {
    204 			return scope;
    205 		}
    206 		scope = scope->parent;
    207 	}
    208 	return nil;
    209 }
    210 
    211 Symbol *symbol_find_in(String *name, Scope *scope) {
    212 	for (Symbol *sym = scope->first; sym != nil; sym = sym->next) {
    213 		if (sym->name == name) {
    214 			return sym;
    215 		}
    216 	}
    217 	return nil;
    218 }
    219 
    220 // find the first surrounding scope of a specified kind
    221 Symbol *symbol_find(String *name) {
    222 	for (Scope *scope = ctx.scope; scope != nil; scope = scope->parent) {
    223 		Symbol *sym = symbol_find_in(name, scope);
    224 		if (sym != nil) {
    225 			return sym;
    226 		}
    227 	}
    228 	return nil;
    229 }
    230 
    231 Symbol *symbol_make_in_scope(String *name, Type *type, Scope *scope) {
    232 	Symbol *sym = malloc(sizeof(Symbol));
    233 	sym->name = name;
    234 	sym->type = type;
    235 	sym->next = nil;
    236 	sym->kind = SYMBOL_VAR;
    237 	if (scope->first == nil) {
    238 		scope->first = sym;
    239 	} else {
    240 		scope->last->next = sym;
    241 	}
    242 	scope->last = sym;
    243 	return sym;
    244 }
    245 
    246 Symbol *symbol_make_global(String *name, Type *type) {
    247 	return symbol_make_in_scope(name, type, &ctx.global);
    248 }
    249 
    250 Symbol *symbol_make(String *name, Type *type) {
    251 	return symbol_make_in_scope(name, type, ctx.scope);
    252 }
    253 
    254 Type *type_make(String *name, u32 kind, Type *of, Symbol *fields, u32 count) {
    255 	Type *type = malloc(sizeof(Type));
    256 	type->name = name;
    257 	type->of = of;
    258 	type->fields = fields;
    259 	type->kind = kind;
    260 	type->count = count;
    261 	if (name != nil) {
    262 		type->next = ctx.typelist;
    263 		ctx.typelist = type;
    264 	} else {
    265 		type->next = nil;
    266 	}
    267 	return type;
    268 }
    269 
    270 Type *type_find(String *name) {
    271 	for (Type *t = ctx.typelist; t != nil; t = t->next) {
    272 		if (t->name == name) {
    273 			return t;
    274 		}
    275 	}
    276 	return nil;
    277 }
    278 
    279 Symbol *type_find_field(Type *type, String *name) {
    280 	if (type->kind != TYPE_STRUCT) {
    281 		error("not a struct");
    282 	}
    283 	for (Symbol *s = type->fields; s != nil; s = s->next) {
    284 		if (s->name == name) {
    285 			return s;
    286 		}
    287 	}
    288 	error("struct has no such field '%s'", name->text);
    289 	return nil;
    290 }
    291 
    292 // ================================================================
    293 
    294 enum {
    295 	cfVisibleEOL   = 1,
    296 	cfAbortOnError = 2,
    297 	cfTraceCodeGen = 3,
    298 };
    299 
    300 void ctx_init() {
    301 	memset(&ctx, 0, sizeof(ctx));
    302 
    303 	// pre-intern keywords
    304 	ctx.idn_if       = string_make("if", 2);
    305 	ctx.idn_fn       = string_make("fn", 2);
    306 	ctx.idn_for      = string_make("for", 3);
    307 	ctx.idn_var      = string_make("var", 3);
    308 	ctx.idn_nil      = string_make("nil", 3);
    309 	ctx.idn_new      = string_make("new", 3);
    310 	ctx.idn_case     = string_make("case", 4);
    311 	ctx.idn_else     = string_make("else", 4);
    312 	ctx.idn_enum     = string_make("enum", 4);
    313 	ctx.idn_true     = string_make("true", 4);
    314 	ctx.idn_break    = string_make("break", 5);
    315 	ctx.idn_while    = string_make("while", 5);
    316 	ctx.idn_false    = string_make("false", 5);
    317 	ctx.idn_switch   = string_make("switch", 6);
    318 	ctx.idn_struct   = string_make("struct", 6);
    319 	ctx.idn_return   = string_make("return", 6);
    320 	ctx.idn_continue = string_make("continue", 8);
    321 
    322 	ctx.type_void    = type_make(string_make("void", 4), TYPE_VOID, nil, nil, 0);
    323 	ctx.type_bool    = type_make(string_make("bool", 4), TYPE_BOOL, nil, nil, 0);
    324 	ctx.type_str     = type_make(string_make("str", 3), TYPE_STR, nil, nil, 0);
    325 	ctx.type_u32     = type_make(string_make("u32", 3), TYPE_U32, nil, nil, 0);
    326 	ctx.type_i32     = type_make(string_make("i32", 3), TYPE_U32, nil, nil, 0);
    327 	ctx.type_u8      = type_make(string_make("u8", 2), TYPE_U8, nil, nil, 0);
    328 
    329 	ctx.scope = &(ctx.global);
    330 
    331 	ctx.outptr = ctx.outbuf;
    332 }
    333 
    334 void dump_file_line(const char* fn, u32 offset);
    335 void dump_error_ctxt();
    336 
    337 void error(const char *fmt, ...) {
    338 	va_list ap;
    339 
    340 	fprintf(stderr,"\n%s:%d: ", ctx.filename, ctx.linenumber);
    341 	va_start(ap, fmt);
    342 	vfprintf(stderr, fmt, ap);
    343 	va_end(ap);
    344 
    345 	if (ctx.linenumber > 0) {
    346 		// dump_file_line(ctx.filename, ctx.lineoffset);
    347 	}
    348 	fprintf(stderr, "\n");
    349 
    350 #if 0
    351 	dump_error_ctxt();
    352 #endif
    353 
    354 	if (ctx.flags & cfAbortOnError) {
    355 		abort();
    356 	} else {
    357 		exit(1);
    358 	}
    359 }
    360 
    361 #define DECL ctx.fp_decl
    362 #define TYPE ctx.fp_type
    363 #define IMPL ctx.fp_impl
    364 
    365 void emit(FILE* fp, const char *fmt, ...) {
    366 	va_list ap;
    367 	va_start(ap, fmt);
    368 	vfprintf(fp, fmt, ap);
    369 	va_end(ap);
    370 }
    371 
    372 int indent = 0;
    373 
    374 void emit_impl(const char *fmt, ...) {
    375 	va_list ap;
    376 	va_start(ap, fmt);
    377 	int n = vsnprintf(ctx.outptr, sizeof(ctx.outbuf) - (ctx.outptr - ctx.outbuf), fmt, ap);
    378 	va_end(ap);
    379 	ctx.outptr += n;
    380 	if (fmt[strlen(fmt) - 1] == '\n') {
    381 		unsigned len = ctx.outptr - ctx.outbuf;
    382 		// any }s reduce the indent level of the current line
    383 		for (unsigned n = 0; n < len; n++) {
    384 			if (ctx.outbuf[n] == '}') indent--;
    385 		}
    386 		for (int n = 0; n < indent; n++) {
    387 			fwrite("    ", 1, 4, ctx.fp_impl);
    388 		}
    389 		fwrite(ctx.outbuf, 1, len, ctx.fp_impl);
    390 		// any {s increase the indent level of the next line
    391 		for (unsigned n = 0; n < len; n++) {
    392 			if (ctx.outbuf[n] == '{') indent++;
    393 		}
    394 		ctx.outptr = ctx.outbuf;
    395 		ctx.outbuf[0] = 0;
    396 	}
    397 }
    398 
    399 void emit_impl_str(void) {
    400 	u32 n = 0;
    401 	emit_impl("(void*) \"");
    402 	while (n < 256) {
    403 		u32 ch = ctx.tmp[n];
    404 		if (ch == 0) {
    405 			break;
    406 		} else if ((ch < ' ') || (ch > '~') || (ch == '"') || (ch == '\\')) {
    407 			emit_impl("\\x%02x", ch);
    408 		} else {
    409 			emit_impl("%c", ch);
    410 		}
    411 		n++;
    412 	}
    413 	emit_impl("\"");
    414 }
    415 
    416 #define emit_decl(fmt...) emit(DECL, fmt)
    417 #define emit_type(fmt...) emit(TYPE, fmt)
    418 
    419 #define KEEP_PARENS 0x10000
    420 
    421 unsigned emit_impl_oparen(void) {
    422 	unsigned idx = ctx.outptr - ctx.outbuf;
    423 	*ctx.outptr++ = '(';
    424 	*ctx.outptr = 0;
    425 	return idx;
    426 }
    427 
    428 void emit_impl_cparen(unsigned idx) {
    429 	if (idx & KEEP_PARENS) {
    430 		*ctx.outptr++ = ')';
    431 		*ctx.outptr = 0;
    432 	} else {
    433 		unsigned len = ctx.outptr - ctx.outbuf;
    434 		idx &= 0xFFFF;
    435 		memmove(ctx.outbuf + idx, ctx.outbuf + idx + 1, len - idx);
    436 		ctx.outptr--;
    437 	}
    438 }
    439 
    440 void ctx_open_source(const char* filename) {
    441 	ctx.filename = filename;
    442 	ctx.linenumber = 0;
    443 
    444 	if (ctx.fd >= 0) {
    445 		close(ctx.fd);
    446 	}
    447 	ctx.fd = open(filename, O_RDONLY);
    448 	if (ctx.fd < 0) {
    449 		error("cannot open file '%s'", filename);
    450 	}
    451 	ctx.ionext = 0;
    452 	ctx.iolast = 0;
    453 	ctx.linenumber = 1;
    454 	ctx.lineoffset = 0;
    455 	ctx.byteoffset = 0;
    456 }
    457 
    458 void ctx_open_output(void) {
    459 	char tmp[1024];
    460 	ctx.nl_decl = 1;
    461 	ctx.nl_type = 1;
    462 	ctx.nl_impl = 1;
    463 
    464 	sprintf(tmp, "%s.decl.h", ctx.outname);
    465 	if ((ctx.fp_decl = fopen(tmp, "w")) == NULL) {
    466 		error("cannot open output '%s'", tmp);
    467 	}
    468 
    469 	sprintf(tmp, "%s.type.h", ctx.outname);
    470 	if ((ctx.fp_type = fopen(tmp, "w")) == NULL) {
    471 		error("cannot open output '%s'", tmp);
    472 	}
    473 
    474 	sprintf(tmp, "%s.impl.c", ctx.outname);
    475 	if ((ctx.fp_impl = fopen(tmp, "w")) == NULL) {
    476 		error("cannot open output '%s'", tmp);
    477 	}
    478 
    479 	emit_impl("#include <builtin.type.h>\n");
    480 	emit_impl("#include \"%s.type.h\"\n", ctx.outname);
    481 	emit_impl("#include \"%s.decl.h\"\n", ctx.outname);
    482 }
    483 
    484 
    485 // ================================================================
    486 // lexical scanner
    487 
    488 // token classes (tok & tcMASK)
    489 enum {
    490 	tcRELOP = 0x08, tcADDOP = 0x10, tcMULOP = 0x18,
    491 	tcAEQOP = 0x20, tcMEQOP = 0x28, tcMASK = 0xF8,
    492 };
    493 
    494 enum {
    495 	// EndMarks, Braces, Brackets Parens
    496 	tEOF, tEOL, tOBRACE, tCBRACE, tOBRACK, tCBRACK, tOPAREN, tCPAREN,
    497 	// RelOps (do not reorder)
    498 	tEQ, tNE, tLT, tLE, tGT, tGE, tx0E, tx0F,
    499 	// AddOps (do not reorder)
    500 	tPLUS, tMINUS, tPIPE, tCARET, tx14, tx15, tx16, tx17,
    501 	// MulOps (do not reorder)
    502 	tSTAR, tSLASH, tPERCENT, tAMP, tLEFT, tRIGHT, tx1E, tx1F,
    503 	// AsnOps (do not reorder)
    504 	tADDEQ, tSUBEQ, tOREQ, tXOREQ, tx24, tx25, tx26, tx27,
    505 	tMULEQ, tDIVEQ, tMODEQ, tANDEQ, tLSEQ, tRSEQ, t2E, t2F,
    506 	// Various, UnaryNot, LogicalOps,
    507 	tSEMI, tCOLON, tDOT, tCOMMA, tNOT, tAND, tOR, tBANG,
    508 	tASSIGN, tINC, tDEC,
    509 	tAT,
    510 	// Keywords
    511 	tNEW, tFN, tSTRUCT, tVAR, tENUM,
    512 	tIF, tELSE, tWHILE,
    513 	tBREAK, tCONTINUE, tRETURN,
    514 	tFOR, tSWITCH, tCASE,
    515 	tTRUE, tFALSE, tNIL,
    516 	tIDN, tNUM, tSTR,
    517 	// used internal to the lexer but never returned
    518 	tSPC, tINV, tDQT, tSQT, tMSC,
    519 };
    520 
    521 const char *tnames[] = {
    522 	"<EOF>", "<EOL>", "{",  "}",  "[",   "]",   "(",   ")",
    523 	"==",    "!=",    "<",  "<=", ">",   ">=",  "",    "",
    524 	"+",     "-",     "|",  "^",  "",    "",    "",    "",
    525 	"*",     "/",     "%",  "&",  "<<",  ">>",  "",    "",
    526 	"+=",    "-=",    "|=", "^=", "",    "",    "",    "",
    527 	"*=",    "/=",    "%=", "&=", "<<=", ">>=", "",    "",
    528 	";",     ":",     ".",  ",",  "~",   "&&",  "||",  "!",
    529 	"=",     "++",    "--",
    530 	"@",
    531 	"new", "fn", "struct", "var", "enum",
    532 	"if", "else", "while",
    533 	"break", "continue", "return",
    534 	"for", "switch", "case",
    535 	"true", "false", "nil",
    536 	"<ID>", "<NUM>", "<STR>",
    537 	"<SPC>", "<INV>", "<DQT>", "<SQT>", "<MSC>",
    538 };
    539 
    540 u8 lextab[256] = {
    541 	tEOF, tINV, tINV, tINV, tINV, tINV, tINV, tINV,
    542 	tINV, tSPC, tEOL, tSPC, tINV, tSPC, tINV, tINV,
    543 	tINV, tINV, tINV, tINV, tINV, tINV, tINV, tINV,
    544 	tINV, tINV, tINV, tINV, tINV, tINV, tINV, tINV,
    545 	tSPC, tBANG, tDQT, tMSC, tMSC, tPERCENT, tAMP, tSQT,
    546 	tOPAREN, tCPAREN, tSTAR, tPLUS, tCOMMA, tMINUS, tDOT, tSLASH,
    547 	tNUM, tNUM, tNUM, tNUM, tNUM, tNUM, tNUM, tNUM,
    548 	tNUM, tNUM, tCOLON, tSEMI, tLT, tASSIGN, tGT, tMSC,
    549 	tAT,  tIDN, tIDN, tIDN, tIDN, tIDN, tIDN, tIDN,
    550 	tIDN, tIDN, tIDN, tIDN, tIDN, tIDN, tIDN, tIDN,
    551 	tIDN, tIDN, tIDN, tIDN, tIDN, tIDN, tIDN, tIDN,
    552 	tIDN, tIDN, tIDN, tOBRACK, tMSC, tCBRACK, tCARET, tIDN,
    553 	tMSC, tIDN, tIDN, tIDN, tIDN, tIDN, tIDN, tIDN,
    554 	tIDN, tIDN, tIDN, tIDN, tIDN, tIDN, tIDN, tIDN,
    555 	tIDN, tIDN, tIDN, tIDN, tIDN, tIDN, tIDN, tIDN,
    556 	tIDN, tIDN, tIDN, tOBRACE, tPIPE, tCBRACE, tNOT, tINV,
    557 	tINV, tINV, tINV, tINV, tINV, tINV, tINV, tINV,
    558 	tINV, tINV, tINV, tINV, tINV, tINV, tINV, tINV,
    559 	tINV, tINV, tINV, tINV, tINV, tINV, tINV, tINV,
    560 	tINV, tINV, tINV, tINV, tINV, tINV, tINV, tINV,
    561 	tINV, tINV, tINV, tINV, tINV, tINV, tINV, tINV,
    562 	tINV, tINV, tINV, tINV, tINV, tINV, tINV, tINV,
    563 	tINV, tINV, tINV, tINV, tINV, tINV, tINV, tINV,
    564 	tINV, tINV, tINV, tINV, tINV, tINV, tINV, tINV,
    565 	tINV, tINV, tINV, tINV, tINV, tINV, tINV, tINV,
    566 	tINV, tINV, tINV, tINV, tINV, tINV, tINV, tINV,
    567 	tINV, tINV, tINV, tINV, tINV, tINV, tINV, tINV,
    568 	tINV, tINV, tINV, tINV, tINV, tINV, tINV, tINV,
    569 	tINV, tINV, tINV, tINV, tINV, tINV, tINV, tINV,
    570 	tINV, tINV, tINV, tINV, tINV, tINV, tINV, tINV,
    571 	tINV, tINV, tINV, tINV, tINV, tINV, tINV, tINV,
    572 	tINV, tINV, tINV, tINV, tINV, tINV, tINV, tINV,
    573 };
    574 
    575 i32 unhex(u32 ch) {
    576 	if ((ch >= '0') && (ch <= '9')) {
    577 		return ch - '0';
    578 	}
    579 	if ((ch >= 'a') && (ch <= 'f')) {
    580 		return ch - 'a' + 10;
    581 	}
    582 	if ((ch >= 'A') && (ch <= 'F')) {
    583 		return ch - 'A' + 10;
    584 	}
    585 	return -1;
    586 }
    587 
    588 u32 scan() {
    589 	while (ctx.ionext == ctx.iolast) {
    590 		if (ctx.fd < 0) {
    591 			ctx.cc = 0;
    592 			return ctx.cc;
    593 		}
    594 		int r = read(ctx.fd, ctx.iobuffer, sizeof(ctx.iobuffer));
    595 		if (r <= 0) {
    596 			ctx.fd = -1;
    597 		} else {
    598 			ctx.iolast = r;
    599 			ctx.ionext = 0;
    600 		}
    601 	}
    602 	ctx.cc = ctx.iobuffer[ctx.ionext];
    603 	ctx.ionext++;
    604 	ctx.byteoffset++;
    605 	return ctx.cc;
    606 }
    607 
    608 u32 unescape(u32 n) {
    609 	if (n == 'n') {
    610 		return 10;
    611 	} else if (n == 'r') {
    612 		return 13;
    613 	} else if (n == 't') {
    614 		return 9;
    615 	} else if (n == '"') {
    616 		return '"';
    617 	} else if (n == '\'') {
    618 		return '\'';
    619 	} else if (n == '\\') {
    620 		return '\\';
    621 	} else if (n == 'x') {
    622 		int x0 = unhex(scan());
    623 		int x1 = unhex(scan());
    624 		if ((x0 < 0) || (x1 < 0)) {
    625 			error("invalid hex escape");
    626 		}
    627 		return (x0 << 4) | x1;
    628 	} else {
    629 		error("invalid escape 0x%02x", n);
    630 		return 0;
    631 	}
    632 }
    633 
    634 token_t scan_string(u32 cc, u32 nc) {
    635 	u32 n = 0;
    636 	while (true) {
    637 		if (nc == '"') {
    638 			nc = scan();
    639 			break;
    640 		} else if (nc == 0) {
    641 			error("unterminated string");
    642 		} else if (nc == '\\') {
    643 			ctx.tmp[n] = unescape(scan());
    644 		} else {
    645 			ctx.tmp[n] = nc;
    646 		}
    647 		nc = scan();
    648 		n++;
    649 		if (n == 255) {
    650 			error("constant string too large");
    651 		}
    652 	}
    653 	ctx.tmp[n] = 0;
    654 	return tSTR;
    655 }
    656 
    657 token_t scan_keyword(u32 len) {
    658 	ctx.tmp[len] = 0;
    659 	String *idn = string_make(ctx.tmp, len);
    660 	ctx.ident = idn;
    661 
    662 	if (len == 2) {
    663 		if (idn == ctx.idn_if) { return tIF; };
    664 		if (idn == ctx.idn_fn) { return tFN; }
    665 	} else if (len == 3) {
    666 		if (idn == ctx.idn_for) { return tFOR; }
    667 		if (idn == ctx.idn_var) { return tVAR; }
    668 		if (idn == ctx.idn_nil) { return tNIL; }
    669 		if (idn == ctx.idn_new) { return tNEW; }
    670 	} else if (len == 4) {
    671 		if (idn == ctx.idn_case) { return tCASE; }
    672 		if (idn == ctx.idn_else) { return tELSE; }
    673 		if (idn == ctx.idn_enum) { return tENUM; }
    674 		if (idn == ctx.idn_true) { return tTRUE; }
    675 	} else if (len == 5) {
    676 		if (idn == ctx.idn_break) { return tBREAK; }
    677 		if (idn == ctx.idn_while) { return tWHILE; }
    678 		if (idn == ctx.idn_false) { return tFALSE; }
    679 	} else if (len == 6) {
    680 		if (idn == ctx.idn_switch) { return tSWITCH; }
    681 		if (idn == ctx.idn_struct) { return tSTRUCT; }
    682 		if (idn == ctx.idn_return) { return tRETURN; }
    683 	} else if (len == 8) {
    684 		if (idn == ctx.idn_continue) { return tCONTINUE; }
    685 	}
    686 	return tIDN;
    687 }
    688 
    689 token_t scan_number(u32 cc, u32 nc) {
    690 	u32 n = 1;
    691 	u32 val = cc - '0';
    692 
    693 	if ((cc == '0') && (nc == 'b')) { // binary
    694 		nc = scan();
    695 		while ((nc == '0') || (nc == '1')) {
    696 			val = (val << 1) | (nc - '0');
    697 			nc = scan();
    698 			n++;
    699 			if (n == 34) {
    700 				error("binary constant too large");
    701 			}
    702 		}
    703 	} else if ((cc == '0') && (nc == 'x')) { // hex
    704 		nc = scan();
    705 		while (true) {
    706 			int tmp = unhex(nc);
    707 			if (tmp == -1) {
    708 				break;
    709 			}
    710 			val = (val << 4) | tmp;
    711 			nc = scan();
    712 			n++;
    713 			if (n == 10) {
    714 				error("hex constant too large");
    715 			}
    716 		}
    717 	} else { // decimal
    718 		while (lextab[nc] == tNUM) {
    719 			u32 tmp = (val * 10) + (nc - '0');
    720 			if (tmp <= val) {
    721 				error("decimal constant too large");
    722 			}
    723 			val = tmp;
    724 			nc = scan();
    725 			n++;
    726 		}
    727 	}
    728 	ctx.num = val;
    729 	return tNUM;
    730 }
    731 
    732 token_t scan_ident(u32 cc, u32 nc) {
    733 	ctx.tmp[0] = cc;
    734 	u32 n = 1;
    735 
    736 	while (true) {
    737 		u32 tok = lextab[nc];
    738 		if ((tok == tIDN) || (tok == tNUM)) {
    739 			ctx.tmp[n] = nc;
    740 			n++;
    741 			if (n == 32) { error("identifier too large"); }
    742 			nc = scan();
    743 		} else {
    744 			break;
    745 		}
    746 	}
    747 	return scan_keyword(n);
    748 }
    749 
    750 token_t _next() {
    751 	u8 nc = ctx.cc;
    752 	while (true) {
    753 		u8 cc = nc;
    754 		nc = scan();
    755 		u32 tok = lextab[cc];
    756 		if (tok == tNUM) { // 0..9
    757 			return scan_number(cc, nc);
    758 		} else if (tok == tIDN) { // _ A..Z a..z
    759 			return scan_ident(cc, nc);
    760 		} else if (tok == tDQT) { // "
    761 			return scan_string(cc, nc);
    762 		} else if (tok == tSQT) { // '
    763 			ctx.num = nc;
    764 			if (nc == '\\') {
    765 				ctx.num = unescape(scan());
    766 			}
    767 			nc = scan();
    768 			if (nc != '\'') {
    769 				error("unterminated character constant");
    770 			}
    771 			nc = scan();
    772 			return tNUM;
    773 		} else if (tok == tPLUS) {
    774 			if (nc == '+') { tok = tINC; nc = scan(); }
    775 		} else if (tok == tMINUS) {
    776 			if (nc == '-') { tok = tDEC; nc = scan(); }
    777 		} else if (tok == tAMP) {
    778 			if (nc == '&') { tok = tAND; nc = scan(); }
    779 		} else if (tok == tPIPE) {
    780 			if (nc == '|') { tok = tOR; nc = scan(); }
    781 		} else if (tok == tGT) {
    782 			if (nc == '=') { tok = tGE; nc = scan(); }
    783 			else if (nc == '>') { tok = tRIGHT; nc = scan(); }
    784 		} else if (tok == tLT) {
    785 			if (nc == '=') { tok = tLE; nc = scan(); }
    786 			else if (nc == '<') { tok = tLEFT; nc = scan(); }
    787 		} else if (tok == tASSIGN) {
    788 			if (nc == '=') { tok = tEQ; nc = scan(); }
    789 		} else if (tok == tBANG) {
    790 			if (nc == '=') { tok = tNE; nc = scan(); }
    791 		} else if (tok == tSLASH) {
    792 			if (nc == '/') {
    793 				// comment -- consume until EOL or EOF
    794 				while ((nc != '\n') && (nc != 0)) {
    795 					nc = scan();
    796 				}
    797 				continue;
    798 			}
    799 		} else if (tok == tEOL) {
    800 			ctx.linenumber++;
    801 			ctx.lineoffset = ctx.byteoffset;
    802 			if (ctx.flags & cfVisibleEOL) {
    803 				return tEOL;
    804 			}
    805 			continue;
    806 		} else if (tok == tSPC) {
    807 			continue;
    808 		} else if ((tok == tMSC) || (tok == tINV)) {
    809 			error("unknown character 0x%02x", cc);
    810 		}
    811 
    812 		// if we're an AddOp or MulOp, followed by an '='
    813 		if (((tok & 0xF0) == 0x10) && (nc == '=')) {
    814 			nc = scan();
    815 			// transform us to a XEQ operation
    816 			tok = tok + 0x10;
    817 		}
    818 
    819 		return tok;
    820 	}
    821 }
    822 
    823 void token_printstr(FILE *fp) {
    824 	u32 n = 0;
    825 	printf("\"");
    826 	while (n < 256) {
    827 		u32 ch = ctx.tmp[n];
    828 		if (ch == 0) {
    829 			break;
    830 		} else if ((ch < ' ') || (ch > '~')) {
    831 			fprintf(fp, "\\x%02x", ch);
    832 		} else if ((ch == '"') || (ch == '\\')) {
    833 			fprintf(fp, "\\%c", ch);
    834 		} else {
    835 			fprintf(fp, "%c", ch);
    836 		}
    837 		n++;
    838 	}
    839 	printf("\"");
    840 }
    841 
    842 void token_print(FILE *fp) {
    843 	if (ctx.tok == tNUM) {
    844 		fprintf(fp, "#%u ", ctx.num);
    845 	} else if (ctx.tok == tIDN) {
    846 		fprintf(fp, "@%s ", ctx.tmp);
    847 	} else if (ctx.tok == tEOL) {
    848 		fprintf(fp, "\n");
    849 	} else if (ctx.tok == tSTR) {
    850 		token_printstr(fp);
    851 	} else {
    852 		fprintf(fp, "%s ", tnames[ctx.tok]);
    853 	}
    854 }
    855 
    856 token_t next() {
    857 #if 1
    858 	return (ctx.tok = _next());
    859 #else
    860 	ctx.tok = _next();
    861 	token_print(stderr);
    862 	fprintf(stderr,"\n");
    863 	return ctx.tok;
    864 #endif
    865 }
    866 
    867 void expected(const char* what) {
    868 	error("expected %s, found %s", what, tnames[ctx.tok]);
    869 }
    870 
    871 void expect(token_t tok) {
    872 	if (ctx.tok != tok) {
    873 		error("expected %s, found %s", tnames[tok], tnames[ctx.tok]);
    874 	}
    875 }
    876 
    877 void require(token_t tok) {
    878 	expect(tok);
    879 	next();
    880 }
    881 
    882 String *parse_name(const char* what) {
    883 	if (ctx.tok != tIDN) {
    884 		error("expected %s, found %s %u", what, tnames[ctx.tok], ctx.tok);
    885 	}
    886 	String *str = ctx.ident;
    887 	next();
    888 	return str;
    889 }
    890 
    891 void parse_expr(void);
    892 
    893 // fwd_ref_ok indicates that an undefined typename
    894 // may be treated as a forward reference.  This is
    895 // only used for pointers (because their size does
    896 // not depend on their target).
    897 Type *parse_type(bool fwd_ref_ok);
    898 
    899 int is_type(const char* typename) {
    900 	String *name = ctx.ident;
    901 	Symbol *sym = symbol_find(name);
    902 	if (sym == nil) {
    903 		error("undefined identifier '%s'", name->text);
    904 	}
    905 	return !strcmp(sym->type->name->text, typename);
    906 }
    907 
    908 // cheesy varargs for a few special purpose functions
    909 void parse_va_call(const char* fn) {
    910 	emit_impl("({ int fd = fn_%s_begin();", fn);
    911 	while (ctx.tok != tCPAREN) {
    912 		if (ctx.tok == tAT) {
    913 			next();
    914 			Type *type = parse_type(false);
    915 			if (type == ctx.type_str) {
    916 				emit_impl(" fn_writes(fd,");
    917 			} else if (type == ctx.type_u32) {
    918 				emit_impl(" fn_writex(fd,");
    919 			} else if (type == ctx.type_i32) {
    920 				emit_impl(" fn_writei(fd,");
    921 			} else {
    922 				error("unsupported type '%s'", type->name->text);
    923 			}
    924 		} else if (ctx.tok == tSTR) {
    925 			emit_impl(" fn_writes(fd,");
    926 		} else if (ctx.tok == tIDN) {
    927 			emit_impl(" fn_write%s(fd,", is_type("str") ? "s" : "x");
    928 		} else {
    929 			emit_impl(" fn_writex(fd,");
    930 		}
    931 		parse_expr();
    932 		emit_impl(");");
    933 		if (ctx.tok != tCPAREN) {
    934 			require(tCOMMA);
    935 		}
    936 	}
    937 	next();
    938 	emit_impl(" fn_%s_end(); })", fn);
    939 }
    940 
    941 void parse_ident(void) {
    942 	String *name = ctx.ident;
    943 	Symbol *sym = symbol_find(name);
    944 	next();
    945 
    946 	if ((sym == nil) && (ctx.tok != tOPAREN)) {
    947 		error("undefined identifier '%s'", name->text);
    948 	}
    949 
    950 	if (ctx.tok == tOPAREN) {
    951 		// function call
    952 		next();
    953 		if (!strcmp(name->text, "error")) {
    954 			parse_va_call("error");
    955 			return;
    956 		}
    957 		emit_impl("fn_%s(", name->text);
    958 		while (ctx.tok != tCPAREN) {
    959 			parse_expr();
    960 			if (ctx.tok != tCPAREN) {
    961 				require(tCOMMA);
    962 				emit_impl(", ");
    963 			}
    964 		}
    965 		next();
    966 		emit_impl(")");
    967 	} else {
    968 		// variable access
    969 		if (sym->kind == SYMBOL_DEF) {
    970 			emit_impl("c$%s", sym->name->text);
    971 		} else {
    972 			emit_impl("$%s", sym->name->text);
    973 		}
    974 	}
    975 
    976 	while (1) {
    977 		if (ctx.tok == tDOT) {
    978 			// field access
    979 			next();
    980 			String *fieldname = parse_name("field name");
    981 			emit_impl("->%s", fieldname->text);
    982 		} else if (ctx.tok == tOBRACK) {
    983 			// array access
    984 			next();
    985 			emit_impl("[");
    986 			parse_expr();
    987 			emit_impl("]");
    988 			require(tCBRACK);
    989 		} else {
    990 			return;
    991 		}
    992 	}
    993 }
    994 
    995 void parse_primary_expr(void) {
    996 	if (ctx.tok == tNUM) {
    997 		emit_impl("0x%x", ctx.num);
    998 	} else if (ctx.tok == tSTR) {
    999 		emit_impl_str();
   1000 	} else if (ctx.tok == tTRUE) {
   1001 		emit_impl("1");
   1002 	} else if (ctx.tok == tFALSE) {
   1003 		emit_impl("0");
   1004 	} else if (ctx.tok == tNIL) {
   1005 		emit_impl("0");
   1006 	} else if (ctx.tok == tOPAREN) {
   1007 		next();
   1008 		parse_expr();
   1009 		require(tCPAREN);
   1010 		return;
   1011 	} else if (ctx.tok == tNEW) {
   1012 		next();
   1013 		require(tOPAREN);
   1014 		String *typename = parse_name("type name");
   1015 		require(tCPAREN);
   1016 		emit_impl("calloc(1,sizeof(t$%s))", typename->text);
   1017 		return;
   1018 	} else if (ctx.tok == tIDN) {
   1019 		parse_ident();
   1020 		return;
   1021 	} else {
   1022 		error("invalid expression");
   1023 	}
   1024 	next();
   1025 }
   1026 
   1027 void parse_unary_expr(void) {
   1028 	u32 op = ctx.tok;
   1029 	if (op == tPLUS) {
   1030 		next();
   1031 		parse_unary_expr();
   1032 	} else if (op == tMINUS) {
   1033 		emit_impl("(-");
   1034 		next();
   1035 		parse_unary_expr();
   1036 		emit_impl(")");
   1037 	} else if (op == tBANG) {
   1038 		emit_impl("(!");
   1039 		next();
   1040 		parse_unary_expr();
   1041 		emit_impl(")");
   1042 	} else if (op == tNOT) {
   1043 		emit_impl("(~");
   1044 		next();
   1045 		parse_unary_expr();
   1046 		emit_impl(")");
   1047 	} else if (op == tAMP) {
   1048 		error("dereference not supported");
   1049 		next();
   1050 		parse_unary_expr();
   1051 	} else {
   1052 		return parse_primary_expr();
   1053 	}
   1054 }
   1055 
   1056 void parse_mul_expr(void) {
   1057 	unsigned x = emit_impl_oparen();
   1058 	parse_unary_expr();
   1059 	while ((ctx.tok & tcMASK) == tcMULOP) {
   1060 		emit_impl(" %s ", tnames[ctx.tok]);
   1061 		next();
   1062 		parse_unary_expr();
   1063 		x |= KEEP_PARENS;
   1064 	}
   1065 	emit_impl_cparen(x);
   1066 }
   1067 
   1068 void parse_add_expr(void) {
   1069 	unsigned x = emit_impl_oparen();
   1070 	parse_mul_expr();
   1071 	while ((ctx.tok & tcMASK) == tcADDOP) {
   1072 		emit_impl(" %s ", tnames[ctx.tok]);
   1073 		next();
   1074 		parse_mul_expr();
   1075 		x |= KEEP_PARENS;
   1076 	}
   1077 	emit_impl_cparen(x);
   1078 }
   1079 
   1080 void parse_rel_expr(void) {
   1081 	unsigned x = emit_impl_oparen();
   1082 	parse_add_expr();
   1083 	if ((ctx.tok & tcMASK) == tcRELOP) {
   1084 		emit_impl(" %s ", tnames[ctx.tok]);
   1085 		next();
   1086 		parse_add_expr();
   1087 		x |= KEEP_PARENS;
   1088 	}
   1089 	emit_impl_cparen(x);
   1090 }
   1091 
   1092 void parse_and_expr(void) {
   1093 	unsigned x = emit_impl_oparen();
   1094 	parse_rel_expr();
   1095 	if (ctx.tok == tAND) {
   1096 		while (ctx.tok == tAND) {
   1097 			emit_impl(" && ");
   1098 			next();
   1099 			parse_rel_expr();
   1100 		}
   1101 		x |= KEEP_PARENS;
   1102 	}
   1103 	emit_impl_cparen(x);
   1104 }
   1105 
   1106 void parse_expr(void) {
   1107 	unsigned x = emit_impl_oparen();
   1108 	parse_and_expr();
   1109 	if (ctx.tok == tOR) {
   1110 		while (ctx.tok == tOR) {
   1111 			emit_impl(" || ");
   1112 			next();
   1113 			parse_and_expr();
   1114 		}
   1115 		x |= KEEP_PARENS;
   1116 	}
   1117 	emit_impl_cparen(x);
   1118 }
   1119 
   1120 Type *parse_struct_type(String *name) {
   1121 	Type *rectype = type_find(name);
   1122 
   1123 	if (rectype) {
   1124 		if (rectype->kind == TYPE_UNDEFINED) {
   1125 			// resolve forward ref
   1126 			rectype->kind = TYPE_STRUCT;
   1127 		} else {
   1128 			error("Cannot redefine struct '%s'", name->text);
   1129 		}
   1130 	} else {
   1131 		rectype = type_make(name, TYPE_STRUCT, nil, nil, 0);
   1132 	};
   1133 	scope_push(SCOPE_STRUCT);
   1134 	require(tOBRACE);
   1135 	emit_type("typedef struct t$%s t$%s;\n", name->text, name->text);
   1136 	emit_decl("struct t$%s {\n", name->text);
   1137 	while (true) {
   1138 		if (ctx.tok == tCBRACE) {
   1139 			next();
   1140 			break;
   1141 		}
   1142 		String *fname = parse_name("field name");
   1143 		bool ptr = (ctx.tok == tSTAR);
   1144 		if (ptr) next();
   1145 		Type *type = parse_type(true);
   1146 		emit_decl("    t$%s %s%s;\n", type->name->text, ptr ? "*" : "", fname->text);
   1147 		Symbol *sym = symbol_make(fname, type);
   1148 		sym->kind = ptr ? SYMBOL_PTR : SYMBOL_FLD;
   1149 		if (ctx.tok != tCBRACE) {
   1150 			require(tCOMMA);
   1151 		}
   1152 	}
   1153 	emit_decl("};\n"); // xxx was _type
   1154 	rectype->fields = scope_pop()->first;
   1155 	return rectype;
   1156 }
   1157 
   1158 Type *parse_array_type(void) {
   1159 	Type *type;
   1160 	u32 nelem = 0;
   1161 	char tmp[256];
   1162 	if (ctx.tok == tCBRACK) {
   1163 		next();
   1164 		type = type_make(nil, TYPE_ARRAY, parse_type(false), nil, 0);
   1165 	} else {
   1166 		if (ctx.tok != tNUM) {
   1167 			error("array size must be numeric");
   1168 		}
   1169 		nelem = ctx.num;
   1170 		next();
   1171 		require(tCBRACK);
   1172 		type = type_make(nil, TYPE_ARRAY, parse_type(false), nil, nelem);
   1173 	}
   1174 	sprintf(tmp, "%s$%u", type->of->name->text, nelem);
   1175 	type->name = string_make(tmp, strlen(tmp));
   1176 	if (nelem == 0) {
   1177 		emit_type("typedef t$%s t$%s[];\n", type->of->name->text, type->name->text);
   1178 	} else {
   1179 		emit_type("typedef t$%s t$%s[%u];\n", type->of->name->text, type->name->text, nelem);
   1180 	}
   1181 	return type;
   1182 }
   1183 
   1184 Type *parse_type(bool fwd_ref_ok) {
   1185 	if (ctx.tok == tSTAR) { // pointer-to
   1186 		error("pointer types not supported");
   1187 		//next();
   1188 		//return type_make(nil, TYPE_POINTER, parse_type(true), nil, 0);
   1189 	} else if (ctx.tok == tOBRACK) { // array-of
   1190 		next();
   1191 		return parse_array_type();
   1192 	} else if (ctx.tok == tFN) {
   1193 		error("func types not supported");
   1194 		//next();
   1195 		//return parse_func_type();
   1196 	} else if (ctx.tok == tSTRUCT) {
   1197 		error ("anonymous struct types not supported");
   1198 		//next();
   1199 		//return parse_struct_type(nil);
   1200 	} else if (ctx.tok == tIDN) {
   1201 		String *name = ctx.ident;
   1202 		next();
   1203 		Type *type = type_find(name);
   1204 		if (type == nil) {
   1205 			if (fwd_ref_ok) {
   1206 				type = type_make(name, TYPE_UNDEFINED, nil, nil, 0);
   1207 			} else {
   1208 				error("undefined type '%s' not usable here", name->text);
   1209 			}
   1210 		}
   1211 		return type;
   1212 	} else {
   1213 		expected("type");
   1214 	}
   1215 	return nil;
   1216 }
   1217 
   1218 void parse_block(void);
   1219 
   1220 void parse_while(void) {
   1221 	emit_impl("while (");
   1222 	parse_expr();
   1223 	require(tOBRACE);
   1224 	scope_push(SCOPE_LOOP);
   1225 	emit_impl(") {\n");
   1226 	parse_block();
   1227 	scope_pop();
   1228 	emit_impl("}\n");
   1229 }
   1230 
   1231 void parse_if(void) {
   1232 	// if expr { block }
   1233 	emit_impl("if (");
   1234 	parse_expr();
   1235 	emit_impl(") {\n");
   1236 	require(tOBRACE);
   1237 	scope_push(SCOPE_BLOCK);
   1238 	parse_block();
   1239 	scope_pop();
   1240 	while (ctx.tok == tELSE) {
   1241 		next();
   1242 		// ... else ...
   1243 		if (ctx.tok == tIF) {
   1244 			// ... if expr { block }
   1245 			emit_impl("} else if ");
   1246 			next();
   1247 			parse_expr();
   1248 			require(tOBRACE);
   1249 			emit_impl(" {\n");
   1250 			scope_push(SCOPE_BLOCK);
   1251 			parse_block();
   1252 			scope_pop();
   1253 		} else {
   1254 			// ... { block }
   1255 			emit_impl("} else {\n");
   1256 			require(tOBRACE);
   1257 			scope_push(SCOPE_BLOCK);
   1258 			parse_block();
   1259 			scope_pop();
   1260 			break;
   1261 		}
   1262 	}
   1263 	emit_impl("}\n");
   1264 }
   1265 
   1266 void parse_return(void) {
   1267 	if (ctx.tok == tSEMI) {
   1268 		//	error("function requires return type");
   1269 		next();
   1270 		emit_impl("return;\n");
   1271 	} else {
   1272 		//	error("return types do not match");
   1273 		emit_impl("return ");
   1274 		parse_expr();
   1275 		emit_impl(";\n");
   1276 		require(tSEMI);
   1277 	}
   1278 }
   1279 
   1280 void parse_break(void) {
   1281 	// XXX break-to-labeled-loop support
   1282 	Scope *scope = scope_find(SCOPE_LOOP);
   1283 	if (scope == nil) {
   1284 		error("break must be used from inside a looping construct");
   1285 	}
   1286 	require(tSEMI);
   1287 	emit_impl("break;\n");
   1288 }
   1289 
   1290 void parse_continue(void) {
   1291 	// XXX continue-to-labeled-loop support
   1292 	Scope *scope = scope_find(SCOPE_LOOP);
   1293 	if (scope == nil) {
   1294 		error("continue must be used from inside a looping construct");
   1295 	}
   1296 	require(tSEMI);
   1297 	emit_impl("continue;\n");
   1298 }
   1299 
   1300 void parse_struct_init(Symbol *var) {
   1301 	while (true) {
   1302 		if (ctx.tok == tCBRACE) {
   1303 			next();
   1304 			break;
   1305 		}
   1306 		String *name = parse_name("field name");
   1307 		Symbol *field = var->type->fields;
   1308 		while (true) {
   1309 			if (field == nil) {
   1310 				error("structure has no '%s' field", name->text);
   1311 			}
   1312 			if (field->name == name) {
   1313 				break;
   1314 			}
   1315 			field = field->next;
   1316 		}
   1317 		require(tCOLON);
   1318 		if (ctx.tok == tOBRACE) {
   1319 			next();
   1320 			emit_impl("{");
   1321 			parse_struct_init(field);
   1322 			emit_impl("}");
   1323 		} else {
   1324 			parse_expr();
   1325 			//emit_impl( "0x%x", ctx.num);
   1326 		}
   1327 		emit_impl( ",");
   1328 		if (ctx.tok != tCBRACE) {
   1329 			require(tCOMMA);
   1330 		}
   1331 	}
   1332 }
   1333 
   1334 void parse_array_init(Symbol *var) {
   1335 	while (true) {
   1336 		if (ctx.tok == tCBRACE) {
   1337 			next();
   1338 			break;
   1339 		}
   1340 		parse_expr();
   1341 		emit_impl(",");
   1342 		if (ctx.tok != tCBRACE) {
   1343 			require(tCOMMA);
   1344 		}
   1345 	}
   1346 }
   1347 
   1348 void parse_var(void) {
   1349 	String *name = parse_name("variable name");
   1350 	Type *type = parse_type(false);
   1351 	Symbol *var = symbol_make(name, type);
   1352 
   1353 	if (ctx.tok == tASSIGN) {
   1354 		next();
   1355 		if (ctx.tok == tOBRACE) {
   1356 			next();
   1357 			if (type->kind == TYPE_STRUCT) {
   1358 				emit_impl("t$%s $$%s = {\n", type->name->text, name->text);
   1359 				parse_struct_init(var);
   1360 				emit_impl("\n};\nt$%s *$%s = &$$%s;\n",
   1361 					type->name->text, name->text, name->text);
   1362 			} else if (type->kind == TYPE_ARRAY) {
   1363 				emit_impl("t$%s $%s = {\n", type->name->text, name->text);
   1364 				parse_array_init(var);
   1365 				emit_impl("\n};\n");
   1366 			} else {
   1367 				error("type %s cannot be initialized with {} expr", type->name->text);
   1368 			}
   1369 		} else {
   1370 			emit_impl("t$%s %s$%s = ", type->name->text,
   1371 				(type->kind == TYPE_STRUCT) ? "*" : "",
   1372 				name->text);
   1373 			parse_expr();
   1374 			emit_impl(";\n");
   1375 		}
   1376 	} else {
   1377 		if (type->kind == TYPE_ARRAY) {
   1378 			emit_impl("t$%s $%s = { 0, };\n", type->name->text, name->text);
   1379 		} else {
   1380 			emit_impl("t$%s %s$%s = 0;\n", type->name->text,
   1381 				(type->kind == TYPE_STRUCT) ? "*" : "",
   1382 				name->text);
   1383 		}
   1384 	}
   1385 	require(tSEMI);
   1386 
   1387 }
   1388 
   1389 void parse_expr_statement(void) {
   1390 	parse_expr();
   1391 	if (ctx.tok == tASSIGN) {
   1392 		emit_impl(" = ");
   1393 		next();
   1394 		parse_expr();
   1395 	} else if ((ctx.tok & tcMASK) == tcAEQOP) {
   1396 		emit_impl(" %s ", tnames[ctx.tok]);
   1397 		next();
   1398 		parse_expr();
   1399 	} else if ((ctx.tok & tcMASK) == tcMEQOP) {
   1400 		emit_impl(" %s ", tnames[ctx.tok]);
   1401 		next();
   1402 		parse_expr();
   1403 	} else if ((ctx.tok == tINC) || (ctx.tok == tDEC)) {
   1404 		emit_impl(" %s", tnames[ctx.tok]);
   1405 		next();
   1406 	}
   1407 	require(tSEMI);
   1408 	emit_impl(";\n");
   1409 }
   1410 
   1411 void parse_block(void) {
   1412 	while (true) {
   1413 		if (ctx.tok == tCBRACE) {
   1414 			next();
   1415 			break;
   1416 		} else if (ctx.tok == tRETURN) {
   1417 			next();
   1418 			parse_return();
   1419 		} else if (ctx.tok == tBREAK) {
   1420 			next();
   1421 			parse_break();
   1422 		} else if (ctx.tok == tCONTINUE) {
   1423 			next();
   1424 			parse_continue();
   1425 		} else if (ctx.tok == tWHILE) {
   1426 			next();
   1427 			parse_while();
   1428 		} else if (ctx.tok == tIF) {
   1429 			next();
   1430 			parse_if();
   1431 		} else if (ctx.tok == tVAR) {
   1432 			next();
   1433 			parse_var();
   1434 		} else if (ctx.tok == tSEMI) {
   1435 			next();
   1436 			// empty statement
   1437 			continue;
   1438 		} else {
   1439 			parse_expr_statement();
   1440 		}
   1441 	}
   1442 }
   1443 
   1444 Symbol *parse_param(String *fname) {
   1445 	String *pname = parse_name("parameter name");
   1446 	Type *ptype = parse_type(false);
   1447 
   1448 	// arrays and structs are always passed as reference parameters
   1449 	//if ((ptype->kind == TYPE_ARRAY) || (ptype->kind == TYPE_RECORD)) {
   1450 	//	ptype = type_make_ptr(ptype);
   1451 	//}
   1452 
   1453 	if (symbol_find(pname)) {
   1454 		error("duplicate parameter name '%s'", pname->text);
   1455 	}
   1456 
   1457 	return symbol_make(pname, ptype);
   1458 }
   1459 
   1460 void parse_function(void) {
   1461 	String *fname = parse_name("function name");
   1462 	Type *rtype = ctx.type_void;
   1463 
   1464 	scope_push(SCOPE_FUNC);
   1465 
   1466 	require(tOPAREN);
   1467 	if (ctx.tok != tCPAREN) {
   1468 		parse_param(fname);
   1469 		while (ctx.tok == tCOMMA) {
   1470 			next();
   1471 			parse_param(fname);
   1472 		}
   1473 	}
   1474 	require(tCPAREN);
   1475 
   1476 	if (ctx.tok != tOBRACE) {
   1477 		rtype = parse_type(false);
   1478 	}
   1479 
   1480 	emit_decl("t$%s%s fn_%s(", rtype->name->text, 
   1481 		rtype->kind == TYPE_STRUCT ? "*" : "", fname->text);
   1482 	emit_impl("t$%s%s fn_%s(", rtype->name->text,
   1483 		rtype->kind == TYPE_STRUCT ? "*" : "", fname->text);
   1484 	for (Symbol *s = ctx.scope->first; s != nil; s = s->next) {
   1485 		emit_decl("t$%s %s$%s%s",
   1486 			s->type->name->text,
   1487 			s->type->kind == TYPE_STRUCT ? "*" : "",
   1488 			s->name->text, s->next ? ", " : "");
   1489 		emit_impl("t$%s %s$%s%s",
   1490 			s->type->name->text,
   1491 			s->type->kind == TYPE_STRUCT ? "*" : "",
   1492 			s->name->text, s->next ? ", " : "");
   1493 	}
   1494 	emit_decl("%s);\n", ctx.scope->first ? "" : "t$void");
   1495 	emit_impl("%s) {\n", ctx.scope->first ? "" : "t$void");
   1496 
   1497 	// TODO: more complete type if needed...
   1498 	Symbol *sym = symbol_make_global(fname, rtype);
   1499 	sym->kind = SYMBOL_FN;
   1500 
   1501 	require(tOBRACE);
   1502 
   1503 	scope_push(SCOPE_BLOCK);
   1504 	parse_block();
   1505 	scope_pop();
   1506 
   1507 	emit_impl("}\n");
   1508 
   1509 	scope_pop();
   1510 }
   1511 
   1512 void parse_enum_def(void) {
   1513 	if (ctx.tok == tIDN) {
   1514 		String *name = parse_name("enum name");
   1515 		type_make(name, TYPE_ENUM, nil, nil, 0);
   1516 		emit_type("typedef t$u32 t$%s; // enum\n", name->text);
   1517 	}
   1518 
   1519 	require(tOBRACE);
   1520 	u32 val = 0;
   1521 	while (ctx.tok != tCBRACE) {
   1522 		String *name = parse_name("enum tag name");
   1523 		Symbol *sym = symbol_find(name);
   1524 		if (sym != nil) {
   1525 			error("cannot redefine %s as enum tag\n", name->text);
   1526 		}
   1527 		symbol_make_global(name, ctx.type_u32)->kind = SYMBOL_DEF;
   1528 		emit_impl("#define c$%s ", name->text, val);
   1529 		if (ctx.tok == tASSIGN) {
   1530 			next();
   1531 			parse_expr();
   1532 			emit_impl("\n");
   1533 		} else {
   1534 			emit_impl("0x%x\n", val);
   1535 			val++;
   1536 		}
   1537 		require(tCOMMA);
   1538 	}
   1539 	require(tCBRACE);
   1540 	require(tSEMI);
   1541 }
   1542 
   1543 void parse_begin() {
   1544 	emit_impl("\n#include <library.impl.h>\n");
   1545 }
   1546 
   1547 void parse_program() {
   1548 	next();
   1549 	for (;;) {
   1550 		if (ctx.tok == tENUM) {
   1551 			next();
   1552 			parse_enum_def();
   1553 		} else if (ctx.tok == tSTRUCT) {
   1554 			next();
   1555 			String *name = parse_name("struct name");
   1556 			parse_struct_type(name);
   1557 			require(tSEMI);
   1558 		} else if (ctx.tok == tFN) {
   1559 			next();
   1560 			parse_function();
   1561 		} else if (ctx.tok == tVAR) {
   1562 			next();
   1563 			parse_var();
   1564 		} else if (ctx.tok == tEOF) {
   1565 			return;
   1566 		} else {
   1567 			expected("function, variable, or type definition");
   1568 		}
   1569 	}
   1570 
   1571 }
   1572 
   1573 void parse_end() {
   1574 	emit_impl("\n#include <library.impl.c>\n");
   1575 }
   1576 
   1577 // ================================================================
   1578 
   1579 int main(int argc, char **argv) {
   1580 	bool first = true;
   1581 
   1582 	ctx_init();
   1583 	ctx.filename = "<commandline>";
   1584 	ctx.outname = nil;
   1585 
   1586 	while (argc > 1) {
   1587 		if (!strcmp(argv[1],"-o")) {
   1588 			if (argc < 2) {
   1589 				error("option -o requires argument");
   1590 			}
   1591 			ctx.outname = argv[2];
   1592 			argc--;
   1593 			argv++;
   1594 		} else if (!strcmp(argv[1], "-A")) {
   1595 			ctx.flags |= cfAbortOnError;
   1596 		} else if (argv[1][0] == '-') {
   1597 			error("unknown option: %s", argv[1]);
   1598 		} else {
   1599 			ctx.filename = argv[1];
   1600 			if (ctx.outname == nil) {
   1601 				ctx.outname = ctx.filename;
   1602 			}
   1603 
   1604 			ctx_open_source(ctx.filename);
   1605 			ctx.linenumber = 1;
   1606 			ctx.lineoffset = 0;
   1607 
   1608 			// prime the lexer
   1609 			scan();
   1610 
   1611 			if (first) {
   1612 				first = false;
   1613 				ctx_open_output();
   1614 				parse_begin();
   1615 			}
   1616 			parse_program();
   1617 		}
   1618 		argc--;
   1619 		argv++;
   1620 	}
   1621 
   1622 	if (ctx.filename == nil) {
   1623 		printf(
   1624 "usage:    compiler [ <option> | <sourcefilename> ]*\n"
   1625 "\n"
   1626 "options:  -o <filename>    output base name (default source name)\n"
   1627 "          -A               abort on error\n");
   1628 		return 0;
   1629 	}
   1630 
   1631 	parse_end();
   1632 
   1633 	return 0;
   1634 }