diff options
Diffstat (limited to 'src/compiler.c')
-rw-r--r-- | src/compiler.c | 209 |
1 files changed, 208 insertions, 1 deletions
diff --git a/src/compiler.c b/src/compiler.c index e303cee..04afd5d 100644 --- a/src/compiler.c +++ b/src/compiler.c | |||
@@ -5,6 +5,15 @@ | |||
5 | 5 | ||
6 | #include "parser.c" | 6 | #include "parser.c" |
7 | 7 | ||
8 | typedef struct Variable { | ||
9 | Str name; | ||
10 | Str type; | ||
11 | sz size; | ||
12 | sz offset; | ||
13 | } Variable; | ||
14 | |||
15 | MAPDEF(StrVarMap, varmap, Str, Variable, str_hash, str_eq) | ||
16 | |||
8 | typedef struct Instruction { | 17 | typedef struct Instruction { |
9 | u8 dst; | 18 | u8 dst; |
10 | u8 a; | 19 | u8 a; |
@@ -33,6 +42,11 @@ typedef struct Chunk { | |||
33 | StrIntMap *strmap; | 42 | StrIntMap *strmap; |
34 | sz str_idx; | 43 | sz str_idx; |
35 | 44 | ||
45 | // Global/Local variables. | ||
46 | Variable *vars; | ||
47 | StrVarMap *varmap; | ||
48 | sz var_off; | ||
49 | |||
36 | // Number of registers currently used in this chunk. | 50 | // Number of registers currently used in this chunk. |
37 | sz reg_idx; | 51 | sz reg_idx; |
38 | 52 | ||
@@ -46,7 +60,9 @@ typedef enum OpCode { | |||
46 | // OP DST A B | 60 | // OP DST A B |
47 | // --------------------------------------------------------------- | 61 | // --------------------------------------------------------------- |
48 | // VM/high level instructions. | 62 | // VM/high level instructions. |
49 | OP_HALT, // halt | 63 | OP_HALT, // halt |
64 | OP_STVARI, // stvari vx, ca | ||
65 | OP_STVAR, // stvar vx, ra | ||
50 | // Load/Store instructions. | 66 | // Load/Store instructions. |
51 | OP_LD8K, // ld8k rx, ca -> u8 rx = ca | 67 | OP_LD8K, // ld8k rx, ca -> u8 rx = ca |
52 | OP_LD16K, // ld16k rx, ca -> u16 rx = ca | 68 | OP_LD16K, // ld16k rx, ca -> u16 rx = ca |
@@ -129,6 +145,8 @@ typedef enum OpCode { | |||
129 | 145 | ||
130 | Str op_str[] = { | 146 | Str op_str[] = { |
131 | [OP_HALT] = cstr("HALT "), | 147 | [OP_HALT] = cstr("HALT "), |
148 | [OP_STVAR] = cstr("STVAR "), | ||
149 | [OP_STVARI] = cstr("STVARI "), | ||
132 | // Load ops. | 150 | // Load ops. |
133 | [OP_LD8K] = cstr("LD8K "), | 151 | [OP_LD8K] = cstr("LD8K "), |
134 | [OP_LD16K] = cstr("LD16K "), | 152 | [OP_LD16K] = cstr("LD16K "), |
@@ -210,6 +228,7 @@ Str op_str[] = { | |||
210 | }; | 228 | }; |
211 | 229 | ||
212 | typedef enum { | 230 | typedef enum { |
231 | COMP_NIL, | ||
213 | COMP_CONST, | 232 | COMP_CONST, |
214 | COMP_STRING, | 233 | COMP_STRING, |
215 | COMP_REG, | 234 | COMP_REG, |
@@ -464,6 +483,54 @@ compile_expr(Chunk *chunk, Node *node) { | |||
464 | .idx = map->val, | 483 | .idx = map->val, |
465 | }; | 484 | }; |
466 | } break; | 485 | } break; |
486 | case NODE_LET: { | ||
487 | sz idx = array_size(chunk->vars); | ||
488 | Str name = node->unique_name; | ||
489 | Str type = node->var_name->type; | ||
490 | sz size = 8; | ||
491 | // TODO: get type storage from a table to consider all the basic | ||
492 | // types as well as user defined ones. | ||
493 | if (str_eq(type, cstr("str"))) { | ||
494 | size = 16; | ||
495 | } | ||
496 | Variable var = (Variable){ | ||
497 | .name = name, | ||
498 | .type = type, | ||
499 | .size = size, | ||
500 | .offset = chunk->var_off, | ||
501 | }; | ||
502 | varmap_insert(&chunk->varmap, name, var, chunk->storage); | ||
503 | array_push(chunk->vars, var, chunk->storage); | ||
504 | chunk->var_off += size; | ||
505 | |||
506 | // Value. | ||
507 | if (node->var_val) { | ||
508 | CompResult res = compile_expr(chunk, node->var_val); | ||
509 | switch (res.type) { | ||
510 | case COMP_CONST: { | ||
511 | EMIT_OP(OP_STVARI, idx, res.idx, 0, node->var_val, | ||
512 | chunk); | ||
513 | } break; | ||
514 | case COMP_REG: { | ||
515 | EMIT_OP(OP_STVAR, idx, res.idx, 0, node->var_val, | ||
516 | chunk); | ||
517 | } break; | ||
518 | default: { | ||
519 | return (CompResult){.type = COMP_ERR}; | ||
520 | } break; | ||
521 | } | ||
522 | } | ||
523 | |||
524 | return (CompResult){.type = COMP_NIL}; | ||
525 | } break; | ||
526 | case NODE_BLOCK: { | ||
527 | CompResult res; | ||
528 | for (sz i = 0; i < array_size(node->elements); i++) { | ||
529 | Node *root = node->elements[i]; | ||
530 | res = compile_expr(chunk, root); | ||
531 | } | ||
532 | return res; | ||
533 | } break; | ||
467 | default: { | 534 | default: { |
468 | eprintln("error: compilation not implemented for node %s", | 535 | eprintln("error: compilation not implemented for node %s", |
469 | node_str[node->kind]); | 536 | node_str[node->kind]); |
@@ -473,4 +540,144 @@ compile_expr(Chunk *chunk, Node *node) { | |||
473 | return (CompResult){.type = COMP_ERR}; | 540 | return (CompResult){.type = COMP_ERR}; |
474 | } | 541 | } |
475 | 542 | ||
543 | void | ||
544 | disassemble_instruction(Instruction instruction) { | ||
545 | switch (instruction.op) { | ||
546 | case OP_MOV8: | ||
547 | case OP_MOV16: | ||
548 | case OP_MOV32: | ||
549 | case OP_MOV64: | ||
550 | println("%s r%d, r%d", op_str[instruction.op], instruction.dst, | ||
551 | instruction.a, instruction.b); | ||
552 | break; | ||
553 | case OP_LD8K: | ||
554 | case OP_LD16K: | ||
555 | case OP_LD32K: | ||
556 | case OP_LD64K: | ||
557 | println("%s r%d, c%d", op_str[instruction.op], instruction.dst, | ||
558 | instruction.a, instruction.b); | ||
559 | break; | ||
560 | case OP_LD8I: | ||
561 | case OP_LD16I: | ||
562 | case OP_LD32I: | ||
563 | case OP_LD64I: | ||
564 | case OP_ST8I: | ||
565 | case OP_ST16I: | ||
566 | case OP_ST32I: | ||
567 | case OP_ST64I: | ||
568 | case OP_ADDI: | ||
569 | case OP_SUBI: | ||
570 | case OP_MULI: | ||
571 | case OP_DIVI: | ||
572 | case OP_MODI: | ||
573 | case OP_ADDFI: | ||
574 | case OP_SUBFI: | ||
575 | case OP_MULFI: | ||
576 | case OP_DIVFI: | ||
577 | case OP_MODFI: | ||
578 | case OP_EQI: | ||
579 | case OP_NEQI: | ||
580 | case OP_LTI: | ||
581 | case OP_GTI: | ||
582 | case OP_LEI: | ||
583 | case OP_GEI: | ||
584 | case OP_ANDI: | ||
585 | case OP_ORI: | ||
586 | case OP_BITLSHIFTI: | ||
587 | case OP_BITRSHIFTI: | ||
588 | case OP_BITANDI: | ||
589 | case OP_BITORI: | ||
590 | println("%s r%d, r%d, c%d", op_str[instruction.op], instruction.dst, | ||
591 | instruction.a, instruction.b); | ||
592 | break; | ||
593 | case OP_LD8: | ||
594 | case OP_LD16: | ||
595 | case OP_LD32: | ||
596 | case OP_LD64: | ||
597 | case OP_ST8: | ||
598 | case OP_ST16: | ||
599 | case OP_ST32: | ||
600 | case OP_ST64: | ||
601 | case OP_ADD: | ||
602 | case OP_SUB: | ||
603 | case OP_MUL: | ||
604 | case OP_DIV: | ||
605 | case OP_MOD: | ||
606 | case OP_ADDF: | ||
607 | case OP_SUBF: | ||
608 | case OP_MULF: | ||
609 | case OP_DIVF: | ||
610 | case OP_MODF: | ||
611 | case OP_EQ: | ||
612 | case OP_NEQ: | ||
613 | case OP_LT: | ||
614 | case OP_GT: | ||
615 | case OP_LE: | ||
616 | case OP_GE: | ||
617 | case OP_AND: | ||
618 | case OP_OR: | ||
619 | case OP_BITLSHIFT: | ||
620 | case OP_BITRSHIFT: | ||
621 | case OP_BITAND: | ||
622 | case OP_BITOR: | ||
623 | println("%s r%d, r%d, r%d", op_str[instruction.op], instruction.dst, | ||
624 | instruction.a, instruction.b); | ||
625 | break; | ||
626 | case OP_STVAR: | ||
627 | println("%s v%d, r%d", op_str[instruction.op], instruction.dst, | ||
628 | instruction.a, instruction.b); | ||
629 | break; | ||
630 | case OP_STVARI: | ||
631 | println("%s v%d, c%d", op_str[instruction.op], instruction.dst, | ||
632 | instruction.a, instruction.b); | ||
633 | break; | ||
634 | case OP_BITNOTI: | ||
635 | case OP_NOTI: | ||
636 | println("%s r%d, c%d", op_str[instruction.op], instruction.dst, | ||
637 | instruction.a, instruction.b); | ||
638 | break; | ||
639 | case OP_BITNOT: | ||
640 | case OP_NOT: | ||
641 | println("%s r%d, r%d", op_str[instruction.op], instruction.dst, | ||
642 | instruction.a, instruction.b); | ||
643 | break; | ||
644 | case OP_HALT: println("%s", op_str[instruction.op]); break; | ||
645 | default: println("Unknown opcode %d", instruction.op); break; | ||
646 | } | ||
647 | } | ||
648 | |||
649 | void | ||
650 | disassemble_chunk(Chunk chunk) { | ||
651 | println("%s: =========== code ===========", chunk.file_name); | ||
652 | for (sz i = 0; i < array_size(chunk.code); i++) { | ||
653 | print("%s: %x{4}: ", chunk.file_name, i); | ||
654 | disassemble_instruction(chunk.code[i]); | ||
655 | } | ||
656 | if (array_size(chunk.constants) > 0) { | ||
657 | println("%s: ========= constants ========", chunk.file_name); | ||
658 | for (sz i = 0; i < array_size(chunk.constants); i++) { | ||
659 | println("%s: %x{2}: %x{8}", chunk.file_name, i, | ||
660 | chunk.constants[i]); | ||
661 | } | ||
662 | } | ||
663 | if (array_size(chunk.strings) > 0) { | ||
664 | println("%s: ========== strings =========", chunk.file_name); | ||
665 | for (sz i = 0; i < array_size(chunk.strings); i++) { | ||
666 | println("%s: %x{2}: %s", chunk.file_name, i, chunk.strings[i]); | ||
667 | } | ||
668 | } | ||
669 | if (array_size(chunk.vars) > 0) { | ||
670 | println("%s: ========= variables ========", chunk.file_name); | ||
671 | for (sz i = 0; i < array_size(chunk.vars); i++) { | ||
672 | println("%s: %x{2}: [%x{4}:%x{4}] %s: %s", chunk.file_name, i, | ||
673 | chunk.vars[i].offset, | ||
674 | chunk.vars[i].offset + chunk.vars[i].size, | ||
675 | chunk.vars[i].name, chunk.vars[i].type); | ||
676 | } | ||
677 | } | ||
678 | println("n_regs: %d, n_vars: %d, n_strings: %d, n_consts: %d", | ||
679 | chunk.reg_idx, array_size(chunk.vars), chunk.str_idx, | ||
680 | chunk.const_idx); | ||
681 | } | ||
682 | |||
476 | #endif // COMPILER_C | 683 | #endif // COMPILER_C |