├── .gitignore ├── Makefile ├── README.md ├── bin ├── depasm ├── packlc ├── pasm └── pvmr ├── examples ├── args.packl ├── class.packl ├── for.packl ├── func.packl ├── hello-world.packl ├── if.packl ├── linked-list.packl ├── proc.packl ├── rule-110.packl ├── shitty-game.packl ├── sort-int-array.packl ├── tree.packl ├── var.packl └── while.packl ├── future └── class-goal.packl ├── main.js ├── main.packl ├── obj ├── packl-array.o ├── packl-codegen.o ├── packl-context.o ├── packl-lexer.o ├── packl-operator.o ├── packl-parser.o ├── packl-printer.o ├── packl.o └── pvm-instructions.o ├── packlc.c ├── packlr.c ├── src ├── .vscode │ └── settings.json ├── headers │ ├── packl-array.h │ ├── packl-codegen.h │ ├── packl-context.h │ ├── packl-defs.h │ ├── packl-error.h │ ├── packl-lexer.h │ ├── packl-operator.h │ ├── packl-parser.h │ ├── packl-printer.h │ ├── packl.h │ └── pvm-instructions.h ├── packl-array.c ├── packl-codegen.c ├── packl-context.c ├── packl-lexer.c ├── packl-operator.c ├── packl-parser.c ├── packl-printer.c ├── packl.c └── pvm-instructions.c ├── std ├── array.packl ├── io.packl └── string.packl ├── tests ├── expression-as-arg.packl ├── expression.packl ├── nested-ifs.packl ├── parse.packl ├── proc-call.packl ├── proc-declaration.packl ├── string.packl ├── tokens.packl └── variable-declaration.packl └── tools ├── arena.c ├── arena.h ├── dyn-arr.h ├── error.h ├── hashmap.c ├── hashmap.h ├── sv.c ├── sv.h └── vector.h /.gitignore: -------------------------------------------------------------------------------- 1 | packlr -------------------------------------------------------------------------------- /Makefile: -------------------------------------------------------------------------------- 1 | CC = gcc 2 | 3 | CFLAGS = -Wall -Werror -g 4 | 5 | SRCDIR = src 6 | OBJDIR = obj 7 | TOOLSDIR = tools 8 | BIN = bin 9 | 10 | ENTRY = packlc.c 11 | 12 | SOURCES = $(ENTRY) $(wildcard $(TOOLSDIR)/*.c) $(wildcard $(SRCDIR)/*.c) 13 | 14 | OBJECTS = $(patsubst $(SRCDIR)/%.c, $(OBJDIR)/%.o, $(SOURCES)) 15 | 16 | EXEC = packlc 17 | 18 | all: $(EXEC) 19 | 20 | $(EXEC): $(OBJECTS) 21 | $(CC) $(CFLAGS) -o $@ $^ 22 | @mkdir -p $(BIN) 23 | mv $(EXEC) $(BIN) 24 | 25 | $(OBJDIR)/%.o: $(SRCDIR)/%.c 26 | @mkdir -p $(OBJDIR) 27 | $(CC) $(CFLAGS) -c -o $@ $< 28 | 29 | clean: 30 | rm -f $(OBJDIR)/*.o $(EXEC) 31 | 32 | .PHONY: all clean 33 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # PACKL 2 | a very small programming language built on top of the PACKL Virtual Machine, it uses PASM for the code generation 3 | 4 | 5 | # Play with PACKL 6 | Once you have a PACKL program, follow the steps below to compile the program 7 | 8 | ```console 9 | ./bin/packlc -code -out .pasm 10 | ./bin/pasm .pasm 11 | ``` 12 | 13 | to run the program type the command below 14 | 15 | ```console 16 | ./bin/pvmr .pvm 17 | ``` 18 | 19 | 20 | # PACKL Features 21 | ## Hello World 22 | 23 | ```nim 24 | proc main() { 25 | write(0, "Hello World\n"); 26 | exit(0); 27 | } 28 | ``` 29 | 30 | ## Variables Declaration and Re-Assignement 31 | 32 | ```nim 33 | proc main() { 34 | var foo: int = 10; 35 | foo = foo - 10; 36 | exit(foo); 37 | } 38 | ``` 39 | 40 | ## Functions 41 | ```nim 42 | func sub(a: int, b: int): int { 43 | sub = a - b; 44 | } 45 | 46 | func add(a: int, b: int): int { 47 | add = a + b; 48 | } 49 | 50 | proc main() { 51 | var i: int = add(1, 2) - sub(8, 5); 52 | exit(i); 53 | } 54 | ``` 55 | 56 | ## If Statements 57 | 58 | ```nim 59 | proc main() { 60 | var i: int = 10; 61 | 62 | if (i < 10) { foo(); } 63 | else if (i < 20) { bar(); } 64 | else { write("none\n"); } 65 | 66 | exit(0); 67 | } 68 | ``` 69 | 70 | ## While Loops 71 | 72 | ```nim 73 | proc main() { 74 | var i: int = 10; 75 | while (i) { 76 | foo(); 77 | i = i - 1; 78 | } 79 | exit(0); 80 | } 81 | ``` 82 | 83 | 84 | ## For Loops 85 | ```nim 86 | proc main() { 87 | for i: int in (1, 10) { 88 | foo(); 89 | } 90 | exit(0); 91 | } 92 | ``` 93 | 94 | ## External Files Importing 95 | 96 | ```nim 97 | use "std/io.packl" as io 98 | 99 | proc main() { 100 | io:println("PACKL"); 101 | exit(0); 102 | } 103 | ``` 104 | 105 | ## Arrays 106 | 107 | ```nim 108 | proc main() { 109 | var nums: array(int, 2) = {1, 2}; 110 | nums[0] = 0; 111 | exit(nums[0]); 112 | } 113 | ``` 114 | 115 | ## Strings 116 | 117 | ```nim 118 | use "std/string.packl" as string 119 | use "std/io.packl" as io 120 | 121 | proc main() { 122 | var s: str = "djaoued"; 123 | io:println(string:toupper(s)); 124 | exit(0); 125 | } 126 | ``` 127 | 128 | ## Comments 129 | 130 | ```nim 131 | # this is a comment 132 | ``` 133 | 134 | ## Operators 135 | 136 | ```nim 137 | proc main() { 138 | var n: int = 20; 139 | var a: int = 10; 140 | var b: int = a++; # b = 10 and a = 11 141 | var c: int = a--; # c = 11 and a = 10 142 | var d: int = a <= 10 # d = 1 143 | var e: int = a >= 10 # e = 1 144 | var f: int = a < 10 # f = 0 145 | var g: int = a > 10 # g = 0 146 | var h: int = a == 10 # h = 1 147 | var i: int = a != 10 # i = 0 148 | var j: int = a and n # j = 1 149 | var k: int = a or n # k = 1 150 | var l: int = a xor n # l = 30 151 | } 152 | ``` 153 | 154 | ## Classes 155 | ```nim 156 | class Point { 157 | x: int; 158 | y: int; 159 | }; 160 | 161 | class Rectangle { 162 | a: Point; # the starting point 163 | w: int; 164 | h: int; 165 | }; 166 | 167 | proc main() { 168 | var r: Rectangle = new Rectangle; 169 | r.init(...); # initializing the rectangle 170 | r.render(...); # rendering the rectangle 171 | write(0, "r: ", r, "\n"); # writing the rectangle object value 172 | } 173 | ``` 174 | 175 | 176 | # Note 177 | The PACKL programming language is still not a stable language, don't expect much from it! -------------------------------------------------------------------------------- /bin/depasm: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DjoCoding/PACKL/253adf2f3436bac67fd29e4b5752a10e1ef3f3bb/bin/depasm -------------------------------------------------------------------------------- /bin/packlc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DjoCoding/PACKL/253adf2f3436bac67fd29e4b5752a10e1ef3f3bb/bin/packlc -------------------------------------------------------------------------------- /bin/pasm: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DjoCoding/PACKL/253adf2f3436bac67fd29e4b5752a10e1ef3f3bb/bin/pasm -------------------------------------------------------------------------------- /bin/pvmr: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DjoCoding/PACKL/253adf2f3436bac67fd29e4b5752a10e1ef3f3bb/bin/pvmr -------------------------------------------------------------------------------- /examples/args.packl: -------------------------------------------------------------------------------- 1 | proc println(s: str) { 2 | write(0, s); 3 | write(0, "\n"); 4 | } 5 | 6 | proc main() { 7 | println("Djaoued"); 8 | exit(1); 9 | } 10 | -------------------------------------------------------------------------------- /examples/class.packl: -------------------------------------------------------------------------------- 1 | class Point { 2 | x: int; 3 | y: int; 4 | }; 5 | 6 | proc Point.init(x: int, y: int) { 7 | this.x = x; 8 | this.y = y; 9 | } 10 | 11 | proc main() { 12 | var p: Point = new Point; 13 | } 14 | 15 | # parsing methods is done 16 | # need to parse expression of object attributes and method calls 17 | # need to generate the code for the object initialzation, object method call ... 18 | # need somehow a way to print an object same as javascript -------------------------------------------------------------------------------- /examples/for.packl: -------------------------------------------------------------------------------- 1 | proc foo() { 2 | write(0, "foo\n"); 3 | } 4 | 5 | proc main() { 6 | for i: int in (1, 10) { 7 | foo(); 8 | } 9 | exit(0); 10 | } -------------------------------------------------------------------------------- /examples/func.packl: -------------------------------------------------------------------------------- 1 | func strlen(s: str): int { 2 | var i: int = 0; 3 | 4 | while(s[i++]) { 5 | } 6 | 7 | strlen = i - 1; 8 | } 9 | 10 | proc main() { 11 | var s: str = "PACKL"; 12 | write(0, "the length of `", s, "` is: ", strlen(s), "\n"); 13 | } -------------------------------------------------------------------------------- /examples/hello-world.packl: -------------------------------------------------------------------------------- 1 | proc main() { 2 | write(0, "Hello World\n"); 3 | exit(0); 4 | } -------------------------------------------------------------------------------- /examples/if.packl: -------------------------------------------------------------------------------- 1 | proc foo() { 2 | write(0, "foo\n"); 3 | } 4 | 5 | proc bar() { 6 | write(0, "bar\n"); 7 | } 8 | 9 | proc main() { 10 | if (1) { 11 | foo(); 12 | } else { 13 | bar(); 14 | } 15 | exit(0); 16 | } -------------------------------------------------------------------------------- /examples/linked-list.packl: -------------------------------------------------------------------------------- 1 | record Node { 2 | value: int; 3 | next: ptr; 4 | }; 5 | 6 | record List { 7 | head: ptr; 8 | tail: ptr; 9 | }; 10 | 11 | func node_get_value(node: ptr): int { 12 | node_get_value = mload(node, sizeof int); 13 | } 14 | 15 | func node_get_next(node: ptr): ptr { 16 | node_get_next = mload(node + sizeof int, sizeof ptr); 17 | } 18 | 19 | proc node_set_value(node: ptr, value: int) { 20 | mset(node, value, sizeof int); 21 | } 22 | 23 | proc node_set_next(node: ptr, next: ptr) { 24 | mset(node + sizeof int, next, sizeof ptr); 25 | } 26 | 27 | func node_init(value: int): ptr { 28 | var node: ptr = new Node; 29 | node_set_value(node, value); 30 | node_set_next(node, 0); 31 | node_init = node; 32 | } 33 | 34 | proc node_write(node: ptr) { 35 | write(0, node_get_value(node)); 36 | } 37 | 38 | 39 | func list_get_head(list: ptr): ptr { 40 | list_get_head = mload(list, sizeof ptr); 41 | } 42 | 43 | func list_get_tail(list: ptr): ptr { 44 | list_get_tail = mload(list + sizeof ptr, sizeof ptr); 45 | } 46 | 47 | proc list_set_head(list: ptr, head: ptr) { 48 | mset(list, head, sizeof ptr); 49 | } 50 | 51 | proc list_set_tail(list: ptr, tail: ptr) { 52 | mset(list + sizeof ptr, tail, sizeof ptr); 53 | } 54 | 55 | func list_init(): ptr { 56 | var list: ptr = new List; 57 | list_set_head(list, 0); 58 | list_set_tail(list, 0); 59 | list_init = list; 60 | } 61 | 62 | proc list_reset(list: ptr) { 63 | list_set_head(list, 0); 64 | list_set_tail(list, 0); 65 | } 66 | 67 | proc list_print(list: ptr) { 68 | var current: ptr = list_get_head(list); 69 | while(current) { 70 | node_write(current); 71 | write(0, " "); 72 | current = node_get_next(current); 73 | } 74 | write(0, "\n"); 75 | } 76 | 77 | proc free_list(list: ptr) { 78 | var current: ptr = list_get_head(list); 79 | var next: ptr = 0; 80 | while(current) { 81 | next = node_get_next(current); 82 | mdealloc(current); 83 | current = next; 84 | } 85 | list_reset(list); 86 | } 87 | 88 | proc list_append(list: ptr, value: int) { 89 | var node: ptr = node_init(value); 90 | var head: ptr = list_get_head(list); 91 | var tail: ptr = list_get_tail(list); 92 | 93 | if (!head) { list_set_head(list, node); list_set_tail(list, node); } 94 | else { 95 | node_set_next(tail, node); 96 | list_set_tail(list, node); 97 | } 98 | } 99 | 100 | 101 | proc main() { 102 | var list: ptr = list_init(); 103 | for i: int in (0, 10) { 104 | list_append(list, i); 105 | } 106 | list_print(list); 107 | free_list(list); 108 | exit(0); 109 | } -------------------------------------------------------------------------------- /examples/proc.packl: -------------------------------------------------------------------------------- 1 | proc bar() { 2 | write(0, "bar\n"); 3 | } 4 | 5 | proc foo() { 6 | write(0, "foo\n"); 7 | bar(); 8 | } 9 | 10 | proc main() { 11 | foo(); 12 | exit(0); 13 | } -------------------------------------------------------------------------------- /examples/rule-110.packl: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DjoCoding/PACKL/253adf2f3436bac67fd29e4b5752a10e1ef3f3bb/examples/rule-110.packl -------------------------------------------------------------------------------- /examples/shitty-game.packl: -------------------------------------------------------------------------------- 1 | proc display(rows: int, cols: int, x: int, y: int, target_x: int, target_y: int) { 2 | for i: int in (0, rows - 1) { 3 | for j: int in (0, cols - 1) { 4 | if (x == i and y == j) { 5 | write(0, " # "); 6 | } else if (i == target_x and j == target_y) { 7 | write(0, "[ ]"); 8 | } else { 9 | write(0, " . "); 10 | } 11 | } 12 | write(0, "\n"); 13 | } 14 | } 15 | 16 | proc display_line(size: int) { 17 | for i: int in (0, size - 1) { 18 | write(0, "-"); 19 | } 20 | write(0, "\n"); 21 | } 22 | 23 | func update(pos: int, target: int): int { 24 | if(target > pos) { 25 | update = pos + 1; 26 | } else if (target < pos) { 27 | update = pos - 1; 28 | } else { 29 | update = pos; 30 | } 31 | } 32 | 33 | func randomize(v: int, max: int): int { 34 | randomize = (v * 23 / 2 + 1) % max; 35 | } 36 | 37 | proc main() { 38 | var x: int = 0; 39 | var y: int = 0; 40 | 41 | var target_x: int = 5; 42 | var target_y: int = 5; 43 | 44 | var rows: int = 10; 45 | var cols: int = 10; 46 | 47 | 48 | while (1) { 49 | display(rows, cols, x, y, target_x, target_y); 50 | x = update(x, target_x); 51 | y = update(y, target_y); 52 | display_line(30); 53 | if (x == target_x and y == target_y) { 54 | target_x = randomize(target_x, rows); 55 | target_y = randomize(target_y, cols); 56 | } 57 | } 58 | } 59 | -------------------------------------------------------------------------------- /examples/sort-int-array.packl: -------------------------------------------------------------------------------- 1 | func random(current: int, max: int): int { 2 | random = (current * 27 + 11) % max; 3 | } 4 | 5 | func arr_alloc(size: int, item_size: int): ptr { 6 | arr_alloc = malloc(size * item_size); 7 | } 8 | 9 | func arr_get_item(arr: ptr, index: int, item_size: int): int { 10 | arr_get_item = mload(arr + item_size * index, item_size); 11 | } 12 | 13 | proc arr_set_item(arr: ptr, index: int, value: int, item_size: int) { 14 | mset(arr + index * item_size, value, item_size); 15 | } 16 | 17 | proc arr_randomize(arr: ptr, size: int, item_size: int) { 18 | var current_item: ptr = arr; 19 | var current_value: int = 331; 20 | 21 | for i: int in (0, size - 1) { 22 | current_value = random(current_value, 100); 23 | arr_set_item(arr, i, current_value, item_size); 24 | } 25 | } 26 | 27 | proc arr_display(arr: ptr, size: int, item_size: int) { 28 | var value: int = 0; 29 | 30 | write(0, "[ "); 31 | for i: int in (0, size - 1) { 32 | write(0, arr_get_item(arr, i, item_size), " "); 33 | } 34 | write(0, "]\n"); 35 | } 36 | 37 | proc arr_swap(arr: ptr, i: int, j: int, item_size: int) { 38 | var first: int = arr_get_item(arr, i, item_size); 39 | var second: int = arr_get_item(arr, j, item_size); 40 | arr_set_item(arr, i, second, item_size); 41 | arr_set_item(arr, j, first, item_size); 42 | } 43 | 44 | 45 | proc arr_sort(arr: ptr, size: int, item_size: int) { 46 | var min_index: int = 0; # the index of the item who has the minimum value 47 | 48 | for i: int in (0, size - 1) { 49 | min_index = i; 50 | for j: int in (i + 1, size - 1) { 51 | if (arr_get_item(arr, min_index, item_size) > arr_get_item(arr, j, item_size)) { 52 | min_index = j; 53 | } 54 | } 55 | arr_swap(arr, i, min_index, item_size); 56 | } 57 | } 58 | 59 | 60 | proc main() { 61 | var i: int = 0; 62 | var size: int = 10; 63 | 64 | var arr: ptr = arr_alloc(size, sizeof(i)); 65 | 66 | arr_randomize(arr, size, sizeof(i)); 67 | arr_display(arr, size, sizeof(i)); 68 | 69 | arr_sort(arr, size, sizeof(i)); 70 | arr_display(arr, size, sizeof(i)); 71 | 72 | mdealloc(arr); 73 | 74 | exit(0); 75 | } -------------------------------------------------------------------------------- /examples/tree.packl: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DjoCoding/PACKL/253adf2f3436bac67fd29e4b5752a10e1ef3f3bb/examples/tree.packl -------------------------------------------------------------------------------- /examples/var.packl: -------------------------------------------------------------------------------- 1 | proc main() { 2 | var number: int = 1 + 2 * 3 + 10; 3 | exit(number); 4 | } -------------------------------------------------------------------------------- /examples/while.packl: -------------------------------------------------------------------------------- 1 | proc main() { 2 | var i: int = 10; 3 | 4 | while(i--) { 5 | write(0, "Hello World\n"); 6 | } 7 | 8 | exit(0); 9 | } 10 | -------------------------------------------------------------------------------- /future/class-goal.packl: -------------------------------------------------------------------------------- 1 | class Node { 2 | value: int; 3 | next: Node; 4 | } 5 | 6 | # here you gonna push two things, the object refered by 'this' and the value 7 | # init is the constructor for any class object 8 | proc Node.init(value: int) { 9 | this.value = value; 10 | this.next = 0; 11 | } 12 | 13 | func Node.value(): int { 14 | value = this.value; 15 | } 16 | 17 | func Node.next(): Node { 18 | next = this.next; 19 | } 20 | 21 | proc main() { 22 | var head: Node; 23 | head.init(10); 24 | var value: int = head.value(); 25 | exit(value); 26 | } -------------------------------------------------------------------------------- /main.js: -------------------------------------------------------------------------------- 1 | const obj = { 2 | name: "djaoued", 3 | age: 18, 4 | }; 5 | 6 | console.log(obj); -------------------------------------------------------------------------------- /main.packl: -------------------------------------------------------------------------------- 1 | class Point { 2 | x: int; 3 | y: int; 4 | }; 5 | 6 | class Rectangle { 7 | a: Point; # the point of the start (left up corner) 8 | w: int; # width 9 | h: int; # height 10 | }; 11 | 12 | proc Point.init(x: int, y: int) { 13 | this.x = x; 14 | this.y = y; 15 | } 16 | 17 | proc Rectangle.init(x: int, y: int, w: int, h: int) { 18 | var a: Point = new Point; 19 | a.init(x, y); 20 | this.a = a; 21 | this.w = w; 22 | this.h = h; 23 | } 24 | 25 | proc main() { 26 | var r: Rectangle = new Rectangle; 27 | r.init(10, 10, 20, 30); 28 | write(0, "r: ", r, "\n"); 29 | exit(0); 30 | } 31 | 32 | 33 | # KEEP WORKING ON THE WRITE FUNCTION TO WRITE OBJECST 34 | -------------------------------------------------------------------------------- /obj/packl-array.o: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DjoCoding/PACKL/253adf2f3436bac67fd29e4b5752a10e1ef3f3bb/obj/packl-array.o -------------------------------------------------------------------------------- /obj/packl-codegen.o: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DjoCoding/PACKL/253adf2f3436bac67fd29e4b5752a10e1ef3f3bb/obj/packl-codegen.o -------------------------------------------------------------------------------- /obj/packl-context.o: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DjoCoding/PACKL/253adf2f3436bac67fd29e4b5752a10e1ef3f3bb/obj/packl-context.o -------------------------------------------------------------------------------- /obj/packl-lexer.o: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DjoCoding/PACKL/253adf2f3436bac67fd29e4b5752a10e1ef3f3bb/obj/packl-lexer.o -------------------------------------------------------------------------------- /obj/packl-operator.o: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DjoCoding/PACKL/253adf2f3436bac67fd29e4b5752a10e1ef3f3bb/obj/packl-operator.o -------------------------------------------------------------------------------- /obj/packl-parser.o: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DjoCoding/PACKL/253adf2f3436bac67fd29e4b5752a10e1ef3f3bb/obj/packl-parser.o -------------------------------------------------------------------------------- /obj/packl-printer.o: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DjoCoding/PACKL/253adf2f3436bac67fd29e4b5752a10e1ef3f3bb/obj/packl-printer.o -------------------------------------------------------------------------------- /obj/packl.o: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DjoCoding/PACKL/253adf2f3436bac67fd29e4b5752a10e1ef3f3bb/obj/packl.o -------------------------------------------------------------------------------- /obj/pvm-instructions.o: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DjoCoding/PACKL/253adf2f3436bac67fd29e4b5752a10e1ef3f3bb/obj/pvm-instructions.o -------------------------------------------------------------------------------- /packlc.c: -------------------------------------------------------------------------------- 1 | #include "src/headers/packl.h" 2 | #include 3 | 4 | typedef struct { 5 | char **value; 6 | int count; 7 | } Args; 8 | 9 | char *args_shift(Args *args) { 10 | args->count--; 11 | char *value = *args->value; 12 | args->value++; 13 | return value; 14 | } 15 | 16 | int args_end(Args *args) { 17 | return (args->count == 0); 18 | } 19 | 20 | void usage(char *program) { 21 | printf("usage: %s [OPTIONS]\n", program); 22 | printf("OPTIONS:\n"); 23 | printf("\thelp: display the usage\n"); 24 | printf("\tlex: lex the PACKL file and display the tokens\n"); 25 | printf("\tparse: parse the PACKL file and display the AST\n"); 26 | printf("\tcode: generate the PASM file\n"); 27 | printf("\tout: specify the PASM output file name\n"); 28 | } 29 | 30 | typedef enum { 31 | LEX = 0, 32 | PARSE, 33 | CODE, 34 | OUT, 35 | COUNT_FLAGS, 36 | } Config_Flags; 37 | 38 | char *flags[] = { 39 | "lex", 40 | "parse", 41 | "code", 42 | "out", 43 | }; 44 | 45 | uint8_t config[COUNT_FLAGS] = {0}; 46 | 47 | void handle_flags(Args *args, char *program, char **output) { 48 | while (!args_end(args)) { 49 | char *flag = args_shift(args); 50 | if (*flag == '-') { 51 | flag++; 52 | for (size_t i = 0; i < ARR_SIZE(flags); ++i) { 53 | if (strcmp(flag, flags[i]) == 0) { if (config[i]) { usage(program); THROW_ERROR("flag %s is already enabled", flag); } else { config[i] = 1; break; } } 54 | if (strcmp(flag, "out")) { continue; } 55 | if (args_end(args)) { usage(program); THROW_ERROR("no output file path provided"); } 56 | *output = args_shift(args); 57 | break; 58 | } 59 | 60 | } else { THROW_ERROR("invalid flag %s", flag); } 61 | } 62 | } 63 | 64 | int main(int argc, char **argv) { 65 | srand(time(NULL)); 66 | 67 | Args args = { argv, argc }; 68 | 69 | char *program = args_shift(&args); 70 | char *input_filepath = NULL; 71 | char *output_filepath = NULL; 72 | 73 | 74 | if (args_end(&args)) { usage(program); THROW_ERROR("no input file path provided"); } 75 | char *flag = args_shift(&args); 76 | 77 | if(strcmp(flag, "-help") == 0) { usage(program); exit(0); } 78 | else { 79 | input_filepath = flag; 80 | } 81 | 82 | handle_flags(&args, program, &output_filepath); 83 | 84 | if (!output_filepath) { output_filepath = "a.out"; } 85 | 86 | PACKL_Compiler c = packl_init(input_filepath, output_filepath); 87 | 88 | if (config[LEX]) { 89 | lex(&c.root_file); 90 | packl_print_tokens(c.root_file.tokens); 91 | } else if (config[PARSE]) { 92 | lex(&c.root_file); 93 | parse(&c.root_file); 94 | packl_print_ast(c.root_file.ast); 95 | } else if (config[CODE]) { 96 | compile(&c); 97 | } 98 | 99 | packl_destroy(&c); 100 | return 0; 101 | } -------------------------------------------------------------------------------- /packlr.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | int main(int argc, char **argv) { 5 | char *program = *argv++; 6 | argc--; 7 | 8 | if(argc == 0) { 9 | fprintf(stderr, "expected a file to compile"); 10 | exit(1); 11 | } 12 | 13 | int donext = 1; 14 | char *filepath = *argv++; 15 | 16 | char command[4000] = {0}; 17 | sprintf(command, "./bin/packlc %s -code -out file.pasm\n", filepath); 18 | if (system(command)) { 19 | fprintf(stderr, "compilation failed\n"); 20 | donext = 0; 21 | } 22 | 23 | 24 | sprintf(command, "./bin/pasm file.pasm\n"); 25 | if (donext && system(command)) { 26 | fprintf(stderr, "assembling failed\n"); 27 | donext = 0; 28 | } 29 | 30 | if (donext) { 31 | sprintf(command, "./bin/pvmr file.pvm\n"); 32 | system(command); 33 | } 34 | 35 | sprintf(command, "rm -f file.pasm file.pvm\n"); 36 | system(command); 37 | 38 | return 0; 39 | } 40 | -------------------------------------------------------------------------------- /src/.vscode/settings.json: -------------------------------------------------------------------------------- 1 | { 2 | "files.associations": { 3 | "*.packl": "nim", 4 | "*.pasm": "asm", 5 | "system_error": "c", 6 | "array": "c", 7 | "functional": "c", 8 | "tuple": "c", 9 | "type_traits": "c", 10 | "utility": "c", 11 | "test.C": "cpp", 12 | "error.h": "c", 13 | "string_view": "c", 14 | "initializer_list": "c", 15 | "packl-context.h": "c", 16 | "packl.h": "c", 17 | "packl-codegen.h": "c", 18 | "random": "c", 19 | "stdexcept": "c", 20 | "algorithm": "c", 21 | "atomic": "c", 22 | "bit": "c", 23 | "*.tcc": "c", 24 | "cassert": "c", 25 | "cctype": "c", 26 | "cerrno": "c", 27 | "climits": "c", 28 | "clocale": "c", 29 | "cmath": "c", 30 | "compare": "c", 31 | "concepts": "c", 32 | "cstdarg": "c", 33 | "cstddef": "c", 34 | "cstdint": "c", 35 | "cstdio": "c", 36 | "cstdlib": "c", 37 | "cwchar": "c", 38 | "cwctype": "c", 39 | "deque": "c", 40 | "string": "c", 41 | "unordered_map": "c", 42 | "vector": "c", 43 | "exception": "c", 44 | "iterator": "c", 45 | "memory": "c", 46 | "memory_resource": "c", 47 | "numeric": "c", 48 | "ios": "c", 49 | "iosfwd": "c", 50 | "limits": "c", 51 | "new": "c", 52 | "numbers": "c", 53 | "ostream": "c", 54 | "queue": "c", 55 | "streambuf": "c", 56 | "cstdbool": "c", 57 | "typeinfo": "c" 58 | } 59 | } -------------------------------------------------------------------------------- /src/headers/packl-array.h: -------------------------------------------------------------------------------- 1 | #ifndef PACKL_ARRAY_H 2 | #define PACKL_ARRAY_H 3 | 4 | #include "packl-defs.h" 5 | #include "packl-context.h" 6 | #include "pvm-instructions.h" 7 | 8 | void packl_generate_array_item_size(PACKL_Compiler *c, PACKL_File *self, PACKL_Type item_type, size_t indent); 9 | void packl_generate_array_size(PACKL_Compiler *c, PACKL_File *self, Array_Type type, size_t indent); 10 | void packl_generate_array_allocation_code(PACKL_Compiler *c, PACKL_File *self, Array_Type type, size_t indent); 11 | 12 | #endif -------------------------------------------------------------------------------- /src/headers/packl-codegen.h: -------------------------------------------------------------------------------- 1 | #ifndef PACKL_CODEGEN_H 2 | #define PACKL_CODEGEN_H 3 | 4 | #include "packl-defs.h" 5 | #include "packl-error.h" 6 | #include "packl-context.h" 7 | #include "packl-lexer.h" 8 | #include "packl-parser.h" 9 | #include "packl-array.h" 10 | #include "packl-operator.h" 11 | #include "pvm-instructions.h" 12 | #include 13 | 14 | #define codegen packl_generate_file_code 15 | 16 | PACKL_File packl_init_file(char *filename, char *fullpath); 17 | void packl_generate_file_code(PACKL_Compiler *c, PACKL_File *self); 18 | 19 | #endif -------------------------------------------------------------------------------- /src/headers/packl-context.h: -------------------------------------------------------------------------------- 1 | #ifndef PACKL_CONTEXT_H 2 | #define PACKL_CONTEXT_H 3 | 4 | #include "packl-defs.h" 5 | 6 | extern size_t data_type_size[COUNT_PACKL_TYPES]; 7 | extern char *context_item_as_cstr[COUNT_CONTEXT_ITEM_TYPES]; 8 | 9 | void packl_init_contexts(PACKL_File *self); 10 | void packl_remove_contexts(PACKL_File *self); 11 | 12 | void packl_push_new_context(PACKL_File *self); 13 | void packl_pop_context(PACKL_File *self); 14 | 15 | Context packl_get_current_context(PACKL_File *self); 16 | Context_Item *packl_get_context_item_in_current_context(PACKL_File *self, String_View id); 17 | Context_Item *packl_get_context_item_in_all_contexts(PACKL_File *self, String_View id); 18 | void packl_push_item_in_current_context(PACKL_File *self, Context_Item item); 19 | char *packl_get_context_item_type_as_cstr(Context_Item_Type type); 20 | 21 | 22 | Context_Item packl_init_var_context_item(String_View name, PACKL_Type type, size_t pos); 23 | Context_Item packl_init_func_context_item(String_View name, PACKL_Type return_type, Parameters params, size_t label_value); 24 | Context_Item packl_init_proc_context_item(String_View name, Parameters params, size_t label_value); 25 | Context_Item packl_init_module_context_item(String_View name, char *filename); 26 | Context_Item packl_init_class_context_item(PACKL_File *self, String_View name, Attributes attrs); 27 | 28 | void packl_find_item_and_report_error_if_found(PACKL_File *self, String_View name, Location loc); 29 | void packl_find_item_in_current_context_and_report_error_if_found(PACKL_File *self, String_View name, Location loc); 30 | 31 | Context_Item *packl_lookup_function_or_procedure(PACKL_File *self, String_View name); 32 | 33 | Variable packl_find_variable(PACKL_File *self, String_View name, Location loc); 34 | Context_Item *packl_find_function_or_procedure(PACKL_File *self, String_View name, Location loc); 35 | Module packl_find_module(PACKL_File *self, String_View name, Location loc); 36 | PACKL_File packl_find_used_file(PACKL_File *self, char *filename); 37 | Class *packl_find_class(PACKL_File *self, String_View name, Location loc); 38 | Attribute *packl_find_class_attr(PACKL_File *self, Class class, String_View attr_name); 39 | Method *packl_find_class_method(PACKL_File *self, Class class, String_View name); 40 | 41 | size_t packl_get_type_size(PACKL_File *self, PACKL_Type type); 42 | 43 | int packl_on_global_context(PACKL_File *self); 44 | Context_Item *packl_get_context_item_in_context(Context context, String_View id); 45 | Function *packl_find_function_in_previous_scopes(PACKL_File *self, String_View name); 46 | 47 | Function packl_init_context_function(PACKL_Type return_type, Parameters params, size_t label_value); 48 | Procedure packl_init_context_procedure(Parameters params, size_t label_value); 49 | 50 | 51 | #endif 52 | -------------------------------------------------------------------------------- /src/headers/packl-defs.h: -------------------------------------------------------------------------------- 1 | #ifndef PACKL_DEFS_H 2 | #define PACKL_DEFS_H 3 | 4 | #include "packl-error.h" 5 | #include "../../tools/sv.h" 6 | 7 | typedef struct { 8 | size_t line; 9 | size_t col; 10 | } Location; 11 | 12 | typedef struct { 13 | char **items; 14 | size_t count; 15 | size_t size; 16 | } Strings; 17 | 18 | #define LOC_FMT "(%zu, %zu)" 19 | #define LOC_UNWRAP(loc) loc.line, loc.col 20 | 21 | #define ARR_SIZE(arr) (sizeof(arr)/sizeof((arr)[0])) 22 | 23 | // LEXING 24 | typedef enum Token_Kind Token_Kind; 25 | typedef struct Token Token; 26 | typedef struct Tokens Tokens; 27 | typedef struct Lexer Lexer; 28 | 29 | 30 | // PARSING 31 | typedef struct Parser Parser; 32 | 33 | // types 34 | typedef enum Type Type; 35 | typedef struct Array_Type Array_Type; 36 | typedef enum PACKL_Type_Kind PACKL_Type_Kind; 37 | typedef union PACKL_Type_As PACKL_Type_As; 38 | typedef struct PACKL_Type PACKL_Type; 39 | 40 | // parameters 41 | typedef struct Parameter Parameter; 42 | typedef struct Parameters Parameters; 43 | 44 | // function definition 45 | typedef struct Func_Def Func_Def; 46 | 47 | // procedure defintion 48 | typedef struct Proc_Def Proc_Def; 49 | 50 | // module 51 | typedef struct Use Use; 52 | 53 | // expression 54 | typedef struct Expr_Attribute Expr_Attribute; 55 | typedef struct Expr_Method_Call Expr_Method_Call; 56 | typedef enum Expr_Operator_Kind Expr_Operator_Kind; 57 | typedef enum Expr_Operator_Input_Kind Expr_Operator_Input_Kind; 58 | typedef union Expr_Operator_Input_As Expr_Operator_Input_As; 59 | typedef struct Expr_Operator_Input Expr_Operator_Input; 60 | typedef struct Expr_Operator Expr_Operator; 61 | typedef struct Expr_SizeOf Expr_SizeOf; 62 | typedef struct Expr_Attribute Expr_Attribute; 63 | typedef enum Operator Operator; 64 | typedef struct Expr_Unary_Op Expr_Unary_Op; 65 | typedef struct Expr_Bin_Op Expr_Bin_Op; 66 | typedef union Expr_As Expr_As; 67 | typedef enum Expr_Kind Expr_Kind; 68 | typedef struct Expression Expression; 69 | typedef struct Expr_Arr Expr_Arr; 70 | typedef struct Expr_Arr_Index Expr_Arr_Index; 71 | 72 | // While Statement 73 | typedef struct While_Statement While_Statement; 74 | 75 | // For Statement 76 | typedef struct For_Statement For_Statement; 77 | 78 | // If Statement 79 | typedef struct If_Statement If_Statement; 80 | 81 | // function call 82 | typedef enum PACKL_Arg_Type PACKL_Arg_Type; 83 | typedef union PACKL_Arg_As PACKL_Arg_As; 84 | typedef struct PACKL_Arg PACKL_Arg; 85 | typedef struct PACKL_Args PACKL_Args; 86 | typedef struct Func_Call Func_Call; 87 | 88 | // Variable 89 | typedef union Variable_Format_As Variable_Format_As; 90 | typedef enum Variable_Format_Kind Variable_Format_Kind; 91 | typedef struct Variable_Format Variable_Format; 92 | 93 | // variable declaration 94 | typedef struct Var_Declaration Var_Declaration; 95 | 96 | // variable reassignement 97 | typedef struct Var_Reassign Var_Reassign; 98 | 99 | // module call 100 | typedef enum Mod_Call_Kind Mod_Call_Kind; 101 | typedef union Mod_Call_As Mod_Call_As; 102 | typedef struct Mod_Call Mod_Call; 103 | 104 | // class 105 | typedef struct Class_Def Class_Def; 106 | typedef struct Attribute Attribute; 107 | typedef struct Attributes Attributes; 108 | typedef union Method_Def_As Method_Def_As; 109 | typedef struct Method_Def Method_Def; 110 | typedef struct Method_Call Method_Call; 111 | 112 | // Nodes 113 | typedef enum Node_Kind Node_Kind; 114 | typedef union Node_As Node_As; 115 | typedef struct Node Node; 116 | 117 | typedef struct AST AST; 118 | 119 | // Context 120 | typedef enum Method_Kind Method_Kind; 121 | typedef union Method_As Method_As; 122 | typedef struct Method Method; 123 | typedef struct Methods Methods; 124 | typedef struct Class Class; 125 | typedef struct Module Module; 126 | typedef struct Function Function; 127 | typedef struct Variable Variable; 128 | typedef struct Procedure Procedure; 129 | typedef enum Context_Item_Type Context_Item_Type; 130 | typedef union Context_Item_As Context_Item_As; 131 | typedef struct Context_Item Context_Item; 132 | typedef struct Context Context; 133 | typedef struct Contexts Contexts; 134 | 135 | // Files 136 | typedef struct PACKL_File PACKL_File; 137 | typedef struct PACKL_External_Files PACKL_External_Files; 138 | typedef struct PACKL_Compiler PACKL_Compiler; 139 | 140 | enum Token_Kind { 141 | TOKEN_KIND_IDENTIFIER = 0, 142 | 143 | TOKEN_KIND_NATIVE, 144 | 145 | TOKEN_KIND_STRING_LIT, 146 | TOKEN_KIND_INTEGER_LIT, 147 | 148 | TOKEN_KIND_SEMI_COLON, 149 | TOKEN_KIND_COLON, 150 | TOKEN_KIND_COMMA, 151 | TOKEN_KIND_DOT, 152 | 153 | TOKEN_KIND_OPEN_BRACKET, 154 | TOKEN_KIND_CLOSE_BRACKET, 155 | TOKEN_KIND_OPEN_PARENT, 156 | TOKEN_KIND_CLOSE_PARENT, 157 | TOKEN_KIND_OPEN_CURLY_BRACE, 158 | TOKEN_KIND_CLOSE_CURLY_BRACE, 159 | 160 | TOKEN_KIND_EQUAL, 161 | 162 | TOKEN_KIND_PLUS, 163 | TOKEN_KIND_DOUBLE_PLUS, 164 | TOKEN_KIND_MINUS, 165 | TOKEN_KIND_DOUBLE_MINUS, 166 | TOKEN_KIND_STAR, 167 | TOKEN_KIND_SLASH, 168 | TOKEN_KIND_MOD, 169 | 170 | TOKEN_KIND_DOUBLE_EQUAL, 171 | TOKEN_KIND_LESS, 172 | TOKEN_KIND_GREATER, 173 | TOKEN_KIND_LESS_OR_EQUAL, 174 | TOKEN_KIND_GREATER_OR_EQUAL, 175 | TOKEN_KIND_NOT, 176 | TOKEN_KIND_NOT_EQUAL, 177 | 178 | TOKEN_KIND_PROC, 179 | TOKEN_KIND_FUNC, 180 | TOKEN_KIND_RETURN, 181 | TOKEN_KIND_VAR, 182 | TOKEN_KIND_IF, 183 | TOKEN_KIND_ELSE, 184 | TOKEN_KIND_WHILE, 185 | TOKEN_KIND_FOR, 186 | TOKEN_KIND_IN, 187 | TOKEN_KIND_USE, 188 | TOKEN_KIND_AS, 189 | TOKEN_KIND_CLASS, 190 | 191 | TOKEN_KIND_OR, 192 | TOKEN_KIND_AND, 193 | TOKEN_KIND_XOR, 194 | 195 | TOKEN_KIND_ARRAY, 196 | TOKEN_KIND_INT_TYPE, 197 | TOKEN_KIND_STR_TYPE, 198 | TOKEN_KIND_PTR_TYPE, 199 | 200 | TOKEN_KIND_OPERATOR, 201 | 202 | TOKEN_KIND_END, 203 | 204 | COUNT_TOKEN_KINDS, 205 | }; 206 | 207 | struct Token { 208 | Location loc; 209 | Token_Kind kind; 210 | String_View text; 211 | }; 212 | 213 | struct Tokens { 214 | Token *items; 215 | size_t count; 216 | size_t size; 217 | }; 218 | 219 | struct Lexer { 220 | String_View source; 221 | Location loc; 222 | size_t current; 223 | }; 224 | 225 | enum Node_Kind { 226 | NODE_KIND_FUNC_CALL = 0, 227 | NODE_KIND_NATIVE_CALL, 228 | NODE_KIND_METHOD_CALL, 229 | NODE_KIND_PROC_DEF, 230 | NODE_KIND_FUNC_DEF, 231 | NODE_KIND_METHOD_DEF, 232 | NODE_KIND_RETURN, 233 | NODE_KIND_VAR_DECLARATION, 234 | NODE_KIND_VAR_REASSIGN, 235 | NODE_KIND_EXPR, 236 | NODE_KIND_IF, 237 | NODE_KIND_WHILE, 238 | NODE_KIND_FOR, 239 | NODE_KIND_USE, 240 | NODE_KIND_MOD_CALL, 241 | NODE_KIND_CLASS, 242 | }; 243 | 244 | 245 | enum Type { 246 | PACKL_TYPE_INT = 0, 247 | PACKL_TYPE_STR, 248 | PACKL_TYPE_PTR, 249 | PACKL_TYPE_VOID, 250 | COUNT_PACKL_TYPES, 251 | }; 252 | 253 | struct Array_Type { 254 | PACKL_Type *item_type; 255 | size_t size; 256 | }; 257 | 258 | enum PACKL_Type_Kind { 259 | PACKL_TYPE_BASIC, 260 | PACKL_TYPE_ARRAY, 261 | PACKL_TYPE_USER_DEFINED, 262 | }; 263 | 264 | union PACKL_Type_As { 265 | Type basic; 266 | Array_Type array; 267 | String_View user_defined; 268 | }; 269 | 270 | struct PACKL_Type { 271 | PACKL_Type_Kind kind; 272 | PACKL_Type_As as; 273 | }; 274 | 275 | enum Expr_Kind { 276 | EXPR_KIND_BIN_OP = 0, 277 | EXPR_KIND_PRE_UNARY_OP, 278 | EXPR_KIND_POST_UNARY_OP, 279 | EXPR_KIND_INTEGER, 280 | EXPR_KIND_STRING, 281 | EXPR_KIND_ID, 282 | EXPR_KIND_FUNC_CALL, 283 | EXPR_KIND_NATIVE_CALL, 284 | EXPR_KIND_MOD_CALL, 285 | EXPR_KIND_ARRAY, 286 | EXPR_KIND_ARRAY_INDEXING, 287 | EXPR_KIND_OBJECT_ATTRIBUTE, 288 | EXPR_KIND_OBJECT_METHOD, 289 | EXPR_KIND_NOT_INITIALIZED, 290 | EXPR_KIND_OPERATOR, 291 | }; 292 | 293 | enum Operator { 294 | OP_PLUS = 0, 295 | OP_MINUS, 296 | OP_MUL, 297 | OP_DIV, 298 | OP_MOD, 299 | OP_L, 300 | OP_G, 301 | OP_LE, 302 | OP_GE, 303 | OP_EQ, 304 | OP_INC, 305 | OP_DEC, 306 | OP_AND, 307 | OP_XOR, 308 | OP_OR, 309 | OP_NOT, 310 | OP_NE, 311 | }; 312 | 313 | struct Expr_Arr { 314 | Expression *items; 315 | size_t count; 316 | size_t size; 317 | }; 318 | 319 | struct Expr_Arr_Index { 320 | String_View name; 321 | Expression *index; 322 | }; 323 | 324 | struct Expr_Bin_Op { 325 | Expression *lhs, *rhs; 326 | Operator op; 327 | }; 328 | 329 | struct Expr_Unary_Op { 330 | Expression *operand; 331 | Operator op; 332 | }; 333 | 334 | struct Expr_Attribute { 335 | String_View obj_name; 336 | String_View attr; 337 | }; 338 | 339 | enum Expr_Operator_Input_Kind { 340 | INPUT_KIND_TYPE = 0, 341 | INPUT_KIND_ID, 342 | }; 343 | 344 | union Expr_Operator_Input_As { 345 | PACKL_Type type; 346 | String_View identifier; 347 | }; 348 | 349 | enum Expr_Operator_Kind { 350 | NEW_OPERATOR = 0, 351 | SIZEOF_OPERATOR, 352 | }; 353 | 354 | struct Expr_Operator_Input { 355 | Expr_Operator_Input_Kind kind; 356 | Expr_Operator_Input_As as; 357 | }; 358 | 359 | struct Expr_Operator { 360 | Expr_Operator_Kind op; 361 | Expr_Operator_Input input; 362 | }; 363 | 364 | union Expr_As { 365 | Expr_Bin_Op bin; 366 | Expr_Unary_Op unary; 367 | 368 | String_View value; 369 | 370 | int64_t integer; 371 | Func_Call *func; 372 | Mod_Call *mod; 373 | 374 | Method_Call *method; 375 | Expr_Attribute attr; 376 | 377 | Expr_Arr arr; 378 | Expr_Arr_Index arr_index; 379 | 380 | Expr_Operator operator; 381 | }; 382 | 383 | struct Expression { 384 | Expr_Kind kind; 385 | Expr_As as; 386 | Location loc; 387 | }; 388 | 389 | struct PACKL_Arg { 390 | Expression expr; 391 | }; 392 | 393 | struct PACKL_Args { 394 | PACKL_Arg *items; 395 | size_t count; 396 | size_t size; 397 | }; 398 | 399 | struct Attribute { 400 | PACKL_Type type; 401 | size_t type_size; // used later when making class contexts 402 | String_View name; 403 | size_t offset; 404 | }; 405 | 406 | struct Attributes { 407 | Attribute *items; 408 | size_t count; 409 | size_t size; 410 | }; 411 | 412 | struct Parameter { 413 | PACKL_Type type; 414 | String_View name; 415 | }; 416 | 417 | struct Parameters { 418 | Parameter *items; 419 | size_t count; 420 | size_t size; 421 | }; 422 | 423 | struct Func_Def { 424 | String_View name; 425 | Parameters params; 426 | AST *body; 427 | PACKL_Type return_type; 428 | }; 429 | 430 | struct Proc_Def { 431 | String_View name; 432 | Parameters params; 433 | AST *body; 434 | }; 435 | 436 | enum Variable_Format_Kind { 437 | VARIABLE_FORMAT_BASIC, 438 | VARIABLE_FORMAT_ARRAY, 439 | VARIABLE_FORMAT_CLASS, 440 | }; 441 | 442 | union Variable_Format_As { 443 | Expression index; 444 | String_View attr; 445 | }; 446 | 447 | struct Variable_Format { 448 | String_View name; 449 | Variable_Format_Kind kind; 450 | Variable_Format_As as; 451 | }; 452 | 453 | struct Var_Reassign { 454 | Variable_Format format; 455 | Expression value; 456 | }; 457 | 458 | struct While_Statement { 459 | Expression condition; 460 | AST *body; 461 | }; 462 | 463 | struct If_Statement { 464 | Expression condition; 465 | AST *body; 466 | AST *esle; // the else part of the if statement, will be set to NULL if none is provided 467 | }; 468 | 469 | struct For_Statement { 470 | String_View iter; 471 | PACKL_Type iter_type; 472 | PACKL_Args args; 473 | AST *body; 474 | }; 475 | 476 | struct Var_Declaration { 477 | String_View name; 478 | PACKL_Type type; 479 | Expression value; 480 | }; 481 | 482 | enum Method_Kind { 483 | METHOD_KIND_FUNCTION = 0, 484 | METHOD_KIND_PROCEDURE, 485 | }; 486 | 487 | union Method_Def_As { 488 | Func_Def func; 489 | Proc_Def proc; 490 | }; 491 | 492 | struct Method_Def { 493 | Method_Kind kind; 494 | String_View class_name; 495 | Method_Def_As as; 496 | }; 497 | 498 | struct Func_Call { 499 | String_View name; 500 | PACKL_Args args; 501 | }; 502 | 503 | struct Method_Call { 504 | String_View object_name; 505 | Func_Call func; 506 | }; 507 | 508 | struct Use { 509 | String_View filename; 510 | String_View alias; 511 | int has_alias; 512 | }; 513 | 514 | enum Mod_Call_Kind { 515 | MODULE_CALL_FUNC_CALL = 0, 516 | MODULE_CALL_VARIABLE, 517 | }; 518 | 519 | union Mod_Call_As { 520 | Func_Call func_call; 521 | String_View var_name; 522 | }; 523 | 524 | struct Mod_Call { 525 | String_View name; 526 | Mod_Call_Kind kind; 527 | Mod_Call_As as; 528 | }; 529 | 530 | struct Class_Def { 531 | String_View name; 532 | Attributes attrs; 533 | }; 534 | 535 | union Node_As { 536 | Func_Call func_call; 537 | Method_Call method_call; 538 | 539 | Proc_Def proc_def; 540 | Func_Def func_def; 541 | Method_Def method_def; 542 | 543 | Expression expr; 544 | 545 | If_Statement fi; 546 | While_Statement hwile; 547 | For_Statement rof; 548 | 549 | Var_Declaration var_dec; 550 | Var_Reassign var; 551 | Expression ret; 552 | 553 | Use use; 554 | Mod_Call mod_call; 555 | Class_Def class; 556 | }; 557 | 558 | struct Node { 559 | Node_Kind kind; 560 | Node_As as; 561 | Location loc; 562 | }; 563 | 564 | struct AST { 565 | Node *items; 566 | size_t count; 567 | size_t size; 568 | }; 569 | 570 | struct Parser { 571 | size_t current; 572 | }; 573 | 574 | struct Procedure { 575 | Parameters params; 576 | size_t label_value; 577 | }; 578 | 579 | struct Variable { 580 | PACKL_Type type; 581 | size_t stack_pos; 582 | }; 583 | 584 | struct Function { 585 | size_t label_value; 586 | Parameters params; 587 | PACKL_Type return_type; 588 | }; 589 | 590 | struct Module { 591 | char *filename; 592 | }; 593 | 594 | union Method_As { 595 | Function func; 596 | Procedure proc; 597 | }; 598 | 599 | struct Method { 600 | String_View name; 601 | Method_Kind kind; 602 | Method_As as; 603 | }; 604 | 605 | struct Methods { 606 | Method *items; 607 | size_t count; 608 | size_t size; 609 | }; 610 | 611 | struct Class { 612 | String_View name; 613 | size_t attrs_size; 614 | Attributes attrs; 615 | Methods methods; 616 | }; 617 | 618 | enum Context_Item_Type { 619 | CONTEXT_ITEM_TYPE_PROCEDURE = 0, 620 | CONTEXT_ITEM_TYPE_VARIABLE, 621 | CONTEXT_ITEM_TYPE_FUNCTION, 622 | CONTEXT_ITEM_TYPE_MODULE, 623 | CONTEXT_ITEM_TYPE_CLASS, 624 | COUNT_CONTEXT_ITEM_TYPES, 625 | }; 626 | 627 | union Context_Item_As { 628 | Procedure proc; 629 | Variable variable; 630 | Function func; 631 | Module module; 632 | Class class; 633 | }; 634 | 635 | struct Context_Item { 636 | String_View name; 637 | Context_Item_Type type; 638 | Context_Item_As as; 639 | }; 640 | 641 | struct Context { 642 | Context_Item *items; 643 | size_t count; 644 | size_t size; 645 | size_t stack_size; 646 | }; 647 | 648 | struct Contexts { 649 | Context *items; 650 | size_t count; 651 | size_t size; 652 | }; 653 | 654 | struct PACKL_External_Files { 655 | PACKL_File *items; 656 | size_t count; 657 | size_t size; 658 | }; 659 | 660 | struct PACKL_File { 661 | char *filename; 662 | char *fullpath; 663 | 664 | Tokens tokens; 665 | AST ast; 666 | 667 | Lexer lexer; 668 | Parser parser; 669 | 670 | Contexts contexts; 671 | 672 | Strings root_files; 673 | PACKL_External_Files used_files; 674 | }; 675 | 676 | struct PACKL_Compiler { 677 | char *output; 678 | FILE *f; 679 | char *entry_file_path; 680 | bool has_entry; 681 | PACKL_File root_file; 682 | size_t label_value; 683 | size_t stack_size; 684 | }; 685 | 686 | 687 | #endif -------------------------------------------------------------------------------- /src/headers/packl-error.h: -------------------------------------------------------------------------------- 1 | #ifndef PACKL_ERROR_H 2 | #define PACKL_ERROR_H 3 | 4 | #include "../../tools/error.h" 5 | 6 | #define PACKL_ERROR(filename, ...) \ 7 | do { \ 8 | fprintf(stderr, "%s: ", filename); \ 9 | THROW_ERROR(__VA_ARGS__); \ 10 | } while(0) 11 | 12 | #define PACKL_ERROR_LOC(filename, loc, ...) \ 13 | do { \ 14 | fprintf(stderr, "%s:" LOC_FMT ": ", filename, LOC_UNWRAP(loc)); \ 15 | THROW_ERROR(__VA_ARGS__); \ 16 | } while(0) 17 | 18 | 19 | 20 | #endif -------------------------------------------------------------------------------- /src/headers/packl-lexer.h: -------------------------------------------------------------------------------- 1 | #ifndef PACKL_LEXER_H 2 | #define PACKL_LEXER_H 3 | 4 | #include "packl-defs.h" 5 | 6 | 7 | extern char *builtin_operators[]; 8 | 9 | #define lpeek packl_lexer_peek 10 | #define ladv packl_lexer_advance 11 | #define leof packl_lexer_eof 12 | #define lread packl_lexer_read_token 13 | #define lex packl_lexer_lex 14 | 15 | void packl_lexer_lex(PACKL_File *self); 16 | 17 | #endif -------------------------------------------------------------------------------- /src/headers/packl-operator.h: -------------------------------------------------------------------------------- 1 | #ifndef PACKL_OPERATOR_H 2 | #define PACKL_OPERATOR_H 3 | 4 | #include "packl-defs.h" 5 | #include "packl-context.h" 6 | 7 | size_t packl_get_operator_input_size(PACKL_Compiler *c, PACKL_File *self, Expr_Operator_Input input); 8 | 9 | #endif -------------------------------------------------------------------------------- /src/headers/packl-parser.h: -------------------------------------------------------------------------------- 1 | #ifndef PACKL_PARSER_H 2 | #define PACKL_PARSER_H 3 | 4 | #include "packl-defs.h" 5 | #include "packl-error.h" 6 | #include 7 | 8 | #define ppeek(self) packl_parser_peek(self, 0) 9 | #define ppeek_(self, ahead) packl_parser_peek(self, ahead) 10 | #define padv packl_parser_advance 11 | #define peot packl_parser_eot 12 | #define pexp packl_parser_expect 13 | #define pstmt packl_parser_parse_statement 14 | #define parse packl_parser_parse 15 | 16 | void packl_parser_parse(PACKL_File *self); 17 | 18 | 19 | #endif -------------------------------------------------------------------------------- /src/headers/packl-printer.h: -------------------------------------------------------------------------------- 1 | #ifndef PACKL_PRINTER_H 2 | #define PACKL_PRINTER_H 3 | 4 | #include "packl-defs.h" 5 | #include "packl-lexer.h" 6 | 7 | void packl_print_tokens(Tokens tokens); 8 | void packl_print_ast(AST ast); 9 | 10 | #endif -------------------------------------------------------------------------------- /src/headers/packl.h: -------------------------------------------------------------------------------- 1 | #ifndef PACKL_H 2 | #define PACKL_H 3 | 4 | 5 | #include "packl-defs.h" 6 | #include "packl-lexer.h" 7 | #include "packl-parser.h" 8 | #include "packl-codegen.h" 9 | #include "packl-context.h" 10 | #include "packl-printer.h" 11 | 12 | #define compile packl_compile 13 | 14 | PACKL_Compiler packl_init(char *input, char *output); 15 | void packl_destroy(PACKL_Compiler *c); 16 | void packl_compile(PACKL_Compiler *c); 17 | 18 | #endif -------------------------------------------------------------------------------- /src/headers/pvm-instructions.h: -------------------------------------------------------------------------------- 1 | #ifndef PVM_INSTRUCTIONS_H 2 | #define PVM_INSTRUCTIONS_H 3 | 4 | #include "packl-defs.h" 5 | 6 | #define PACKL_COMMENT(f, indent, ...) { fprint_indent(f, indent); fprintf(f, "; " __VA_ARGS__); fprintf(f, "\n"); } 7 | 8 | void fprintfln(FILE *f); 9 | void fprint_indent(FILE *f, size_t indent); 10 | void packl_generate_label(PACKL_Compiler *c, size_t label_value, size_t indent); 11 | void packl_generate_push(PACKL_Compiler *c, int64_t value, size_t indent); 12 | void packl_generate_pushs(PACKL_Compiler *c, String_View value, size_t indent); 13 | void packl_generate_nop(PACKL_Compiler *c, size_t indent); 14 | void packl_generate_halt(PACKL_Compiler *c, size_t indent); 15 | void packl_generate_pop(PACKL_Compiler *c, size_t indent); 16 | void packl_generate_add(PACKL_Compiler *c, size_t indent); 17 | void packl_generate_sub(PACKL_Compiler *c, size_t indent); 18 | void packl_generate_mul(PACKL_Compiler *c, size_t indent); 19 | void packl_generate_div(PACKL_Compiler *c, size_t indent); 20 | void packl_generate_mod(PACKL_Compiler *c, size_t indent); 21 | void packl_generate_cmpl(PACKL_Compiler *c, size_t indent); 22 | void packl_generate_cmpg(PACKL_Compiler *c, size_t indent); 23 | void packl_generate_cmpge(PACKL_Compiler *c, size_t indent); 24 | void packl_generate_cmple(PACKL_Compiler *c, size_t indent); 25 | void packl_generate_cmpe(PACKL_Compiler *c, size_t indent); 26 | void packl_generate_cmpne(PACKL_Compiler *c, size_t indent); 27 | void packl_generate_swap(PACKL_Compiler *c, size_t indent); 28 | void packl_generate_dup(PACKL_Compiler *c, size_t indent); 29 | void packl_generate_inswap(PACKL_Compiler *c, int64_t value, size_t indent); 30 | void packl_generate_indup(PACKL_Compiler *c, int64_t value, size_t indent); 31 | void packl_generate_syscall(PACKL_Compiler *c, int64_t value, size_t indent); 32 | void packl_generate_writei(PACKL_Compiler *c, size_t indent); 33 | void packl_generate_jmp(PACKL_Compiler *c, size_t value, size_t indent); 34 | void packl_generate_cmp(PACKL_Compiler *c, size_t indent); 35 | void packl_generate_jz(PACKL_Compiler *c, size_t value, size_t indent); 36 | void packl_generate_jle(PACKL_Compiler *c, size_t value, size_t indent); 37 | void packl_generate_jl(PACKL_Compiler *c, size_t value, size_t indent); 38 | void packl_generate_jge(PACKL_Compiler *c, size_t value, size_t indent); 39 | void packl_generate_jg(PACKL_Compiler *c, size_t value, size_t indent); 40 | void packl_generate_putc(PACKL_Compiler *c, size_t indent); 41 | void packl_generate_call(PACKL_Compiler *c, size_t value, size_t indent); 42 | void packl_generate_ret(PACKL_Compiler *c, size_t indent); 43 | void packl_generate_store(PACKL_Compiler *c, size_t indent); 44 | void packl_generate_load(PACKL_Compiler *c, size_t indent); 45 | void packl_generate_readc(PACKL_Compiler *c, size_t indent); 46 | void packl_generate_loadb(PACKL_Compiler *c, size_t indent); 47 | void packl_generate_storeb(PACKL_Compiler *c, size_t indent); 48 | void packl_generate_ssp(PACKL_Compiler *c, size_t indent); 49 | void packl_generate_not(PACKL_Compiler *c, size_t indent); 50 | void packl_generate_and(PACKL_Compiler *c, size_t indent); 51 | void packl_generate_or(PACKL_Compiler *c, size_t indent); 52 | void packl_generate_xor(PACKL_Compiler *c, size_t indent); 53 | 54 | #endif -------------------------------------------------------------------------------- /src/packl-array.c: -------------------------------------------------------------------------------- 1 | #include "headers/packl-array.h" 2 | 3 | void packl_generate_array_item_size(PACKL_Compiler *c, PACKL_File *self, PACKL_Type item_type, size_t indent) { 4 | size_t item_size = packl_get_type_size(self, item_type); 5 | packl_generate_push(c, (int64_t)item_size, indent); 6 | } 7 | 8 | void packl_generate_array_size(PACKL_Compiler *c, PACKL_File *self, Array_Type type, size_t indent) { 9 | size_t size = type.size; 10 | packl_generate_array_item_size(c, self, *type.item_type, indent); 11 | packl_generate_push(c, (int64_t)size, indent); 12 | packl_generate_mul(c, indent); 13 | } 14 | 15 | void packl_generate_array_allocation_code(PACKL_Compiler *c, PACKL_File *self, Array_Type type, size_t indent) { 16 | packl_generate_array_size(c, self, type, indent); 17 | packl_generate_syscall(c, 2, indent); // the alloc syscall 18 | } 19 | -------------------------------------------------------------------------------- /src/packl-context.c: -------------------------------------------------------------------------------- 1 | #include "headers/packl-context.h" 2 | 3 | size_t data_type_size[COUNT_PACKL_TYPES] = {8, 8, 8}; 4 | 5 | char *context_item_as_cstr[COUNT_CONTEXT_ITEM_TYPES] = { 6 | "procedure", 7 | "variable", 8 | "function", 9 | "class", 10 | }; 11 | 12 | Context packl_get_current_context(PACKL_File *self) { 13 | return self->contexts.items[self->contexts.count - 1]; 14 | } 15 | 16 | int packl_on_global_context(PACKL_File *self) { 17 | return self->contexts.count == 1; 18 | } 19 | 20 | void packl_destroy_context(Context context) { 21 | for (size_t i = 0; i < context.count; ++i) { 22 | Context_Item item = context.items[i]; 23 | if (context.items[i].type == CONTEXT_ITEM_TYPE_PROCEDURE) { 24 | free(item.as.proc.params.items); 25 | item.as.proc.params.size = 0; 26 | } 27 | } 28 | } 29 | 30 | void packl_pop_context(PACKL_File *self) { 31 | Context current = packl_get_current_context(self); 32 | packl_destroy_context(current); 33 | self->contexts.count--; 34 | } 35 | 36 | void packl_push_new_context(PACKL_File *self) { 37 | Context context = {0}; 38 | DA_INIT(&context, sizeof(Context_Item)); 39 | DA_APPEND(&self->contexts, context); 40 | } 41 | 42 | void packl_init_contexts(PACKL_File *self) { 43 | DA_INIT(&self->contexts, sizeof(Context)); 44 | } 45 | 46 | void packl_remove_contexts(PACKL_File *self) { 47 | free(self->contexts.items); 48 | } 49 | 50 | Context_Item *packl_get_context_item_in_context(Context context, String_View id) { 51 | for (size_t i = 0; i < context.count; ++i) { 52 | if (sv_eq(context.items[i].name, id)) { return &context.items[i]; } 53 | } 54 | return NULL; 55 | } 56 | 57 | Context_Item *packl_get_context_item_in_current_context(PACKL_File *self, String_View id) { 58 | return packl_get_context_item_in_context(packl_get_current_context(self), id); 59 | } 60 | 61 | Context_Item *packl_get_context_item_in_all_contexts(PACKL_File *self, String_View id) { 62 | for (size_t i = self->contexts.count - 1;; --i) { 63 | Context context = self->contexts.items[i]; 64 | Context_Item *item = packl_get_context_item_in_context(context, id); 65 | if (item) { return item; } 66 | if (i == 0) { break; } 67 | } 68 | return NULL; 69 | } 70 | 71 | char *packl_get_context_item_type_as_cstr(Context_Item_Type type) { 72 | return context_item_as_cstr[type]; 73 | } 74 | 75 | void packl_push_item_in_current_context(PACKL_File *self, Context_Item item) { 76 | DA_APPEND(&self->contexts.items[self->contexts.count - 1], item); 77 | } 78 | 79 | Parameters packl_copy_params(Parameters params) { 80 | Parameters out = {0}; 81 | out.items = malloc(sizeof(Parameter) * params.count); 82 | out.count = out.size = params.count; 83 | memcpy(out.items, params.items, sizeof(Parameter) * params.count); 84 | return out; 85 | } 86 | 87 | Variable packl_init_context_variable(PACKL_Type type, size_t pos) { 88 | Variable var = {0}; 89 | var.stack_pos = pos; 90 | var.type = type; 91 | return var; 92 | } 93 | 94 | size_t packl_get_array_size(PACKL_File *self, Array_Type arr_type) { 95 | size_t size = arr_type.size; 96 | size_t item_size = 0; 97 | 98 | PACKL_Type item_type = *arr_type.item_type; 99 | 100 | switch(item_type.kind) { 101 | case PACKL_TYPE_ARRAY: 102 | item_size = packl_get_array_size(self,item_type.as.array); 103 | break; 104 | default: 105 | item_size = packl_get_type_size(self, item_type); 106 | } 107 | 108 | return size * item_size; 109 | } 110 | 111 | size_t packl_get_user_defined_type(PACKL_File *self, String_View type_name) { 112 | Context_Item *item = packl_get_context_item_in_all_contexts(self, type_name); 113 | if (!item) { 114 | PACKL_ERROR(self->filename, "`" SV_FMT "` type not declared yet", SV_UNWRAP(type_name)); 115 | } 116 | 117 | if (item->type != CONTEXT_ITEM_TYPE_CLASS) { 118 | PACKL_ERROR(self->filename, "`" SV_FMT "` is not a type", SV_UNWRAP(type_name)); 119 | } 120 | 121 | return item->as.class.attrs_size; 122 | } 123 | 124 | size_t packl_get_type_size(PACKL_File *self, PACKL_Type type) { 125 | switch(type.kind) { 126 | case PACKL_TYPE_BASIC: 127 | return data_type_size[type.as.basic]; 128 | case PACKL_TYPE_ARRAY: 129 | return packl_get_array_size(self, type.as.array); 130 | case PACKL_TYPE_USER_DEFINED: 131 | return packl_get_user_defined_type(self, type.as.user_defined); 132 | default: 133 | ASSERT(false, "unreachable"); 134 | } 135 | } 136 | 137 | size_t packl_set_class_attrs_offset(PACKL_File *self, String_View class_name, Attributes attrs) { 138 | size_t offset = 0; 139 | 140 | for(size_t i = 0; i < attrs.count; ++i) { 141 | attrs.items[i].offset = offset; 142 | PACKL_Type attr_type = attrs.items[i].type; 143 | 144 | // support for self referencing classes 145 | if (attr_type.kind == PACKL_TYPE_USER_DEFINED && sv_eq(attr_type.as.user_defined, class_name)) { 146 | attrs.items[i].type_size = 8; // sizeof(ptr) 147 | } else { 148 | attrs.items[i].type_size = packl_get_type_size(self, attrs.items[i].type); 149 | } 150 | 151 | offset += attrs.items[i].type_size; 152 | } 153 | 154 | // the last offset will be the size of the whole structure 155 | return offset; 156 | } 157 | 158 | Class packl_init_context_class(PACKL_File *self, String_View name, Attributes attrs) { 159 | Class class = {0}; 160 | class.name = name; 161 | class.attrs_size = packl_set_class_attrs_offset(self, name, attrs); 162 | class.attrs = attrs; 163 | return class; 164 | } 165 | 166 | Function packl_init_context_function(PACKL_Type return_type, Parameters params, size_t label_value) { 167 | Function func = {0}; 168 | func.label_value = label_value; 169 | func.params = packl_copy_params(params); 170 | func.return_type = return_type; 171 | return func; 172 | } 173 | 174 | Function packl_init_context_function(PACKL_Type return_type, Parameters params, size_t label_value); 175 | Procedure packl_init_context_procedure(Parameters params, size_t label_value); 176 | 177 | Procedure packl_init_context_procedure(Parameters params, size_t label_value) { 178 | Procedure proc = {0}; 179 | proc.label_value = label_value; 180 | proc.params = packl_copy_params(params); 181 | return proc; 182 | } 183 | 184 | Module packl_init_context_module(char *filename) { 185 | Module module = {0}; 186 | module.filename = filename; 187 | return module; 188 | } 189 | 190 | Context_Item packl_init_var_context_item(String_View name, PACKL_Type type, size_t pos) { 191 | Variable var = packl_init_context_variable(type, pos); 192 | return (Context_Item) { .name = name, .type = CONTEXT_ITEM_TYPE_VARIABLE, .as.variable = var }; 193 | } 194 | 195 | Context_Item packl_init_func_context_item(String_View name, PACKL_Type return_type, Parameters params, size_t label_value) { 196 | Function func = packl_init_context_function(return_type, params, label_value); 197 | return (Context_Item) { .name = name, .type = CONTEXT_ITEM_TYPE_FUNCTION, .as.func = func }; 198 | } 199 | 200 | Context_Item packl_init_proc_context_item(String_View name, Parameters params, size_t label_value) { 201 | Procedure proc = packl_init_context_procedure(params, label_value); 202 | return (Context_Item) { .name = name, .type = CONTEXT_ITEM_TYPE_PROCEDURE, .as.proc = proc }; 203 | } 204 | 205 | Context_Item packl_init_module_context_item(String_View name, char *filename) { 206 | Module module = packl_init_context_module(filename); 207 | return (Context_Item) { .name = name, .type = CONTEXT_ITEM_TYPE_MODULE, .as.module = module }; 208 | } 209 | 210 | Context_Item packl_init_class_context_item(PACKL_File *self, String_View name, Attributes attrs) { 211 | Class class = packl_init_context_class(self, name, attrs); 212 | DA_INIT(&class.methods, sizeof(Method)); 213 | return (Context_Item) { .name = name, .type = CONTEXT_ITEM_TYPE_CLASS, .as.class = class }; 214 | } 215 | 216 | void packl_find_item_and_report_error_if_found(PACKL_File *self, String_View name, Location loc) { 217 | Context_Item *item = packl_get_context_item_in_all_contexts(self, name); 218 | if (!item) { return; } 219 | PACKL_ERROR_LOC(self->filename, loc, SV_FMT " declared twice, first declared as %s", SV_UNWRAP(name), context_item_as_cstr[item->type]); 220 | } 221 | 222 | void packl_find_item_in_current_context_and_report_error_if_found(PACKL_File *self, String_View name, Location loc) { 223 | Context_Item *item = packl_get_context_item_in_current_context(self, name); 224 | if (!item) { return; } 225 | PACKL_ERROR_LOC(self->filename, loc, SV_FMT " declared twice, first declared as %s", SV_UNWRAP(name), context_item_as_cstr[item->type]); 226 | } 227 | 228 | Variable packl_find_variable(PACKL_File *self, String_View name, Location loc) { 229 | Context_Item *item = packl_get_context_item_in_all_contexts(self, name); 230 | if (!item) { PACKL_ERROR_LOC(self->filename, loc, "variable `" SV_FMT "` referenced before declaration", SV_UNWRAP(name)); } 231 | if (item->type != CONTEXT_ITEM_TYPE_VARIABLE) { PACKL_ERROR_LOC(self->filename, loc, "expected `" SV_FMT "` to be a variable but found as %s", SV_UNWRAP(name), context_item_as_cstr[item->type]); } 232 | return item->as.variable; 233 | } 234 | 235 | Class *packl_find_class(PACKL_File *self, String_View name, Location loc) { 236 | Context_Item *item = packl_get_context_item_in_all_contexts(self, name); 237 | if (!item) { PACKL_ERROR_LOC(self->filename, loc, "class `" SV_FMT "` referenced before declaration", SV_UNWRAP(name)); } 238 | if (item->type != CONTEXT_ITEM_TYPE_CLASS) { PACKL_ERROR_LOC(self->filename, loc, "expected `" SV_FMT "` to be a class but found as %s", SV_UNWRAP(name), context_item_as_cstr[item->type]); } 239 | return &item->as.class; 240 | } 241 | 242 | Method *packl_find_class_method(PACKL_File *self, Class class, String_View name) { 243 | for(size_t i = 0; i < class.methods.count; ++i) { 244 | Method method = class.methods.items[i]; 245 | if (sv_eq(method.name, name)) { 246 | return &class.methods.items[i]; 247 | } 248 | } 249 | return NULL; 250 | } 251 | 252 | Attribute *packl_find_class_attr(PACKL_File *self, Class class, String_View attr_name) { 253 | for(size_t i = 0; i < class.attrs.count; ++i) { 254 | Attribute attr = class.attrs.items[i]; 255 | if (sv_eq(attr.name, attr_name)) { 256 | return &class.attrs.items[i]; 257 | } 258 | } 259 | return NULL; 260 | } 261 | 262 | Module packl_find_module(PACKL_File *self, String_View name, Location loc) { 263 | Context_Item *item = packl_get_context_item_in_all_contexts(self, name); 264 | if (!item) { PACKL_ERROR_LOC(self->filename, loc, "module `" SV_FMT "` referenced before usage", SV_UNWRAP(name)); } 265 | if (item->type != CONTEXT_ITEM_TYPE_MODULE) { PACKL_ERROR_LOC(self->filename, loc, "expected `" SV_FMT "` to be a module but found as %s", SV_UNWRAP(name), context_item_as_cstr[item->type]); } 266 | return item->as.module; 267 | } 268 | 269 | Context_Item *packl_lookup_function_or_procedure(PACKL_File *self, String_View name) { 270 | Context_Item *item = packl_get_context_item_in_all_contexts(self, name); 271 | if (!item) { return NULL; } 272 | if (item->type != CONTEXT_ITEM_TYPE_FUNCTION && item->type != CONTEXT_ITEM_TYPE_PROCEDURE) { PACKL_ERROR(self->filename, "expected `" SV_FMT "` to be a function or a procedure but found as %s", SV_UNWRAP(name), context_item_as_cstr[item->type]); } 273 | return item; 274 | } 275 | 276 | 277 | Context_Item *packl_find_function_or_procedure(PACKL_File *self, String_View name, Location loc) { 278 | Context_Item *item = packl_get_context_item_in_all_contexts(self, name); 279 | if (!item) { PACKL_ERROR_LOC(self->filename, loc, "function `" SV_FMT "` called before declaration", SV_UNWRAP(name)); } 280 | if (item->type != CONTEXT_ITEM_TYPE_FUNCTION && item->type != CONTEXT_ITEM_TYPE_PROCEDURE) { PACKL_ERROR_LOC(self->filename, loc, "expected `" SV_FMT "` to be a function or a procedure but found as %s", SV_UNWRAP(name), context_item_as_cstr[item->type]); } 281 | return item; 282 | } 283 | 284 | PACKL_File packl_find_used_file(PACKL_File *self, char *filename) { 285 | for(size_t i = 0; i < self->used_files.count; ++i) { 286 | PACKL_File file = self->used_files.items[i]; 287 | if (strcmp(file.filename, filename) == 0) { 288 | return file; 289 | } 290 | } 291 | ASSERT(false, "unreachable"); 292 | } 293 | 294 | // this is used for finding the function to execute recursion 295 | Function *packl_find_function_in_previous_scopes(PACKL_File *self, String_View name) { 296 | if (packl_on_global_context(self)) { return NULL; } 297 | 298 | for (size_t i = self->contexts.count - 1; i != 0; --i) { 299 | Context context = self->contexts.items[i - 1]; 300 | Context_Item *item = packl_get_context_item_in_context(context, name); 301 | if (!item) { continue; } 302 | if (item->type == CONTEXT_ITEM_TYPE_FUNCTION) { 303 | return &item->as.func; 304 | } 305 | } 306 | 307 | return NULL; 308 | } 309 | 310 | -------------------------------------------------------------------------------- /src/packl-lexer.c: -------------------------------------------------------------------------------- 1 | #include "headers/packl-lexer.h" 2 | 3 | char *symbols[] = { 4 | ";", 5 | ":", 6 | ",", 7 | "[", 8 | "]", 9 | "(", 10 | ")", 11 | "{", 12 | "}", 13 | ".", 14 | }; 15 | 16 | Token_Kind symbol_token_kinds[] = { 17 | TOKEN_KIND_SEMI_COLON, 18 | TOKEN_KIND_COLON, 19 | TOKEN_KIND_COMMA, 20 | TOKEN_KIND_OPEN_BRACKET, 21 | TOKEN_KIND_CLOSE_BRACKET, 22 | TOKEN_KIND_OPEN_PARENT, 23 | TOKEN_KIND_CLOSE_PARENT, 24 | TOKEN_KIND_OPEN_CURLY_BRACE, 25 | TOKEN_KIND_CLOSE_CURLY_BRACE, 26 | TOKEN_KIND_DOT, 27 | }; 28 | 29 | char *keywords[] = { 30 | "proc", 31 | 32 | "func", 33 | "return", 34 | 35 | "var", 36 | 37 | "if", 38 | "else", 39 | 40 | "while", 41 | 42 | "for", 43 | "in", 44 | 45 | "use", 46 | "as", 47 | 48 | "class", 49 | 50 | "or", 51 | "and", 52 | "xor", 53 | 54 | "array", 55 | "int", 56 | "str", 57 | "ptr", 58 | }; 59 | 60 | char *natives[] = { 61 | "write", 62 | "exit", 63 | "malloc", 64 | "mdealloc", 65 | "mload", 66 | "mset", 67 | }; 68 | 69 | Token_Kind keyword_token_kinds[] = { 70 | TOKEN_KIND_PROC, 71 | 72 | TOKEN_KIND_FUNC, 73 | TOKEN_KIND_RETURN, 74 | 75 | TOKEN_KIND_VAR, 76 | 77 | TOKEN_KIND_IF, 78 | TOKEN_KIND_ELSE, 79 | 80 | TOKEN_KIND_WHILE, 81 | 82 | TOKEN_KIND_FOR, 83 | TOKEN_KIND_IN, 84 | 85 | TOKEN_KIND_USE, 86 | TOKEN_KIND_AS, 87 | 88 | TOKEN_KIND_CLASS, 89 | 90 | TOKEN_KIND_OR, 91 | TOKEN_KIND_AND, 92 | TOKEN_KIND_XOR, 93 | 94 | TOKEN_KIND_ARRAY, 95 | TOKEN_KIND_INT_TYPE, 96 | TOKEN_KIND_STR_TYPE, 97 | TOKEN_KIND_PTR_TYPE, 98 | }; 99 | 100 | char *builtin_operators[] = { 101 | "new", 102 | "sizeof", 103 | }; 104 | 105 | char packl_lexer_peek(PACKL_File *self) { 106 | return (self->lexer.source.content[self->lexer.current]); 107 | } 108 | 109 | void packl_lexer_advance(PACKL_File *self) { 110 | char current = lpeek(self); 111 | 112 | if (current == '\n') { self->lexer.loc.line++; self->lexer.loc.col = 1; } 113 | else { self->lexer.loc.col++; } 114 | 115 | self->lexer.current++; 116 | } 117 | 118 | bool packl_lexer_eof(PACKL_File *self) { 119 | return (self->lexer.source.count <= self->lexer.current); 120 | } 121 | 122 | Token packl_lexer_lex_string(PACKL_File *self) { 123 | Token token = {0}; 124 | token.loc = self->lexer.loc; 125 | 126 | char *begin = &self->lexer.source.content[self->lexer.current]; 127 | size_t size = 0; 128 | 129 | // consuming the `"` char 130 | ladv(self); 131 | 132 | // consuming the quotes 133 | begin++; 134 | 135 | char current = 0; 136 | 137 | while (!leof(self)) { 138 | current = lpeek(self); 139 | ladv(self); 140 | if (current == '"') { break; } 141 | size++; 142 | } 143 | 144 | token.kind = TOKEN_KIND_STRING_LIT; 145 | token.text = SV_GET(begin, size); 146 | 147 | return token; 148 | } 149 | 150 | Token packl_lexer_lex_id(PACKL_File *self) { 151 | Token token = {0}; 152 | token.loc = self->lexer.loc; 153 | 154 | char *begin = &self->lexer.source.content[self->lexer.current]; 155 | size_t size = 0; 156 | 157 | 158 | while (!leof(self)) { 159 | if(!isalnum(lpeek(self)) && lpeek(self) != '_') { break; } 160 | ladv(self); 161 | size++; 162 | } 163 | 164 | String_View id = SV_GET(begin, size); 165 | 166 | // check for builtin operators (sizeof), (new) 167 | for(size_t i = 0; i < ARR_SIZE(builtin_operators); ++i) { 168 | if (sv_eq(id, SV(builtin_operators[i]))) { 169 | token.text = SV_GET(begin, size); 170 | token.kind = TOKEN_KIND_OPERATOR; 171 | return token; 172 | } 173 | } 174 | 175 | // check for the natives 176 | for (size_t i = 0; i < ARR_SIZE(natives); ++i) { 177 | if (sv_eq(id, SV(natives[i]))) { 178 | token.text = SV_GET(begin, size); 179 | token.kind = TOKEN_KIND_NATIVE; 180 | return token; 181 | } 182 | } 183 | 184 | // check for keywords 185 | for (size_t i = 0; i < ARR_SIZE(keywords); ++i) { 186 | if (sv_eq(id, SV(keywords[i]))) { 187 | token.text = SV_GET(begin, size); 188 | token.kind = keyword_token_kinds[i]; 189 | return token; 190 | } 191 | } 192 | 193 | token.text = id; 194 | token.kind = TOKEN_KIND_IDENTIFIER; 195 | return token; 196 | } 197 | 198 | Token packl_lexer_lex_number(PACKL_File *self) { 199 | Token token = {0}; 200 | token.loc = self->lexer.loc; 201 | 202 | char *begin = &self->lexer.source.content[self->lexer.current]; 203 | size_t size = 0; 204 | 205 | 206 | while (!leof(self)) { 207 | if (!isdigit(lpeek(self))) { break; } 208 | ladv(self); 209 | size++; 210 | } 211 | 212 | token.text = SV_GET(begin, size); 213 | token.kind = TOKEN_KIND_INTEGER_LIT; 214 | return token; 215 | } 216 | 217 | Token packl_lexer_read_token(PACKL_File *self) { 218 | Token token = {0}; 219 | token.loc = self->lexer.loc; 220 | 221 | char *current = &self->lexer.source.content[self->lexer.current]; 222 | 223 | token.text = SV_GET(current, 1); 224 | 225 | for (size_t i = 0; i < ARR_SIZE(symbols); ++i) { 226 | if (sv_eq(SV(symbols[i]), token.text)) { 227 | ladv(self); 228 | token.kind = symbol_token_kinds[i]; 229 | return token; 230 | } 231 | } 232 | 233 | if (*current == '=') { 234 | ladv(self); 235 | if (lpeek(self) == '=') { 236 | token.text.count++; 237 | token.kind = TOKEN_KIND_DOUBLE_EQUAL; 238 | ladv(self); 239 | return token; 240 | } 241 | token.kind = TOKEN_KIND_EQUAL; 242 | return token; 243 | } 244 | 245 | if (*current == '<') { 246 | ladv(self); 247 | if (lpeek(self) == '=') { 248 | token.text.count++; 249 | ladv(self); 250 | token.kind = TOKEN_KIND_LESS_OR_EQUAL; 251 | return token; 252 | } 253 | token.kind = TOKEN_KIND_LESS; 254 | return token; 255 | } 256 | 257 | if(*current == '>') { 258 | ladv(self); 259 | if (lpeek(self) == '=') { 260 | token.text.count++; 261 | ladv(self); 262 | token.kind = TOKEN_KIND_GREATER_OR_EQUAL; 263 | return token; 264 | } 265 | token.kind = TOKEN_KIND_GREATER; 266 | return token; 267 | } 268 | 269 | if (*current == '+') { 270 | ladv(self); 271 | if (lpeek(self) == '+') { 272 | token.text.count++; 273 | ladv(self); 274 | token.kind = TOKEN_KIND_DOUBLE_PLUS; 275 | return token; 276 | } 277 | token.kind = TOKEN_KIND_PLUS; 278 | return token; 279 | } 280 | 281 | 282 | if (*current == '-') { 283 | ladv(self); 284 | if (lpeek(self) == '-') { 285 | token.text.count++; 286 | ladv(self); 287 | token.kind = TOKEN_KIND_DOUBLE_MINUS; 288 | return token; 289 | } 290 | token.kind = TOKEN_KIND_MINUS; 291 | return token; 292 | } 293 | 294 | if (*current == '*') { 295 | ladv(self); 296 | token.kind = TOKEN_KIND_STAR; 297 | return token; 298 | } 299 | 300 | if (*current == '/') { 301 | ladv(self); 302 | token.kind = TOKEN_KIND_SLASH; 303 | return token; 304 | } 305 | 306 | if (*current == '%') { 307 | ladv(self); 308 | token.kind = TOKEN_KIND_MOD; 309 | return token; 310 | } 311 | 312 | if (*current == '!') { 313 | ladv(self); 314 | if (lpeek(self) == '=') { 315 | token.text.count++; 316 | ladv(self); 317 | token.kind = TOKEN_KIND_NOT_EQUAL; 318 | return token; 319 | } 320 | token.kind = TOKEN_KIND_NOT; 321 | return token; 322 | } 323 | 324 | if (*current == '"') { return packl_lexer_lex_string(self); } 325 | 326 | if (isdigit(*current)) { return packl_lexer_lex_number(self); } 327 | 328 | if (isalpha(*current)) { return packl_lexer_lex_id(self); } 329 | 330 | if (*current == '-') { 331 | TODO("handle negative numbers"); 332 | } 333 | 334 | PACKL_ERROR_LOC(self->filename, token.loc, "failed to identify the char `%c`", *current); 335 | } 336 | 337 | void packl_lexer_skip_comment(PACKL_File *self) { 338 | while (!leof(self)) { 339 | if (lpeek(self) == '\n') { break; } 340 | ladv(self); 341 | } 342 | } 343 | 344 | void packl_lexer_lex(PACKL_File *self) { 345 | DA_INIT(&self->tokens, sizeof(Token)); 346 | while (!leof(self)) { 347 | if (lpeek(self) == '#') { packl_lexer_skip_comment(self); continue; } 348 | if (isspace(lpeek(self))) { ladv(self); continue; } 349 | Token token = lread(self); 350 | DA_APPEND(&self->tokens, token); 351 | } 352 | DA_APPEND(&self->tokens, ((Token) { .kind = TOKEN_KIND_END, .loc = self->lexer.loc })); 353 | } -------------------------------------------------------------------------------- /src/packl-operator.c: -------------------------------------------------------------------------------- 1 | #include "headers/packl-operator.h" 2 | 3 | size_t packl_get_operator_input_size(PACKL_Compiler *c, PACKL_File *self, Expr_Operator_Input input) { 4 | if (input.kind == INPUT_KIND_TYPE) { 5 | return packl_get_type_size(self, input.as.type); 6 | } 7 | 8 | if (input.kind == INPUT_KIND_ID) { 9 | Context_Item *item = packl_get_context_item_in_all_contexts(self, input.as.identifier); 10 | if (!item) { 11 | PACKL_ERROR(self->filename, "`" SV_FMT "` not declared yet", SV_UNWRAP(input.as.identifier)); 12 | } 13 | 14 | if (item->type == CONTEXT_ITEM_TYPE_CLASS) { 15 | return item->as.class.attrs_size; 16 | } 17 | 18 | PACKL_ERROR(self->filename, "expected `"SV_FMT"` to be a class type but found as %s", SV_UNWRAP(item->name), context_item_as_cstr[item->type]); 19 | } 20 | 21 | ASSERT(false, "`packl_generate_native_sizeof_code` failed to generate the code for the sizeof operator input kind"); 22 | } -------------------------------------------------------------------------------- /src/packl-parser.c: -------------------------------------------------------------------------------- 1 | #include "headers/packl-parser.h" 2 | 3 | char *token_kinds_str[] = { 4 | "id", 5 | "native", 6 | 7 | "str", 8 | "int", 9 | 10 | ";", 11 | ":", 12 | ",", 13 | ".", 14 | 15 | "[", 16 | "]", 17 | "(", 18 | ")", 19 | "{", 20 | "}", 21 | 22 | "=", 23 | 24 | "+", 25 | "++", 26 | "-", 27 | "--", 28 | "*", 29 | "/", 30 | "%", 31 | 32 | "==", 33 | "<", 34 | ">", 35 | "<=", 36 | ">=", 37 | "!", 38 | "!=", 39 | 40 | "proc", 41 | "func", 42 | "return", 43 | "var", 44 | "if", 45 | "else", 46 | "while", 47 | "for", 48 | "in", 49 | "use", 50 | "as", 51 | "class", 52 | 53 | "or", 54 | "and", 55 | "xor", 56 | 57 | "array", 58 | "int", 59 | "str", 60 | "ptr", 61 | 62 | "operator", 63 | }; 64 | 65 | Node packl_init_node(Node_Kind kind, Location loc) { 66 | return (Node) { .kind = kind, .loc = loc }; 67 | } 68 | 69 | PACKL_Type packl_parser_parse_type(PACKL_File *self); 70 | Expression packl_parser_parse_comparative_expr(PACKL_File *self); 71 | Expression packl_parser_parse_expr(PACKL_File *self); 72 | Node packl_parser_parse_statement(PACKL_File *self); 73 | 74 | 75 | 76 | Token packl_parser_peek(PACKL_File *self, size_t ahead) { 77 | return self->tokens.items[self->parser.current + ahead]; 78 | } 79 | 80 | void packl_parser_advance(PACKL_File *self) { 81 | self->parser.current++; 82 | } 83 | 84 | // get the number of tokens that can be consumed 85 | size_t packl_get_tokens_number(PACKL_File *self) { 86 | return self->tokens.count - self->parser.current; 87 | } 88 | 89 | bool packl_parser_eot(PACKL_File *self) { 90 | return ppeek(self).kind == TOKEN_KIND_END; 91 | } 92 | 93 | Operator packl_get_operator(PACKL_File *self, Token token) { 94 | switch(token.kind) { 95 | case TOKEN_KIND_PLUS: 96 | return OP_PLUS; 97 | case TOKEN_KIND_MINUS: 98 | return OP_MINUS; 99 | case TOKEN_KIND_STAR: 100 | return OP_MUL; 101 | case TOKEN_KIND_SLASH: 102 | return OP_DIV; 103 | case TOKEN_KIND_MOD: 104 | return OP_MOD; 105 | case TOKEN_KIND_LESS: 106 | return OP_L; 107 | case TOKEN_KIND_GREATER: 108 | return OP_G; 109 | case TOKEN_KIND_LESS_OR_EQUAL: 110 | return OP_LE; 111 | case TOKEN_KIND_GREATER_OR_EQUAL: 112 | return OP_GE; 113 | case TOKEN_KIND_DOUBLE_EQUAL: 114 | return OP_EQ; 115 | case TOKEN_KIND_AND: 116 | return OP_AND; 117 | case TOKEN_KIND_OR: 118 | return OP_OR; 119 | case TOKEN_KIND_XOR: 120 | return OP_XOR; 121 | case TOKEN_KIND_NOT_EQUAL: 122 | return OP_NE; 123 | case TOKEN_KIND_DOUBLE_PLUS: 124 | return OP_INC; 125 | case TOKEN_KIND_DOUBLE_MINUS: 126 | return OP_DEC; 127 | case TOKEN_KIND_NOT: 128 | return OP_NOT; 129 | default: 130 | PACKL_ERROR_LOC(self->filename, token.loc, "expected operator type but `" SV_FMT "` found", SV_UNWRAP(ppeek(self).text)); 131 | } 132 | } 133 | 134 | void packl_parser_expect(PACKL_File *self, Token_Kind kind, Token *token) { 135 | if (peot(self)) { PACKL_ERROR_LOC(self->filename, ppeek(self).loc, "expected token of kind `%s` but end found", token_kinds_str[kind]); } 136 | 137 | 138 | Token current = ppeek(self); 139 | if (current.kind != kind) { 140 | PACKL_ERROR_LOC(self->filename, current.loc, "expected token of kind `%s` but `" SV_FMT "` found", token_kinds_str[kind], SV_UNWRAP(current.text)); 141 | } 142 | 143 | if (token) *token = current; 144 | padv(self); 145 | } 146 | 147 | PACKL_Arg packl_parser_parse_arg(PACKL_File *self) { 148 | PACKL_Arg arg = {0}; 149 | arg.expr = packl_parser_parse_expr(self); 150 | return arg; 151 | } 152 | 153 | 154 | PACKL_Args packl_parser_parse_args(PACKL_File *self) { 155 | PACKL_Args args = {0}; 156 | DA_INIT(&args, sizeof(PACKL_Arg)); 157 | 158 | if (ppeek(self).kind == TOKEN_KIND_CLOSE_PARENT) { return args; } 159 | 160 | while (!peot(self)) { 161 | PACKL_Arg arg = packl_parser_parse_arg(self); 162 | DA_APPEND(&args, arg); 163 | 164 | Token token = ppeek(self); 165 | 166 | if (token.kind == TOKEN_KIND_COMMA) { padv(self); continue; } 167 | else if (token.kind == TOKEN_KIND_CLOSE_PARENT) { break; } 168 | else { PACKL_ERROR_LOC(self->filename, token.loc, "unexpected token found `" SV_FMT "`", SV_UNWRAP(token.text)); } 169 | } 170 | 171 | return args; 172 | } 173 | 174 | Func_Call packl_parser_parse_func_call(PACKL_File *self) { 175 | Func_Call func_call = {0}; 176 | Token token = ppeek(self); 177 | 178 | func_call.name = token.text; 179 | 180 | // consume the function name 181 | padv(self); 182 | 183 | // parsing arguments 184 | pexp(self, TOKEN_KIND_OPEN_PARENT, NULL); 185 | func_call.args = packl_parser_parse_args(self); 186 | pexp(self, TOKEN_KIND_CLOSE_PARENT, NULL); 187 | 188 | return func_call; 189 | } 190 | 191 | Mod_Call packl_parser_parse_module_call(PACKL_File *self) { 192 | Mod_Call mod_call = {0}; 193 | 194 | Token token = {0}; 195 | pexp(self, TOKEN_KIND_IDENTIFIER, &token); 196 | mod_call.name = token.text; 197 | 198 | pexp(self, TOKEN_KIND_COLON, NULL); 199 | 200 | if (packl_get_tokens_number(self) < 2) { 201 | PACKL_ERROR_LOC(self->filename, ppeek(self).loc, "expected more tokens after module call `" SV_FMT "`", SV_UNWRAP(mod_call.name)); 202 | } 203 | 204 | if (ppeek(self).kind != TOKEN_KIND_IDENTIFIER) { 205 | PACKL_ERROR_LOC(self->filename, ppeek(self).loc, "expected identifier after module call `" SV_FMT "`", SV_UNWRAP(mod_call.name)); 206 | } 207 | 208 | if (ppeek_(self, 1).kind == TOKEN_KIND_OPEN_PARENT) { 209 | mod_call.kind = MODULE_CALL_FUNC_CALL; 210 | mod_call.as.func_call = packl_parser_parse_func_call(self); 211 | return mod_call; 212 | } 213 | 214 | mod_call.kind = MODULE_CALL_VARIABLE; 215 | mod_call.as.var_name = ppeek(self).text; 216 | padv(self); 217 | 218 | return mod_call; 219 | } 220 | 221 | 222 | 223 | Parameter packl_parser_parse_param(PACKL_File *self) { 224 | Parameter param = {0}; 225 | 226 | Token token = {0}; 227 | 228 | // for the param name 229 | pexp(self, TOKEN_KIND_IDENTIFIER, &token); 230 | param.name = token.text; 231 | 232 | pexp(self, TOKEN_KIND_COLON, NULL); 233 | 234 | param.type = packl_parser_parse_type(self); 235 | 236 | return param; 237 | } 238 | 239 | Parameters packl_parser_parse_params(PACKL_File *self) { 240 | Parameters params = {0}; 241 | DA_INIT(¶ms, sizeof(Parameter)); 242 | 243 | while (!peot(self)) { 244 | if (ppeek(self).kind == TOKEN_KIND_CLOSE_PARENT) { break; } 245 | Parameter param = packl_parser_parse_param(self); 246 | DA_APPEND(¶ms, param); 247 | if (ppeek(self).kind == TOKEN_KIND_COMMA) { padv(self); } 248 | } 249 | 250 | return params; 251 | } 252 | 253 | AST packl_parser_parse_body(PACKL_File *self) { 254 | AST ast = {0}; 255 | DA_INIT(&ast, sizeof(Node)); 256 | 257 | while (!peot(self)) { 258 | if (ppeek(self).kind == TOKEN_KIND_CLOSE_CURLY_BRACE) { break; } 259 | Node node = pstmt(self); 260 | 261 | if (node.kind == NODE_KIND_PROC_DEF) { PACKL_ERROR_LOC(self->filename, node.loc, "procedure `" SV_FMT "` defined inside a body", SV_UNWRAP(node.as.proc_def.name)); } 262 | if (node.kind == NODE_KIND_FUNC_DEF) { PACKL_ERROR_LOC(self->filename, node.loc, "function `" SV_FMT "` defined inside a body", SV_UNWRAP(node.as.func_def.name)); } 263 | 264 | 265 | DA_APPEND(&ast, node); 266 | if (ppeek(self).kind == TOKEN_KIND_SEMI_COLON) { padv(self); } 267 | } 268 | 269 | return ast; 270 | } 271 | 272 | Proc_Def packl_parser_parse_proc_def(PACKL_File *self) { 273 | Proc_Def proc = {0}; 274 | Token token = {0}; 275 | 276 | pexp(self, TOKEN_KIND_IDENTIFIER, &token); 277 | proc.name = token.text; 278 | 279 | if (ppeek(self).kind == TOKEN_KIND_OPEN_PARENT) { 280 | padv(self); 281 | proc.params = packl_parser_parse_params(self); 282 | pexp(self, TOKEN_KIND_CLOSE_PARENT, NULL); 283 | } 284 | 285 | pexp(self, TOKEN_KIND_OPEN_CURLY_BRACE, &token); 286 | 287 | proc.body = malloc(sizeof(AST)); 288 | *proc.body = packl_parser_parse_body(self); 289 | 290 | pexp(self, TOKEN_KIND_CLOSE_CURLY_BRACE, &token); 291 | 292 | return proc; 293 | } 294 | 295 | 296 | Array_Type packl_parser_parse_array_type(PACKL_File *self) { 297 | Array_Type arr_type = {0}; 298 | 299 | pexp(self, TOKEN_KIND_ARRAY, NULL); 300 | 301 | pexp(self, TOKEN_KIND_OPEN_PARENT, NULL); 302 | 303 | arr_type.item_type = malloc(sizeof(PACKL_Type)); 304 | *arr_type.item_type = packl_parser_parse_type(self); 305 | 306 | pexp(self, TOKEN_KIND_COMMA, NULL); 307 | 308 | Token token = {0}; 309 | pexp(self, TOKEN_KIND_INTEGER_LIT, &token); 310 | arr_type.size = integer_from_sv(token.text); 311 | 312 | pexp(self, TOKEN_KIND_CLOSE_PARENT, NULL); 313 | 314 | return arr_type; 315 | } 316 | 317 | PACKL_Type packl_parser_parse_type(PACKL_File *self) { 318 | PACKL_Type type = {0}; 319 | 320 | Token token = ppeek(self); 321 | 322 | if(token.kind == TOKEN_KIND_ARRAY) { 323 | type.kind = PACKL_TYPE_ARRAY; 324 | type.as.array = packl_parser_parse_array_type(self); 325 | return type; 326 | } 327 | 328 | if (token.kind == TOKEN_KIND_INT_TYPE) { 329 | padv(self); 330 | type.kind = PACKL_TYPE_BASIC; 331 | type.as.basic = PACKL_TYPE_INT; 332 | return type; 333 | } 334 | 335 | if(token.kind == TOKEN_KIND_STR_TYPE) { 336 | padv(self); 337 | type.kind = PACKL_TYPE_BASIC; 338 | type.as.basic = PACKL_TYPE_STR; 339 | return type; 340 | } 341 | 342 | if (token.kind == TOKEN_KIND_PTR_TYPE) { 343 | padv(self); 344 | type.kind = PACKL_TYPE_BASIC; 345 | type.as.basic = PACKL_TYPE_PTR; 346 | return type; 347 | } 348 | 349 | if (token.kind == TOKEN_KIND_IDENTIFIER) { 350 | padv(self); 351 | type.kind = PACKL_TYPE_USER_DEFINED; 352 | type.as.user_defined = token.text; 353 | return type; 354 | } 355 | 356 | PACKL_ERROR_LOC(self->filename, token.loc, "unknown type `" SV_FMT "`", SV_UNWRAP(token.text)); 357 | } 358 | 359 | Expr_Arr packl_parser_parse_array_initialization(PACKL_File *self) { 360 | Expr_Arr arr = {0}; 361 | DA_INIT(&arr, sizeof(Expression)); 362 | 363 | if (ppeek(self).kind == TOKEN_KIND_CLOSE_CURLY_BRACE) { return arr; } 364 | 365 | while (!peot(self)) { 366 | Expression expr = packl_parser_parse_expr(self); 367 | DA_APPEND(&arr, expr); 368 | 369 | Token token = ppeek(self); 370 | 371 | if (token.kind == TOKEN_KIND_COMMA) { padv(self); continue; } 372 | else if (token.kind == TOKEN_KIND_CLOSE_CURLY_BRACE) { break; } 373 | else { PACKL_ERROR_LOC(self->filename, token.loc, "unexpected token found `" SV_FMT "`", SV_UNWRAP(token.text)); } 374 | } 375 | 376 | return arr; 377 | } 378 | 379 | Var_Declaration packl_parser_parse_var_dec(PACKL_File *self) { 380 | Var_Declaration var_dec = {0}; 381 | 382 | // consuming the `var` keyword 383 | padv(self); 384 | 385 | Token token = {0}; 386 | pexp(self, TOKEN_KIND_IDENTIFIER, &token); 387 | var_dec.name = token.text; 388 | 389 | pexp(self, TOKEN_KIND_COLON, NULL); 390 | 391 | var_dec.type = packl_parser_parse_type(self); 392 | 393 | if (ppeek(self).kind == TOKEN_KIND_SEMI_COLON) { 394 | var_dec.value.kind = EXPR_KIND_NOT_INITIALIZED; 395 | return var_dec; 396 | } 397 | 398 | pexp(self, TOKEN_KIND_EQUAL, NULL); 399 | 400 | if(ppeek(self).kind == TOKEN_KIND_SEMI_COLON) { 401 | 402 | } 403 | 404 | if (var_dec.type.kind == PACKL_TYPE_ARRAY) {} 405 | 406 | if(ppeek(self).kind == TOKEN_KIND_OPEN_CURLY_BRACE) { 407 | padv(self); 408 | var_dec.value.kind = EXPR_KIND_ARRAY; 409 | var_dec.value.as.arr = packl_parser_parse_array_initialization(self); 410 | pexp(self, TOKEN_KIND_CLOSE_CURLY_BRACE, NULL); 411 | } else { 412 | var_dec.value = packl_parser_parse_expr(self); 413 | } 414 | 415 | return var_dec; 416 | } 417 | 418 | Expression get_bin_operation(Expression lhs, Expression rhs, Operator op) { 419 | Expression expr = {0}; 420 | expr.kind = EXPR_KIND_BIN_OP; 421 | 422 | expr.as.bin.lhs = malloc(sizeof(Expression)); 423 | expr.as.bin.rhs = malloc(sizeof(Expression)); 424 | 425 | *expr.as.bin.lhs = lhs; 426 | *expr.as.bin.rhs = rhs; 427 | expr.as.bin.op = op; 428 | 429 | expr.loc = lhs.loc; 430 | 431 | return expr; 432 | } 433 | 434 | Expression get_func_call_expr(Func_Call func) { 435 | Expression expr = {0}; 436 | expr.kind = EXPR_KIND_FUNC_CALL; 437 | expr.as.func = malloc(sizeof(Func_Call)); 438 | *expr.as.func = func; 439 | return expr; 440 | } 441 | 442 | Expression get_mod_call_expr(Mod_Call mod) { 443 | Expression expr = {0}; 444 | expr.kind = EXPR_KIND_MOD_CALL; 445 | expr.as.func = malloc(sizeof(Mod_Call)); 446 | *expr.as.mod = mod; 447 | return expr; 448 | } 449 | 450 | Expression get_arr_index_expr(Expr_Arr_Index arr_index) { 451 | Expression expr = {0}; 452 | expr.kind = EXPR_KIND_ARRAY_INDEXING; 453 | expr.as.arr_index = arr_index; 454 | return expr; 455 | } 456 | 457 | Expression get_native_call_expr(Func_Call func) { 458 | Expression expr = {0}; 459 | expr.kind = EXPR_KIND_NATIVE_CALL; 460 | expr.as.func = malloc(sizeof(Func_Call)); 461 | *expr.as.func = func; 462 | return expr; 463 | } 464 | 465 | int ismultiplicative(Token_Kind kind) { 466 | Token_Kind kinds[] = { 467 | TOKEN_KIND_STAR, 468 | TOKEN_KIND_SLASH, 469 | TOKEN_KIND_MOD, 470 | }; 471 | 472 | for (size_t i = 0; i < ARR_SIZE(kinds); ++i) { 473 | if (kinds[i] == kind) { return true; } 474 | } 475 | 476 | return false; 477 | } 478 | 479 | int isadditive(Token_Kind kind) { 480 | Token_Kind kinds[] = { 481 | TOKEN_KIND_PLUS, 482 | TOKEN_KIND_MINUS, 483 | }; 484 | 485 | for (size_t i = 0; i < ARR_SIZE(kinds); ++i) { 486 | if (kinds[i] == kind) { return true; } 487 | } 488 | 489 | return false; 490 | } 491 | 492 | int iscomparative(Token_Kind kind) { 493 | Token_Kind kinds[] = { 494 | TOKEN_KIND_LESS, 495 | TOKEN_KIND_GREATER, 496 | TOKEN_KIND_DOUBLE_EQUAL, 497 | TOKEN_KIND_LESS_OR_EQUAL, 498 | TOKEN_KIND_GREATER_OR_EQUAL, 499 | TOKEN_KIND_NOT_EQUAL, 500 | }; 501 | 502 | for (size_t i = 0; i < ARR_SIZE(kinds); ++i) { 503 | if (kinds[i] == kind) { return true; } 504 | } 505 | 506 | return false; 507 | } 508 | 509 | int islogical(Token_Kind kind) { 510 | Token_Kind kinds[] = { 511 | TOKEN_KIND_AND, 512 | TOKEN_KIND_OR, 513 | TOKEN_KIND_XOR, 514 | }; 515 | 516 | for (size_t i = 0; i < ARR_SIZE(kinds); ++i) { 517 | if (kinds[i] == kind) { return true; } 518 | } 519 | 520 | return false; 521 | } 522 | 523 | int ispreunary(Token_Kind kind) { 524 | Token_Kind kinds[] = { 525 | TOKEN_KIND_NOT, 526 | }; 527 | 528 | for(size_t i = 0; i < ARR_SIZE(kinds); ++i) { 529 | if (kinds[i] == kind) { return true; } 530 | } 531 | 532 | return false; 533 | } 534 | 535 | int ispostunary(Token_Kind kind) { 536 | Token_Kind kinds[] = { 537 | TOKEN_KIND_DOUBLE_PLUS, 538 | TOKEN_KIND_DOUBLE_MINUS, 539 | }; 540 | 541 | for(size_t i = 0; i < ARR_SIZE(kinds); ++i) { 542 | if (kinds[i] == kind) { return true; } 543 | } 544 | 545 | return false; 546 | } 547 | 548 | Expr_Arr_Index packl_parser_parse_array_indexing(PACKL_File *self) { 549 | Expr_Arr_Index arr_index = {0}; 550 | 551 | Token token = {0}; 552 | pexp(self, TOKEN_KIND_IDENTIFIER, &token); 553 | arr_index.name = token.text; 554 | 555 | pexp(self, TOKEN_KIND_OPEN_BRACKET, NULL); 556 | arr_index.index = malloc(sizeof(Expression)); 557 | *arr_index.index = packl_parser_parse_expr(self); 558 | pexp(self, TOKEN_KIND_CLOSE_BRACKET, NULL); 559 | 560 | return arr_index; 561 | } 562 | 563 | Expression packl_parser_parse_primary_expr(PACKL_File *self); 564 | 565 | Expression packl_parser_preunary_expression(PACKL_File *self) { 566 | Expression expr = {0}; 567 | expr.kind = EXPR_KIND_PRE_UNARY_OP; 568 | expr.as.unary.op = packl_get_operator(self, ppeek(self)); 569 | 570 | padv(self); 571 | 572 | expr.as.unary.operand = malloc(sizeof(Expression)); 573 | *expr.as.unary.operand = packl_parser_parse_primary_expr(self); 574 | return expr; 575 | } 576 | 577 | Expr_Attribute packl_parser_parse_attr(PACKL_File *self) { 578 | Expr_Attribute expr = {0}; 579 | 580 | Token token = {0}; 581 | pexp(self, TOKEN_KIND_IDENTIFIER, &token); 582 | expr.obj_name = token.text; 583 | 584 | pexp(self, TOKEN_KIND_DOT, NULL); 585 | pexp(self, TOKEN_KIND_IDENTIFIER, &token); 586 | expr.attr = token.text; 587 | 588 | return expr; 589 | } 590 | 591 | Expr_Operator packl_parser_parse_builtin_operator(PACKL_File *self) { 592 | Expr_Operator expr = {0}; 593 | 594 | Token token = {0}; 595 | pexp(self, TOKEN_KIND_OPERATOR, &token); 596 | 597 | if (sv_eq(token.text, SV("sizeof"))) { 598 | expr.op = SIZEOF_OPERATOR; 599 | } else if (sv_eq(token.text, SV("new"))) { 600 | expr.op = NEW_OPERATOR; 601 | } else { 602 | ASSERT(false, "`packl_parser_parse_builtin_operator` failed to parse the operator added"); 603 | } 604 | 605 | token = ppeek(self); 606 | switch(token.kind) { 607 | case TOKEN_KIND_IDENTIFIER: 608 | expr.input.kind = INPUT_KIND_ID; 609 | expr.input.as.identifier = token.text; 610 | padv(self); 611 | break; 612 | default: 613 | expr.input.kind = INPUT_KIND_TYPE; 614 | expr.input.as.type = packl_parser_parse_type(self); 615 | break; 616 | } 617 | 618 | return expr; 619 | } 620 | 621 | Method_Call packl_parser_parse_method_call(PACKL_File *self) { 622 | Method_Call method = {0}; 623 | 624 | Token token = {0}; 625 | pexp(self, TOKEN_KIND_IDENTIFIER, &token); 626 | method.object_name = token.text; 627 | 628 | pexp(self, TOKEN_KIND_DOT, NULL); 629 | 630 | method.func = packl_parser_parse_func_call(self); 631 | 632 | return method; 633 | } 634 | 635 | Expr_Attribute packl_parser_parse_object_attr(PACKL_File *self) { 636 | Expr_Attribute attr = {0}; 637 | 638 | Token token = {0}; 639 | pexp(self, TOKEN_KIND_IDENTIFIER, &token); 640 | attr.obj_name = token.text; 641 | 642 | pexp(self, TOKEN_KIND_DOT, NULL); 643 | 644 | pexp(self, TOKEN_KIND_IDENTIFIER, &token); 645 | attr.attr = token.text; 646 | 647 | return attr; 648 | } 649 | 650 | Expression packl_parser_parse_primary_expr(PACKL_File *self) { 651 | if (peot(self)) { PACKL_ERROR_LOC(self->filename, ppeek(self).loc, "expected more tokens for the expression evaluation but end found"); } 652 | 653 | Token token = ppeek(self); 654 | Expression expr = {0}; 655 | expr.loc = token.loc; 656 | 657 | if (ispreunary(token.kind)) { 658 | return packl_parser_preunary_expression(self); 659 | } 660 | 661 | if (token.kind == TOKEN_KIND_INTEGER_LIT) { 662 | padv(self); 663 | expr.kind = EXPR_KIND_INTEGER; 664 | expr.as.integer = integer_from_sv(token.text); 665 | return expr; 666 | } 667 | 668 | if (token.kind == TOKEN_KIND_STRING_LIT) { 669 | padv(self); 670 | expr.kind = EXPR_KIND_STRING; 671 | expr.as.value = token.text; 672 | return expr; 673 | } 674 | 675 | if (token.kind == TOKEN_KIND_IDENTIFIER) { 676 | if (packl_get_tokens_number(self) < 2) { PACKL_ERROR_LOC(self->filename, ppeek(self).loc, "expected a `;` but end of tokens found"); } 677 | 678 | Expression expr = {0}; 679 | 680 | switch(ppeek_(self, 1).kind) { 681 | case TOKEN_KIND_OPEN_PARENT: 682 | expr.kind = EXPR_KIND_FUNC_CALL; 683 | expr.as.func = malloc(sizeof(Func_Call)); 684 | *expr.as.func = packl_parser_parse_func_call(self); 685 | break; 686 | case TOKEN_KIND_COLON: 687 | expr.kind = EXPR_KIND_MOD_CALL; 688 | expr.as.func = malloc(sizeof(Func_Call)); 689 | *expr.as.func = packl_parser_parse_func_call(self); 690 | break; 691 | case TOKEN_KIND_OPEN_BRACKET: 692 | expr.kind = EXPR_KIND_ARRAY_INDEXING; 693 | expr.as.arr_index = packl_parser_parse_array_indexing(self); 694 | break; 695 | case TOKEN_KIND_DOT: 696 | if (packl_get_tokens_number(self) < 4) { 697 | PACKL_ERROR_LOC(self->filename, ppeek(self).loc, "expected more tokens to parse object attribute or method call"); 698 | } 699 | 700 | if (ppeek_(self, 3).kind == TOKEN_KIND_OPEN_PARENT) { 701 | expr.kind = EXPR_KIND_OBJECT_METHOD; 702 | expr.as.method = malloc(sizeof(Method_Call)); 703 | *expr.as.method = packl_parser_parse_method_call(self); 704 | } else { 705 | expr.kind = EXPR_KIND_OBJECT_ATTRIBUTE; 706 | expr.as.attr = packl_parser_parse_object_attr(self); 707 | } 708 | 709 | break; 710 | default: 711 | expr.kind = EXPR_KIND_ID; 712 | expr.as.value = token.text; 713 | padv(self); 714 | } 715 | 716 | if (ispostunary(ppeek(self).kind)) { 717 | Expression unary_expr = {0}; 718 | unary_expr.loc = expr.loc; 719 | unary_expr.kind = EXPR_KIND_POST_UNARY_OP; 720 | unary_expr.as.unary.op = packl_get_operator(self, ppeek(self)); 721 | 722 | padv(self); 723 | 724 | unary_expr.as.unary.operand = malloc(sizeof(Expression)); 725 | *unary_expr.as.unary.operand = expr; 726 | expr = unary_expr; 727 | } 728 | 729 | return expr; 730 | } 731 | 732 | if (token.kind == TOKEN_KIND_OPEN_PARENT) { 733 | padv(self); 734 | Expression expr = packl_parser_parse_comparative_expr(self); 735 | pexp(self, TOKEN_KIND_CLOSE_PARENT, NULL); 736 | return expr; 737 | } 738 | 739 | if (token.kind == TOKEN_KIND_NATIVE) { 740 | if (ppeek_(self, 1).kind == TOKEN_KIND_OPEN_PARENT) { 741 | expr.kind = EXPR_KIND_NATIVE_CALL; 742 | expr.as.func = malloc(sizeof(Func_Call)); 743 | *expr.as.func = packl_parser_parse_func_call(self); 744 | return expr; 745 | } 746 | 747 | PACKL_ERROR_LOC(self->filename, token.loc, "expected `(` after the native `" SV_FMT "`", SV_UNWRAP(token.text)); 748 | } 749 | 750 | if(token.kind == TOKEN_KIND_OPERATOR) { 751 | expr.kind = EXPR_KIND_OPERATOR; 752 | expr.as.operator = packl_parser_parse_builtin_operator(self); 753 | return expr; 754 | } 755 | 756 | PACKL_ERROR_LOC(self->filename, ppeek(self).loc, "unexpected token found when parsing expression `" SV_FMT "`", SV_UNWRAP(token.text)); 757 | } 758 | 759 | Expression packl_parser_parse_multiplicative_expr(PACKL_File *self) { 760 | Expression lhs = packl_parser_parse_primary_expr(self); 761 | 762 | while (!peot(self)) { 763 | Token token = ppeek(self); 764 | if (!ismultiplicative(token.kind)) { break; } 765 | 766 | Operator op = packl_get_operator(self, token); 767 | padv(self); 768 | 769 | Expression rhs = packl_parser_parse_primary_expr(self); 770 | 771 | Expression bin = get_bin_operation(lhs, rhs, op); 772 | 773 | lhs = bin; 774 | } 775 | 776 | return lhs; 777 | } 778 | 779 | Expression packl_parser_parse_additive_expr(PACKL_File *self) { 780 | Expression lhs = packl_parser_parse_multiplicative_expr(self); 781 | 782 | while (!peot(self)) { 783 | Token token = ppeek(self); 784 | if (!isadditive(token.kind)) { break; } 785 | 786 | Operator op = packl_get_operator(self, token); 787 | padv(self); 788 | 789 | Expression rhs = packl_parser_parse_multiplicative_expr(self); 790 | 791 | Expression bin = get_bin_operation(lhs, rhs, op); 792 | 793 | lhs = bin; 794 | } 795 | 796 | return lhs; 797 | } 798 | 799 | Expression packl_parser_parse_comparative_expr(PACKL_File *self) { 800 | Expression lhs = packl_parser_parse_additive_expr(self); 801 | 802 | while (!peot(self)) { 803 | Token token = ppeek(self); 804 | if (!iscomparative(token.kind)) { break; } 805 | 806 | Operator op = packl_get_operator(self, token); 807 | padv(self); 808 | 809 | Expression rhs = packl_parser_parse_additive_expr(self); 810 | 811 | Expression bin = get_bin_operation(lhs, rhs, op); 812 | 813 | lhs = bin; 814 | } 815 | 816 | return lhs; 817 | } 818 | 819 | Expression packl_parser_parse_logical_expr(PACKL_File *self) { 820 | Expression lhs = packl_parser_parse_comparative_expr(self); 821 | 822 | while (!peot(self)) { 823 | Token token = ppeek(self); 824 | if (!islogical(token.kind)) { break; } 825 | 826 | Operator op = packl_get_operator(self, token); 827 | padv(self); 828 | 829 | Expression rhs = packl_parser_parse_comparative_expr(self); 830 | 831 | Expression bin = get_bin_operation(lhs, rhs, op); 832 | 833 | lhs = bin; 834 | } 835 | 836 | return lhs; 837 | } 838 | 839 | Expression packl_parser_parse_expr(PACKL_File *self) { 840 | if (peot(self)) { PACKL_ERROR_LOC(self->filename, ppeek(self).loc, "expected an expresssion but end found"); } 841 | return packl_parser_parse_logical_expr(self); 842 | } 843 | 844 | Variable_Format packl_parser_parse_variable_fmt(PACKL_File *self) { 845 | Variable_Format fmt = {0}; 846 | 847 | Token token = {0}; 848 | pexp(self, TOKEN_KIND_IDENTIFIER, &token); 849 | fmt.name = token.text; 850 | 851 | if (ppeek(self).kind == TOKEN_KIND_OPEN_BRACKET) { 852 | fmt.kind = VARIABLE_FORMAT_ARRAY; 853 | padv(self); 854 | fmt.as.index = packl_parser_parse_expr(self); 855 | pexp(self, TOKEN_KIND_CLOSE_BRACKET, NULL); 856 | } else if (ppeek(self).kind == TOKEN_KIND_DOT) { 857 | fmt.kind = VARIABLE_FORMAT_CLASS; 858 | padv(self); 859 | pexp(self, TOKEN_KIND_IDENTIFIER, &token); 860 | fmt.as.attr = token.text; 861 | } else { 862 | fmt.kind = VARIABLE_FORMAT_BASIC; 863 | } 864 | 865 | return fmt; 866 | } 867 | 868 | Expression packl_parser_parse_variable_value(PACKL_File *self, String_View var_name) { 869 | Expression value = {0}; 870 | 871 | if (ppeek(self).kind == TOKEN_KIND_DOUBLE_PLUS) { 872 | value.kind = EXPR_KIND_POST_UNARY_OP; 873 | value.as.unary.op = OP_INC; 874 | value.as.unary.operand = malloc(sizeof(Expression)); 875 | value.as.unary.operand->kind = EXPR_KIND_ID; 876 | value.as.unary.operand->as.value = var_name; 877 | value.loc = ppeek(self).loc; 878 | padv(self); 879 | } else if (ppeek(self).kind == TOKEN_KIND_DOUBLE_MINUS) { 880 | value.kind = EXPR_KIND_POST_UNARY_OP; 881 | value.as.unary.op = OP_DEC; 882 | value.as.unary.operand = malloc(sizeof(Expression)); 883 | value.as.unary.operand->kind = EXPR_KIND_ID; 884 | value.as.unary.operand->as.value = var_name; 885 | value.loc = ppeek(self).loc; 886 | padv(self); 887 | } else { 888 | pexp(self, TOKEN_KIND_EQUAL, NULL); 889 | value = packl_parser_parse_expr(self); 890 | } 891 | 892 | return value; 893 | } 894 | 895 | Var_Reassign packl_parser_parse_var_reassign(PACKL_File *self) { 896 | Var_Reassign var = {0}; 897 | var.format = packl_parser_parse_variable_fmt(self); 898 | var.value = packl_parser_parse_variable_value(self, var.format.name); 899 | return var; 900 | } 901 | 902 | Node packl_parser_parse_identifier(PACKL_File *self) { 903 | Node node = {0}; 904 | node.loc = ppeek(self).loc; 905 | 906 | if (packl_get_tokens_number(self) < 2) { 907 | PACKL_ERROR_LOC(self->filename, ppeek(self).loc, "expected more tokens after `" SV_FMT "`", SV_UNWRAP(ppeek(self).text)); 908 | } 909 | 910 | if (ppeek_(self, 1).kind == TOKEN_KIND_OPEN_PARENT) { 911 | node.kind = NODE_KIND_FUNC_CALL; 912 | node.as.func_call = packl_parser_parse_func_call(self); 913 | return node; 914 | } 915 | 916 | if (ppeek_(self, 1).kind == TOKEN_KIND_OPEN_BRACKET) { 917 | node.kind = NODE_KIND_VAR_REASSIGN; 918 | node.as.var = packl_parser_parse_var_reassign(self); 919 | return node; 920 | } 921 | 922 | if (ppeek_(self, 1).kind == TOKEN_KIND_DOT) { 923 | if (packl_get_tokens_number(self) < 4) { 924 | PACKL_ERROR(self->filename, "unexpcted expression"); 925 | } 926 | 927 | if (ppeek_(self, 3).kind == TOKEN_KIND_OPEN_PARENT) { 928 | node.kind = NODE_KIND_METHOD_CALL; 929 | node.as.method_call = packl_parser_parse_method_call(self); 930 | return node; 931 | } 932 | 933 | node.kind = NODE_KIND_VAR_REASSIGN; 934 | node.as.var = packl_parser_parse_var_reassign(self); 935 | return node; 936 | } 937 | 938 | if (ppeek_(self, 1).kind == TOKEN_KIND_COLON) { 939 | node.kind = NODE_KIND_MOD_CALL; 940 | node.as.mod_call = packl_parser_parse_module_call(self); 941 | return node; 942 | } 943 | 944 | if (ppeek_(self, 1).kind == TOKEN_KIND_EQUAL) { 945 | node.kind = NODE_KIND_VAR_REASSIGN; 946 | node.as.var = packl_parser_parse_var_reassign(self); 947 | return node; 948 | } 949 | 950 | if (ppeek_(self, 1).kind == TOKEN_KIND_DOUBLE_PLUS) { 951 | node.kind = NODE_KIND_VAR_REASSIGN; 952 | node.as.var = packl_parser_parse_var_reassign(self); 953 | return node; 954 | } 955 | 956 | if (ppeek_(self, 1).kind == TOKEN_KIND_DOUBLE_MINUS) { 957 | node.kind = NODE_KIND_VAR_REASSIGN; 958 | node.as.var = packl_parser_parse_var_reassign(self); 959 | return node; 960 | } 961 | 962 | PACKL_ERROR(self->filename, "unexpected token found `" SV_FMT "`", SV_UNWRAP(ppeek(self).text)); 963 | } 964 | 965 | Node packl_parser_parse_native_call(PACKL_File *self) { 966 | Node node = {0}; 967 | node.loc = ppeek(self).loc; 968 | 969 | if (packl_get_tokens_number(self) < 2) { 970 | PACKL_ERROR_LOC(self->filename, node.loc, "expected more tokens after `" SV_FMT "`", SV_UNWRAP(ppeek(self).text)); 971 | } 972 | 973 | if (ppeek_(self, 1).kind == TOKEN_KIND_OPEN_PARENT) { 974 | node.kind = NODE_KIND_NATIVE_CALL; 975 | node.as.func_call = packl_parser_parse_func_call(self); 976 | return node; 977 | } 978 | 979 | PACKL_ERROR_LOC(self->filename, node.loc, "expected `(` after the native call `" SV_FMT "`", SV_UNWRAP(ppeek(self).text)); 980 | } 981 | 982 | Node packl_get_node_from_if(If_Statement fi) { 983 | return (Node) { .kind = NODE_KIND_IF, .as.fi = fi }; 984 | } 985 | 986 | If_Statement packl_parser_parse_if_statement(PACKL_File *self) { 987 | If_Statement fi = {0}; 988 | 989 | // consume the `if` token 990 | pexp(self, TOKEN_KIND_IF, NULL); 991 | 992 | if (peot(self)) { PACKL_ERROR(self->filename, "expected `if` condition but end found"); } 993 | 994 | if (ppeek(self).kind == TOKEN_KIND_OPEN_PARENT) { 995 | padv(self); 996 | fi.condition = packl_parser_parse_expr(self); 997 | pexp(self, TOKEN_KIND_CLOSE_PARENT, NULL); 998 | pexp(self, TOKEN_KIND_OPEN_CURLY_BRACE, NULL); 999 | } else { 1000 | fi.condition = packl_parser_parse_expr(self); 1001 | } 1002 | 1003 | fi.body = malloc(sizeof(AST)); 1004 | *fi.body = packl_parser_parse_body(self); 1005 | pexp(self, TOKEN_KIND_CLOSE_CURLY_BRACE, NULL); 1006 | 1007 | if (peot(self)) { PACKL_ERROR(self->filename, "expected more tokens for the `if` statement but end found"); } 1008 | 1009 | if (ppeek(self).kind == TOKEN_KIND_ELSE) { 1010 | padv(self); 1011 | fi.esle = malloc(sizeof(AST)); 1012 | 1013 | if (ppeek(self).kind == TOKEN_KIND_OPEN_CURLY_BRACE) { 1014 | padv(self); 1015 | *fi.esle = packl_parser_parse_body(self); 1016 | pexp(self, TOKEN_KIND_CLOSE_CURLY_BRACE, NULL); 1017 | } else { 1018 | If_Statement elseif = packl_parser_parse_if_statement(self); 1019 | Node node = packl_get_node_from_if(elseif); 1020 | DA_INIT(fi.esle, sizeof(Node)); 1021 | DA_APPEND(fi.esle, node); 1022 | } 1023 | } 1024 | 1025 | return fi; 1026 | } 1027 | 1028 | Func_Def packl_parser_parse_func_def(PACKL_File *self) { 1029 | Func_Def func = {0}; 1030 | Token token = {0}; 1031 | 1032 | pexp(self, TOKEN_KIND_IDENTIFIER, &token); 1033 | func.name = token.text; 1034 | 1035 | if (ppeek(self).kind == TOKEN_KIND_OPEN_PARENT) { 1036 | padv(self); 1037 | func.params = packl_parser_parse_params(self); 1038 | pexp(self, TOKEN_KIND_CLOSE_PARENT, NULL); 1039 | } 1040 | 1041 | // for the return type 1042 | pexp(self, TOKEN_KIND_COLON, NULL); 1043 | func.return_type = packl_parser_parse_type(self); 1044 | 1045 | pexp(self, TOKEN_KIND_OPEN_CURLY_BRACE, &token); 1046 | 1047 | func.body = malloc(sizeof(AST)); 1048 | *func.body = packl_parser_parse_body(self); 1049 | 1050 | pexp(self, TOKEN_KIND_CLOSE_CURLY_BRACE, &token); 1051 | 1052 | return func; 1053 | } 1054 | 1055 | 1056 | Method_Def packl_parser_parse_method_def(PACKL_File *self) { 1057 | Method_Def method = {0}; 1058 | 1059 | Token token = ppeek(self); 1060 | 1061 | switch(token.kind) { 1062 | case TOKEN_KIND_FUNC: 1063 | method.kind = METHOD_KIND_FUNCTION; 1064 | break; 1065 | case TOKEN_KIND_PROC: 1066 | method.kind = METHOD_KIND_PROCEDURE; 1067 | break; 1068 | default: 1069 | ASSERT(false, "`packl_parser_parse_method_def` failed to parse the method defintion type"); 1070 | } 1071 | 1072 | padv(self); 1073 | 1074 | pexp(self, TOKEN_KIND_IDENTIFIER, &token); 1075 | method.class_name = token.text; 1076 | 1077 | pexp(self, TOKEN_KIND_DOT, NULL); 1078 | 1079 | if (method.kind == METHOD_KIND_FUNCTION) { 1080 | Func_Def func = packl_parser_parse_func_def(self); 1081 | method.as.func = func; 1082 | } else if (method.kind == METHOD_KIND_PROCEDURE) { 1083 | Proc_Def proc = packl_parser_parse_proc_def(self); 1084 | method.as.proc = proc; 1085 | } else { 1086 | ASSERT(false, "`packl_parser_parse_method_def` failed to parse the method defintion node"); 1087 | } 1088 | 1089 | return method; 1090 | } 1091 | 1092 | While_Statement packl_parser_parse_while_statement(PACKL_File *self) { 1093 | While_Statement hwile = {0}; 1094 | 1095 | // consume the `while` token 1096 | pexp(self, TOKEN_KIND_WHILE, NULL); 1097 | 1098 | if (peot(self)) { PACKL_ERROR(self->filename, "expected `while` condition but end found"); } 1099 | 1100 | if (ppeek(self).kind == TOKEN_KIND_OPEN_PARENT) { 1101 | padv(self); 1102 | hwile.condition = packl_parser_parse_expr(self); 1103 | pexp(self, TOKEN_KIND_CLOSE_PARENT, NULL); 1104 | pexp(self, TOKEN_KIND_OPEN_CURLY_BRACE, NULL); 1105 | } else { 1106 | hwile.condition = packl_parser_parse_expr(self); 1107 | } 1108 | 1109 | hwile.body = malloc(sizeof(AST)); 1110 | *hwile.body = packl_parser_parse_body(self); 1111 | pexp(self, TOKEN_KIND_CLOSE_CURLY_BRACE, NULL); 1112 | 1113 | if (peot(self)) { PACKL_ERROR(self->filename, "expected more tokens for the `while` statement but end found"); } 1114 | 1115 | return hwile; 1116 | } 1117 | 1118 | For_Statement packl_parser_parser_for(PACKL_File *self) { 1119 | For_Statement rof = {0}; 1120 | 1121 | pexp(self, TOKEN_KIND_FOR, NULL); 1122 | 1123 | Token token = {0}; 1124 | pexp(self, TOKEN_KIND_IDENTIFIER, &token); 1125 | rof.iter = token.text; 1126 | 1127 | pexp(self, TOKEN_KIND_COLON, NULL); 1128 | 1129 | rof.iter_type = packl_parser_parse_type(self); 1130 | 1131 | pexp(self, TOKEN_KIND_IN, NULL); 1132 | 1133 | pexp(self, TOKEN_KIND_OPEN_PARENT, NULL); 1134 | rof.args = packl_parser_parse_args(self); 1135 | pexp(self, TOKEN_KIND_CLOSE_PARENT, NULL); 1136 | 1137 | pexp(self, TOKEN_KIND_OPEN_CURLY_BRACE, NULL); 1138 | rof.body = malloc(sizeof(AST)); 1139 | *rof.body = packl_parser_parse_body(self); 1140 | pexp(self, TOKEN_KIND_CLOSE_CURLY_BRACE, NULL); 1141 | 1142 | return rof; 1143 | } 1144 | 1145 | Expression packl_parser_parse_return(PACKL_File *self) { 1146 | pexp(self, TOKEN_KIND_RETURN, NULL); 1147 | return packl_parser_parse_expr(self); 1148 | } 1149 | 1150 | Use packl_parser_parse_module_use(PACKL_File *self) { 1151 | Use use = {0}; 1152 | 1153 | pexp(self, TOKEN_KIND_USE, NULL); 1154 | 1155 | Token token = {0}; 1156 | pexp(self, TOKEN_KIND_STRING_LIT, &token); 1157 | use.filename = token.text; 1158 | 1159 | pexp(self, TOKEN_KIND_AS, NULL); 1160 | 1161 | pexp(self, TOKEN_KIND_IDENTIFIER, &token); 1162 | use.alias = token.text; 1163 | use.has_alias = 1; 1164 | 1165 | return use; 1166 | } 1167 | 1168 | Attribute packl_parser_parse_class_attr(PACKL_File *self) { 1169 | Attribute attr = {0}; 1170 | 1171 | Token token = {0}; 1172 | pexp(self, TOKEN_KIND_IDENTIFIER, &token); 1173 | attr.name = token.text; 1174 | 1175 | pexp(self, TOKEN_KIND_COLON, NULL); 1176 | 1177 | attr.type = packl_parser_parse_type(self); 1178 | 1179 | return attr; 1180 | } 1181 | 1182 | Attributes packl_parser_parse_class_attrs(PACKL_File *self) { 1183 | Attributes attrs = {0}; 1184 | DA_INIT(&attrs, sizeof(Attribute)); 1185 | 1186 | while (!peot(self)) { 1187 | if (ppeek(self).kind == TOKEN_KIND_CLOSE_CURLY_BRACE) { break; } 1188 | Attribute attr = packl_parser_parse_class_attr(self); 1189 | DA_APPEND(&attrs, attr); 1190 | if (ppeek(self).kind == TOKEN_KIND_SEMI_COLON) { padv(self); } 1191 | } 1192 | 1193 | return attrs; 1194 | } 1195 | 1196 | Class_Def packl_parser_parse_class(PACKL_File *self) { 1197 | Class_Def class = {0}; 1198 | 1199 | pexp(self, TOKEN_KIND_CLASS, NULL); 1200 | 1201 | Token token = {0}; 1202 | pexp(self, TOKEN_KIND_IDENTIFIER, &token); 1203 | class.name = token.text; 1204 | 1205 | pexp(self, TOKEN_KIND_OPEN_CURLY_BRACE, NULL); 1206 | class.attrs = packl_parser_parse_class_attrs(self); 1207 | pexp(self, TOKEN_KIND_CLOSE_CURLY_BRACE, NULL); 1208 | 1209 | return class; 1210 | } 1211 | 1212 | Node packl_parser_parse_method_def_node(PACKL_File *self) { 1213 | Node node = packl_init_node(NODE_KIND_METHOD_DEF, ppeek(self).loc); 1214 | node.as.method_def = packl_parser_parse_method_def(self); 1215 | return node; 1216 | } 1217 | 1218 | Node packl_parser_parse_proc_def_node(PACKL_File *self) { 1219 | if (packl_get_tokens_number(self) < 3) { 1220 | PACKL_ERROR_LOC(self->filename, ppeek(self).loc, "expected more tokens for procedure parsing"); 1221 | } 1222 | 1223 | if (ppeek_(self, 2).kind == TOKEN_KIND_DOT) { 1224 | return packl_parser_parse_method_def_node(self); 1225 | } 1226 | 1227 | pexp(self, TOKEN_KIND_PROC, NULL); 1228 | Node node = packl_init_node(NODE_KIND_PROC_DEF, ppeek(self).loc); 1229 | node.as.proc_def = packl_parser_parse_proc_def(self); 1230 | return node; 1231 | } 1232 | 1233 | Node packl_parser_parse_func_def_node(PACKL_File *self) { 1234 | if (packl_get_tokens_number(self) < 3) { 1235 | PACKL_ERROR_LOC(self->filename, ppeek(self).loc, "expected more tokens for function parsing"); 1236 | } 1237 | 1238 | if (ppeek_(self, 2).kind == TOKEN_KIND_DOT) { 1239 | return packl_parser_parse_method_def_node(self); 1240 | } 1241 | 1242 | pexp(self, TOKEN_KIND_FUNC, NULL); 1243 | Node node = packl_init_node(NODE_KIND_FUNC_DEF, ppeek(self).loc); 1244 | node.as.func_def = packl_parser_parse_func_def(self); 1245 | return node; 1246 | } 1247 | 1248 | Node packl_parser_parse_var_dec_node(PACKL_File *self) { 1249 | Node node = packl_init_node(NODE_KIND_VAR_DECLARATION, ppeek(self).loc); 1250 | node.as.var_dec = packl_parser_parse_var_dec(self); 1251 | return node; 1252 | } 1253 | 1254 | Node packl_parser_parse_if_node(PACKL_File *self) { 1255 | Node node = packl_init_node(NODE_KIND_IF, ppeek(self).loc); 1256 | node.as.fi = packl_parser_parse_if_statement(self); 1257 | return node; 1258 | } 1259 | 1260 | Node packl_parser_parse_while_node(PACKL_File *self) { 1261 | Node node = packl_init_node(NODE_KIND_WHILE, ppeek(self).loc); 1262 | node.as.hwile = packl_parser_parse_while_statement(self); 1263 | return node; 1264 | } 1265 | 1266 | 1267 | Node packl_parser_parse_return_node(PACKL_File *self) { 1268 | Node node = packl_init_node(NODE_KIND_RETURN, ppeek(self).loc); 1269 | node.as.ret = packl_parser_parse_return(self); 1270 | return node; 1271 | } 1272 | 1273 | Node packl_parser_parse_for_node(PACKL_File *self) { 1274 | Node node = packl_init_node(NODE_KIND_FOR, ppeek(self).loc); 1275 | node.as.rof = packl_parser_parser_for(self); 1276 | return node; 1277 | } 1278 | 1279 | Node packl_parser_parse_use_node(PACKL_File *self) { 1280 | Node node = packl_init_node(NODE_KIND_USE, ppeek(self).loc); 1281 | node.as.use = packl_parser_parse_module_use(self); 1282 | return node; 1283 | } 1284 | 1285 | Node packl_parser_parse_class_node(PACKL_File *self) { 1286 | Node node = packl_init_node(NODE_KIND_CLASS, ppeek(self).loc); 1287 | node.as.class = packl_parser_parse_class(self); 1288 | return node; 1289 | } 1290 | 1291 | Node packl_parser_parse_statement(PACKL_File *self) { 1292 | switch(ppeek(self).kind) { 1293 | case TOKEN_KIND_NATIVE: 1294 | return packl_parser_parse_native_call(self); 1295 | case TOKEN_KIND_IDENTIFIER: 1296 | return packl_parser_parse_identifier(self); 1297 | case TOKEN_KIND_PROC: 1298 | return packl_parser_parse_proc_def_node(self); 1299 | case TOKEN_KIND_VAR: 1300 | return packl_parser_parse_var_dec_node(self); 1301 | case TOKEN_KIND_IF: 1302 | return packl_parser_parse_if_node(self); 1303 | case TOKEN_KIND_WHILE: 1304 | return packl_parser_parse_while_node(self); 1305 | case TOKEN_KIND_FUNC: 1306 | return packl_parser_parse_func_def_node(self); 1307 | case TOKEN_KIND_RETURN: 1308 | return packl_parser_parse_return_node(self); 1309 | case TOKEN_KIND_FOR: 1310 | return packl_parser_parse_for_node(self); 1311 | case TOKEN_KIND_USE: 1312 | return packl_parser_parse_use_node(self); 1313 | case TOKEN_KIND_CLASS: 1314 | return packl_parser_parse_class_node(self); 1315 | default: 1316 | PACKL_ERROR_LOC(self->filename, ppeek(self).loc, "unexpected token found at the beginning of a statement `" SV_FMT "`", SV_UNWRAP(ppeek(self).text)); 1317 | } 1318 | } 1319 | 1320 | AST packl_parser_parse_statements(PACKL_File *self) { 1321 | AST ast = {0}; 1322 | DA_INIT(&ast, sizeof(Node)); 1323 | 1324 | while (!peot(self)) { 1325 | Node node = pstmt(self); 1326 | DA_APPEND(&ast, node); 1327 | if (ppeek(self).kind == TOKEN_KIND_SEMI_COLON) { padv(self); } 1328 | } 1329 | 1330 | return ast; 1331 | } 1332 | 1333 | void packl_parser_parse(PACKL_File *self) { 1334 | self->ast = packl_parser_parse_statements(self); 1335 | } 1336 | -------------------------------------------------------------------------------- /src/packl-printer.c: -------------------------------------------------------------------------------- 1 | #include "headers/packl-printer.h" 2 | 3 | char *token_kinds[] = { 4 | "id", 5 | "native", 6 | 7 | "str", 8 | "int", 9 | 10 | ";", 11 | ":", 12 | ",", 13 | ".", 14 | 15 | "[", 16 | "]", 17 | "(", 18 | ")", 19 | "{", 20 | "}", 21 | 22 | "=", 23 | 24 | "+", 25 | "++", 26 | "-", 27 | "--", 28 | "*", 29 | "/", 30 | "%", 31 | 32 | "==", 33 | "<", 34 | ">", 35 | "<=", 36 | ">=", 37 | "!", 38 | "!=", 39 | 40 | "proc", 41 | 42 | "func", 43 | "return", 44 | 45 | "var", 46 | 47 | "if", 48 | "else", 49 | 50 | "while", 51 | 52 | "for", 53 | "in", 54 | 55 | "use", 56 | "as", 57 | 58 | "class", 59 | 60 | "or", 61 | "and", 62 | "xor", 63 | 64 | "array", 65 | "type-int", 66 | "type-str", 67 | "type-ptr", 68 | 69 | "operator", 70 | 71 | "end", 72 | }; 73 | 74 | char *operator_input_kind[] = { 75 | "type", 76 | "identifier", 77 | }; 78 | 79 | void packl_print_expr(Expression expr, size_t indent); 80 | void packl_print_mod_call(Mod_Call mod_call, size_t indent); 81 | void packl_print_func_call(Func_Call func_call, size_t indent); 82 | void packl_print_method_call(Method_Call method, size_t indent); 83 | void packl_print_ast_nodes(AST ast, size_t indent); 84 | 85 | void print_indent(size_t indent) { 86 | for (size_t i = 0; i < indent; ++i) { printf(" "); } 87 | } 88 | 89 | void packl_print_operator(Operator op, size_t indent) { 90 | switch(op) { 91 | case OP_PLUS: 92 | printf("+\n"); 93 | break; 94 | case OP_MINUS: 95 | printf("-\n"); 96 | break; 97 | case OP_MUL: 98 | printf("*\n"); 99 | break; 100 | case OP_DIV: 101 | printf("/\n"); 102 | break; 103 | case OP_MOD: 104 | printf("mod\n"); 105 | break; 106 | case OP_L: 107 | printf("<\n"); 108 | break; 109 | case OP_G: 110 | printf(">\n"); 111 | break; 112 | case OP_LE: 113 | printf("<=\n"); 114 | break; 115 | case OP_GE: 116 | printf(">=\n"); 117 | break; 118 | case OP_EQ: 119 | printf("==\n"); 120 | break; 121 | case OP_AND: 122 | printf("and\n"); 123 | break; 124 | case OP_OR: 125 | printf("or\n"); 126 | break; 127 | case OP_XOR: 128 | printf("xor\n"); 129 | break; 130 | case OP_NOT: 131 | printf("!\n"); 132 | break; 133 | case OP_NE: 134 | printf("!="); 135 | break; 136 | case OP_INC: 137 | printf("++\n"); 138 | break; 139 | case OP_DEC: 140 | printf("--\n"); 141 | break; 142 | default: 143 | ASSERT(false, "unreachable"); 144 | } 145 | } 146 | 147 | char *packl_token_kind_stringify(Token_Kind kind) { 148 | return token_kinds[kind]; 149 | } 150 | 151 | void packl_print_token(Token tok) { 152 | char *token_kind_str = packl_token_kind_stringify(tok.kind); 153 | 154 | printf("%s\t", token_kind_str); 155 | if (tok.text.count == 0) { printf("\n"); return; } 156 | printf(SV_FMT "\n", SV_UNWRAP(tok.text)); 157 | } 158 | 159 | void packl_print_tokens(Tokens toks) { 160 | for (size_t i = 0; i < toks.count; ++i) { 161 | packl_print_token(toks.items[i]); 162 | } 163 | } 164 | 165 | void packl_print_basic_type(Type type, size_t indent) { 166 | print_indent(indent); 167 | if(type == PACKL_TYPE_INT) { 168 | printf("int-type\n"); 169 | return; 170 | } 171 | 172 | if (type == PACKL_TYPE_STR) { 173 | printf("str-type\n"); 174 | return; 175 | } 176 | 177 | if (type == PACKL_TYPE_PTR) { 178 | printf("ptr-type\n"); 179 | return; 180 | } 181 | 182 | ASSERT(false, "unreachable"); 183 | } 184 | 185 | void packl_print_type(PACKL_Type type, size_t indent); 186 | 187 | void packl_print_array_type(Array_Type type, size_t indent) { 188 | print_indent(indent); 189 | printf("type: array\n"); 190 | packl_print_type(*type.item_type, indent + 1); 191 | print_indent(indent); 192 | printf("size: %zu\n", (size_t)type.size); 193 | } 194 | 195 | void packl_print_type(PACKL_Type type, size_t indent) { 196 | if(type.kind == PACKL_TYPE_BASIC) { 197 | packl_print_basic_type(type.as.basic, indent); 198 | return; 199 | } 200 | 201 | 202 | if (type.kind == PACKL_TYPE_ARRAY) { 203 | packl_print_array_type(type.as.array, indent); 204 | return; 205 | } 206 | 207 | if (type.kind == PACKL_TYPE_USER_DEFINED) { 208 | print_indent(indent); 209 | printf("user-defined: `" SV_FMT "`\n", SV_UNWRAP(type.as.user_defined)); 210 | return; 211 | } 212 | 213 | ASSERT(false, "unreachable"); 214 | } 215 | 216 | void packl_print_expr_arr(Expr_Arr exprs, size_t indent) { 217 | print_indent(indent); 218 | printf("array:\n"); 219 | for(size_t i = 0; i < exprs.count; ++i) { 220 | packl_print_expr(exprs.items[i], indent + 1); 221 | } 222 | } 223 | 224 | void packl_print_expr_arr_index(Expr_Arr_Index arr_index, size_t indent) { 225 | print_indent(indent); 226 | printf("array indexing:\n"); 227 | 228 | print_indent(indent + 1); 229 | printf("array name: `" SV_FMT "`\n", SV_UNWRAP(arr_index.name)); 230 | 231 | packl_print_expr(*arr_index.index, indent + 1); 232 | } 233 | 234 | void packl_print_string_expr(String_View value, size_t indent) { 235 | print_indent(indent); 236 | printf("string: \"" SV_FMT "\"\n", SV_UNWRAP(value)); 237 | } 238 | 239 | void packl_print_integer_expr(int64_t value, size_t indent) { 240 | print_indent(indent); 241 | printf("integer: %ld\n", value); 242 | } 243 | 244 | void packl_print_id_expr(String_View value, size_t indent) { 245 | print_indent(indent); 246 | printf("identifier: `" SV_FMT "`\n", SV_UNWRAP(value)); 247 | } 248 | 249 | void packl_print_binop_expr(Expression expr, size_t indent) { 250 | print_indent(indent); 251 | packl_print_operator(expr.as.bin.op, indent + 1); 252 | packl_print_expr(*expr.as.bin.lhs, indent + 2); 253 | packl_print_expr(*expr.as.bin.rhs, indent + 2); 254 | } 255 | 256 | void packl_print_preunary_expr(Expr_Unary_Op unary, size_t indent) { 257 | print_indent(indent); 258 | printf("pre-unary:\n"); 259 | 260 | print_indent(indent + 1); 261 | packl_print_operator(unary.op, indent + 1); 262 | 263 | if (unary.operand) { 264 | packl_print_expr(*unary.operand, indent + 2); 265 | } 266 | } 267 | 268 | void packl_print_postunary_expr(Expr_Unary_Op unary, size_t indent) { 269 | print_indent(indent); 270 | printf("post-unary:\n"); 271 | 272 | print_indent(indent + 1); 273 | packl_print_operator(unary.op, indent + 1); 274 | 275 | if (unary.operand) { 276 | packl_print_expr(*unary.operand, indent + 2); 277 | } 278 | } 279 | 280 | void packl_print_operator_expr(Expr_Operator operator, size_t indent) { 281 | print_indent(indent); 282 | printf("operator: %s\n", builtin_operators[operator.op]); 283 | 284 | print_indent(indent + 1); 285 | printf("input-type: `%s`\n", operator_input_kind[operator.input.kind]); 286 | 287 | if (operator.input.kind == INPUT_KIND_TYPE) { 288 | packl_print_type(operator.input.as.type, indent + 1); 289 | } else { 290 | print_indent(indent + 1); 291 | printf("value: `" SV_FMT "`\n", SV_UNWRAP(operator.input.as.identifier)); 292 | } 293 | } 294 | 295 | void packl_print_object_attr_expr(Expr_Attribute attr, size_t indent) { 296 | print_indent(indent); 297 | printf("object name: `" SV_FMT "`, attribute: `" SV_FMT "`\n", SV_UNWRAP(attr.obj_name), SV_UNWRAP(attr.attr)); 298 | } 299 | 300 | void packl_print_expr(Expression expr, size_t indent) { 301 | switch(expr.kind) { 302 | case EXPR_KIND_OPERATOR: 303 | return packl_print_operator_expr(expr.as.operator, indent); 304 | case EXPR_KIND_STRING: 305 | return packl_print_string_expr(expr.as.value, indent); 306 | case EXPR_KIND_INTEGER: 307 | return packl_print_integer_expr(expr.as.integer, indent); 308 | case EXPR_KIND_ID: 309 | return packl_print_id_expr(expr.as.value, indent); 310 | case EXPR_KIND_FUNC_CALL: 311 | return packl_print_func_call(*expr.as.func, indent); 312 | case EXPR_KIND_BIN_OP: 313 | return packl_print_binop_expr(expr, indent); 314 | case EXPR_KIND_NATIVE_CALL: 315 | return packl_print_func_call(*expr.as.func, indent); 316 | case EXPR_KIND_MOD_CALL: 317 | return packl_print_mod_call(*expr.as.mod, indent); 318 | case EXPR_KIND_ARRAY: 319 | return packl_print_expr_arr(expr.as.arr, indent); 320 | case EXPR_KIND_ARRAY_INDEXING: 321 | return packl_print_expr_arr_index(expr.as.arr_index, indent); 322 | case EXPR_KIND_PRE_UNARY_OP: 323 | return packl_print_preunary_expr(expr.as.unary, indent); 324 | case EXPR_KIND_POST_UNARY_OP: 325 | return packl_print_postunary_expr(expr.as.unary, indent); 326 | case EXPR_KIND_OBJECT_ATTRIBUTE: 327 | return packl_print_object_attr_expr(expr.as.attr, indent); 328 | case EXPR_KIND_OBJECT_METHOD: 329 | return packl_print_method_call(*expr.as.method, indent); 330 | case EXPR_KIND_NOT_INITIALIZED: 331 | print_indent(indent); 332 | printf("not initialized\n"); 333 | return; 334 | default: 335 | ASSERT(false, "unreachable"); 336 | } 337 | } 338 | 339 | void packl_print_arg(PACKL_Arg arg, size_t indent) { 340 | packl_print_expr(arg.expr, indent); 341 | } 342 | 343 | void packl_print_args(PACKL_Args args, size_t indent) { 344 | print_indent(indent); 345 | printf("begin\n"); 346 | 347 | for(size_t i = 0; i < args.count; ++i) { 348 | packl_print_arg(args.items[i], indent + 1); 349 | } 350 | 351 | print_indent(indent); 352 | printf("end\n"); 353 | } 354 | 355 | void packl_print_func_call(Func_Call func_call, size_t indent) { 356 | print_indent(indent); 357 | printf("func name: `"SV_FMT"`\n", SV_UNWRAP(func_call.name)); 358 | 359 | print_indent(indent + 1); 360 | printf("args:\n"); 361 | packl_print_args(func_call.args, indent + 2); 362 | } 363 | 364 | void packl_print_param(Parameter param, size_t indent) { 365 | print_indent(indent); 366 | printf("name: `" SV_FMT "`", SV_UNWRAP(param.name)); 367 | print_indent(indent); 368 | printf("type:"); 369 | packl_print_type(param.type, indent); 370 | } 371 | 372 | void packl_print_params(Parameters params, size_t indent) { 373 | print_indent(indent); 374 | printf("begin\n"); 375 | 376 | for(size_t i = 0; i < params.count; ++i) { 377 | packl_print_param(params.items[i], indent + 1); 378 | } 379 | 380 | print_indent(indent); 381 | printf("end\n"); 382 | } 383 | 384 | void packl_print_body(AST body, size_t indent) { 385 | print_indent(indent); 386 | printf("body:"); 387 | packl_print_ast_nodes(body, indent + 2); 388 | } 389 | 390 | void packl_print_proc_def(Proc_Def proc_def, size_t indent) { 391 | print_indent(indent); 392 | printf("proc name: `"SV_FMT"`\n", SV_UNWRAP(proc_def.name)); 393 | 394 | print_indent(indent + 1); 395 | printf("params:\n"); 396 | packl_print_params(proc_def.params, indent + 2); 397 | 398 | packl_print_body(*proc_def.body, indent + 1); 399 | } 400 | 401 | void packl_print_var_dec(Var_Declaration var_dec, size_t indent) { 402 | print_indent(indent); 403 | printf("variable name: `" SV_FMT "`\n", SV_UNWRAP(var_dec.name)); 404 | 405 | print_indent(indent); 406 | printf("variable type:\n"); 407 | packl_print_type(var_dec.type, indent + 1); 408 | 409 | print_indent(indent); 410 | printf("value:\n"); 411 | 412 | packl_print_expr(var_dec.value, indent + 1); 413 | } 414 | 415 | void packl_print_else(AST ast, size_t indent) { 416 | print_indent(indent); 417 | printf("else:\n"); 418 | packl_print_body(ast, indent + 1); 419 | } 420 | 421 | void packl_print_if(If_Statement fi, size_t indent) { 422 | print_indent(indent); 423 | printf("condition:\n"); 424 | packl_print_expr(fi.condition, indent + 1); 425 | 426 | packl_print_body(*fi.body, indent + 1); 427 | 428 | if (fi.esle) { 429 | packl_print_else(*fi.esle, indent); 430 | } 431 | } 432 | 433 | void packl_print_while(While_Statement hwile, size_t indent) { 434 | print_indent(indent); 435 | printf("condition:\n"); 436 | packl_print_expr(hwile.condition, indent + 1); 437 | packl_print_body(*hwile.body, indent + 1); 438 | } 439 | 440 | void packl_print_for(For_Statement rof, size_t indent) { 441 | print_indent(indent); 442 | printf("iterator: `" SV_FMT "`", SV_UNWRAP(rof.iter)); 443 | print_indent(indent); 444 | printf("type:\n"); 445 | packl_print_type(rof.iter_type, indent); 446 | packl_print_args(rof.args, indent + 1); 447 | packl_print_body(*rof.body, indent + 1); 448 | } 449 | 450 | void packl_print_use(Use use, size_t indent) { 451 | print_indent(indent); 452 | printf("file `" SV_FMT "`\n", SV_UNWRAP(use.filename)); 453 | print_indent(indent); 454 | printf("alias: `" SV_FMT "`\n", SV_UNWRAP(use.alias)); 455 | } 456 | 457 | void packl_print_mod_call(Mod_Call mod_call, size_t indent) { 458 | print_indent(indent); 459 | printf("alias `" SV_FMT "`\n", SV_UNWRAP(mod_call.name)); 460 | if (mod_call.kind == MODULE_CALL_FUNC_CALL) { 461 | packl_print_func_call(mod_call.as.func_call, indent + 1); 462 | } else { 463 | print_indent(indent + 1); 464 | printf("kind: variable, name: `" SV_FMT "`\n", SV_UNWRAP(mod_call.as.var_name)); 465 | } 466 | } 467 | 468 | void packl_print_attr(Attribute attr, size_t indent) { 469 | print_indent(indent); 470 | printf("name: `" SV_FMT "`", SV_UNWRAP(attr.name)); 471 | print_indent(indent); 472 | printf("type:"); 473 | packl_print_type(attr.type, indent); 474 | } 475 | 476 | void packl_print_attrs(Attributes attrs, size_t indent) { 477 | print_indent(indent); 478 | printf("begin\n"); 479 | 480 | for(size_t i = 0; i < attrs.count; ++i) { 481 | packl_print_attr(attrs.items[i], indent + 1); 482 | } 483 | 484 | print_indent(indent); 485 | printf("end\n"); 486 | } 487 | 488 | void packl_print_method_call(Method_Call method, size_t indent) { 489 | print_indent(indent); 490 | printf("object name: `" SV_FMT "`\n", SV_UNWRAP(method.object_name)); 491 | packl_print_func_call(method.func, indent + 1); 492 | } 493 | 494 | void packl_print_class(Class_Def class, size_t indent) { 495 | print_indent(indent); 496 | printf("class name: `" SV_FMT "`\n", SV_UNWRAP(class.name)); 497 | 498 | print_indent(indent); 499 | printf("attrs\n"); 500 | packl_print_attrs(class.attrs, indent + 1); 501 | } 502 | 503 | void packl_print_var_reassign(Var_Reassign var, size_t indent) { 504 | print_indent(indent); 505 | printf("variable name: `" SV_FMT "`\n", SV_UNWRAP(var.format.name)); 506 | 507 | if(var.format.kind == VARIABLE_FORMAT_ARRAY) { 508 | print_indent(indent); 509 | printf("type: array\n"); 510 | print_indent(indent); 511 | printf("index:\n"); 512 | packl_print_expr(var.format.as.index, indent + 1); 513 | } else if (var.format.kind == VARIABLE_FORMAT_CLASS) { 514 | print_indent(indent); 515 | printf("type: attr, `" SV_FMT "`\n", SV_UNWRAP(var.format.as.attr)); 516 | } else { 517 | print_indent(indent); 518 | printf("type: basic\n"); 519 | } 520 | 521 | print_indent(indent); 522 | printf("value:\n"); 523 | packl_print_expr(var.value, indent + 1); 524 | } 525 | 526 | void packl_print_func_def(Func_Def func, size_t indent) { 527 | print_indent(indent); 528 | printf("function name: `" SV_FMT "`\n", SV_UNWRAP(func.name)); 529 | 530 | print_indent(indent); 531 | printf("return type\n"); 532 | packl_print_type(func.return_type, indent); 533 | packl_print_body(*func.body, indent + 1); 534 | } 535 | 536 | void packl_print_method_def(Method_Def method, size_t indent) { 537 | print_indent(indent); 538 | printf("class name: `" SV_FMT "`\n", SV_UNWRAP(method.class_name)); 539 | 540 | if (method.kind == METHOD_KIND_FUNCTION) { 541 | packl_print_func_def(method.as.func, indent + 1); 542 | } else if (method.kind == METHOD_KIND_PROCEDURE) { 543 | packl_print_proc_def(method.as.proc, indent + 1); 544 | } else { 545 | ASSERT(false, "`packl_print_method_def` failed to print the method, unknow method kind"); 546 | } 547 | } 548 | 549 | void packl_print_native_call_node(Node node, size_t indent) { 550 | print_indent(indent); 551 | printf("node kind: native call\n"); 552 | 553 | packl_print_func_call(node.as.func_call, indent + 1); 554 | } 555 | 556 | void packl_print_func_call_node(Node node, size_t indent) { 557 | print_indent(indent); 558 | printf("node kind: function call\n"); 559 | packl_print_func_call(node.as.func_call, indent + 1); 560 | } 561 | 562 | void packl_print_proc_def_node(Node node, size_t indent) { 563 | print_indent(indent); 564 | printf("node kind: procedure defintion\n"); 565 | packl_print_proc_def(node.as.proc_def, indent + 1); 566 | } 567 | 568 | void packl_print_var_dec_node(Node node, size_t indent) { 569 | print_indent(indent); 570 | printf("node kind: variable declaration\n"); 571 | packl_print_var_dec(node.as.var_dec, indent + 1); 572 | } 573 | 574 | void packl_print_if_node(Node node, size_t indent) { 575 | print_indent(indent); 576 | printf("node kind: if statement\n"); 577 | packl_print_if(node.as.fi, indent + 1); 578 | } 579 | 580 | void packl_print_while_node(Node node, size_t indent) { 581 | print_indent(indent); 582 | printf("node kind: while statement\n"); 583 | packl_print_while(node.as.hwile, indent + 1); 584 | } 585 | 586 | void packl_print_var_reassign_node(Node node, size_t indent) { 587 | print_indent(indent); 588 | printf("node kind: variable reassignement\n"); 589 | packl_print_var_reassign(node.as.var, indent + 1); 590 | } 591 | 592 | void packl_print_func_def_node(Node node, size_t indent) { 593 | print_indent(indent); 594 | printf("node kind: function definition\n"); 595 | packl_print_func_def(node.as.func_def, indent + 1); 596 | } 597 | 598 | void packl_print_method_def_node(Node node, size_t indent) { 599 | print_indent(indent); 600 | printf("node kind: method definition\n"); 601 | packl_print_method_def(node.as.method_def, indent + 1); 602 | } 603 | 604 | void packl_print_return_node(Node node, size_t indent) { 605 | print_indent(indent); 606 | printf("return:\n"); 607 | packl_print_expr(node.as.ret, indent + 1); 608 | } 609 | 610 | void packl_print_for_node(Node node, size_t indent) { 611 | print_indent(indent); 612 | printf("node kind: for statement\n"); 613 | packl_print_for(node.as.rof, indent + 1); 614 | } 615 | 616 | void packl_print_use_node(Node node, size_t indent) { 617 | print_indent(indent); 618 | printf("node kind: use\n"); 619 | packl_print_use(node.as.use, indent + 1); 620 | } 621 | 622 | void packl_print_mod_call_node(Node node, size_t indent) { 623 | print_indent(indent); 624 | printf("node kind: module call\n"); 625 | packl_print_mod_call(node.as.mod_call, indent + 1); 626 | } 627 | 628 | void packl_print_class_def_node(Node node, size_t indent) { 629 | print_indent(indent); 630 | printf("node kind: class defintion\n"); 631 | packl_print_class(node.as.class, indent + 1); 632 | } 633 | 634 | void packl_print_method_call_node(Node node, size_t indent) { 635 | print_indent(indent); 636 | printf("node kind: method call\n"); 637 | packl_print_method_call(node.as.method_call, indent); 638 | } 639 | 640 | void packl_print_ast_node(Node node, size_t indent) { 641 | switch(node.kind) { 642 | case NODE_KIND_NATIVE_CALL: 643 | return packl_print_native_call_node(node, indent); 644 | case NODE_KIND_FUNC_CALL: 645 | return packl_print_func_call_node(node, indent); 646 | case NODE_KIND_PROC_DEF: 647 | return packl_print_proc_def_node(node, indent); 648 | case NODE_KIND_VAR_DECLARATION: 649 | return packl_print_var_dec_node(node, indent); 650 | case NODE_KIND_IF: 651 | return packl_print_if_node(node, indent); 652 | case NODE_KIND_WHILE: 653 | return packl_print_while_node(node, indent); 654 | case NODE_KIND_VAR_REASSIGN: 655 | return packl_print_var_reassign_node(node, indent); 656 | case NODE_KIND_FUNC_DEF: 657 | return packl_print_func_def_node(node, indent); 658 | case NODE_KIND_RETURN: 659 | return packl_print_return_node(node, indent); 660 | case NODE_KIND_FOR: 661 | return packl_print_for_node(node, indent); 662 | case NODE_KIND_USE: 663 | return packl_print_use_node(node, indent); 664 | case NODE_KIND_MOD_CALL: 665 | return packl_print_mod_call_node(node, indent); 666 | case NODE_KIND_CLASS: 667 | return packl_print_class_def_node(node, indent); 668 | case NODE_KIND_METHOD_DEF: 669 | return packl_print_method_def_node(node, indent); 670 | case NODE_KIND_METHOD_CALL: 671 | return packl_print_method_call_node(node, indent); 672 | default: 673 | ASSERT(false, "unreachable"); 674 | } 675 | } 676 | 677 | void packl_print_ast_nodes(AST ast, size_t indent) { 678 | for (size_t i = 0; i < ast.count; ++i) { 679 | printf("\n"); 680 | packl_print_ast_node(ast.items[i], indent); 681 | } 682 | } 683 | 684 | void packl_print_ast(AST ast) { 685 | printf("Program: \n"); 686 | packl_print_ast_nodes(ast, 0); 687 | } -------------------------------------------------------------------------------- /src/packl.c: -------------------------------------------------------------------------------- 1 | #include "headers/packl.h" 2 | 3 | PACKL_Compiler packl_init(char *input, char *output) { 4 | PACKL_Compiler c = {0}; 5 | c.output = output; 6 | char *fullpath = malloc(sizeof(char) * (FILENAME_MAX)); 7 | 8 | if (!realpath(input, fullpath)) { 9 | fprintf(stderr, "could not find the file %s\n", input); 10 | exit(1); 11 | } 12 | 13 | c.root_file = packl_init_file(input, fullpath); 14 | return c; 15 | } 16 | 17 | void packl_generate_code(PACKL_Compiler *c) { 18 | c->f = fopen(c->output, "w"); 19 | if(!c->f) { 20 | PACKL_ERROR(c->root_file.filename, "could not open the output file for writing"); 21 | } 22 | codegen(c, &c->root_file); 23 | fclose(c->f); 24 | } 25 | 26 | void packl_compile(PACKL_Compiler *c) { 27 | lex(&c->root_file); 28 | parse(&c->root_file); 29 | packl_generate_code(c); 30 | } 31 | 32 | void packl_destroy_ast(AST ast); 33 | 34 | void packl_destroy_func_call(Func_Call call); 35 | 36 | 37 | void packl_destroy_type(PACKL_Type type) { 38 | if(type.kind == PACKL_TYPE_BASIC) { return; } 39 | if(type.kind == PACKL_TYPE_ARRAY) { 40 | packl_destroy_type(*type.as.array.item_type); 41 | free(type.as.array.item_type); 42 | return; 43 | } 44 | if (type.kind == PACKL_TYPE_USER_DEFINED) { return; } 45 | ASSERT(false, "unreachable"); 46 | } 47 | 48 | void packl_destroy_expr(Expression expr) { 49 | switch(expr.kind) { 50 | case EXPR_KIND_OPERATOR: 51 | if (expr.as.operator.input.kind == INPUT_KIND_TYPE) { 52 | packl_destroy_type(expr.as.operator.input.as.type); 53 | } 54 | break; 55 | case EXPR_KIND_BIN_OP: 56 | packl_destroy_expr(*expr.as.bin.lhs); 57 | packl_destroy_expr(*expr.as.bin.rhs); 58 | free(expr.as.bin.lhs); 59 | free(expr.as.bin.rhs); 60 | break; 61 | case EXPR_KIND_FUNC_CALL: 62 | packl_destroy_func_call(*expr.as.func); 63 | free(expr.as.func); 64 | break; 65 | case EXPR_KIND_ARRAY: 66 | for(size_t i = 0; i < expr.as.arr.count; ++i) { 67 | packl_destroy_expr(expr.as.arr.items[i]); 68 | } 69 | free(expr.as.arr.items); 70 | break; 71 | case EXPR_KIND_ARRAY_INDEXING: 72 | packl_destroy_expr(*expr.as.arr_index.index); 73 | free(expr.as.arr_index.index); 74 | break; 75 | case EXPR_KIND_PRE_UNARY_OP: 76 | case EXPR_KIND_POST_UNARY_OP: 77 | if (expr.as.unary.operand) { 78 | packl_destroy_expr(*expr.as.unary.operand); 79 | free(expr.as.unary.operand); 80 | } 81 | break; 82 | case EXPR_KIND_OBJECT_METHOD: 83 | packl_destroy_func_call(expr.as.method->func); 84 | free(expr.as.method); 85 | break; 86 | default: 87 | break; 88 | } 89 | } 90 | 91 | void packl_destroy_native_call(Func_Call call) { 92 | packl_destroy_func_call(call); 93 | } 94 | 95 | void packl_destroy_func_call(Func_Call call) { 96 | for(size_t i = 0; i < call.args.count; ++i) { 97 | Expression arg = call.args.items[i].expr; 98 | packl_destroy_expr(arg); 99 | } 100 | free(call.args.items); 101 | } 102 | 103 | void packl_destroy_proc_def(Proc_Def proc) { 104 | packl_destroy_ast(*proc.body); 105 | free(proc.params.items); 106 | free(proc.body); 107 | } 108 | 109 | void packl_destroy_var_dec(Var_Declaration var) { 110 | packl_destroy_expr(var.value); 111 | packl_destroy_type(var.type); 112 | } 113 | 114 | void packl_destroy_if(If_Statement fi) { 115 | packl_destroy_expr(fi.condition); 116 | 117 | packl_destroy_ast(*fi.body); 118 | free(fi.body); 119 | 120 | if(fi.esle) { packl_destroy_ast(*fi.esle); free(fi.esle); } 121 | } 122 | 123 | void packl_destroy_while(While_Statement hwile) { 124 | packl_destroy_expr(hwile.condition); 125 | 126 | packl_destroy_ast(*hwile.body); 127 | free(hwile.body); 128 | } 129 | 130 | void packl_destroy_var_reassign(Var_Reassign var) { 131 | if (var.format.kind == VARIABLE_FORMAT_ARRAY) { 132 | packl_destroy_expr(var.format.as.index); 133 | } 134 | 135 | packl_destroy_expr(var.value); 136 | } 137 | 138 | void packl_destroy_func_def(Func_Def func) { 139 | packl_destroy_ast(*func.body); 140 | free(func.params.items); 141 | free(func.body); 142 | } 143 | 144 | void packl_destroy_for(For_Statement rof) { 145 | packl_destroy_ast(*rof.body); 146 | free(rof.args.items); 147 | free(rof.body); 148 | } 149 | 150 | void packl_destroy_mod_call(Mod_Call mod_call) { 151 | if (mod_call.kind == MODULE_CALL_FUNC_CALL) { 152 | packl_destroy_func_call(mod_call.as.func_call); 153 | } 154 | } 155 | 156 | void packl_destroy_class(Class_Def class) { 157 | free(class.attrs.items); 158 | } 159 | 160 | void packl_destroy_method_def(Method_Def method) { 161 | if (method.kind == METHOD_KIND_FUNCTION) { 162 | packl_destroy_func_def(method.as.func); 163 | } else if (method.kind == METHOD_KIND_PROCEDURE) { 164 | packl_destroy_proc_def(method.as.proc); 165 | } else { 166 | ASSERT(false, "`packl_destroy_method_def` failed because of the unknow method kind"); 167 | } 168 | } 169 | 170 | void packl_destroy_method_call(Method_Call method) { 171 | packl_destroy_func_call(method.func); 172 | } 173 | 174 | void packl_destroy_node(Node node) { 175 | switch(node.kind) { 176 | case NODE_KIND_NATIVE_CALL: 177 | return packl_destroy_native_call(node.as.func_call); 178 | case NODE_KIND_FUNC_CALL: 179 | return packl_destroy_func_call(node.as.func_call); 180 | case NODE_KIND_PROC_DEF: 181 | return packl_destroy_proc_def(node.as.proc_def); 182 | case NODE_KIND_VAR_DECLARATION: 183 | return packl_destroy_var_dec(node.as.var_dec); 184 | case NODE_KIND_IF: 185 | return packl_destroy_if(node.as.fi); 186 | case NODE_KIND_WHILE: 187 | return packl_destroy_while(node.as.hwile); 188 | case NODE_KIND_VAR_REASSIGN: 189 | return packl_destroy_var_reassign(node.as.var); 190 | case NODE_KIND_FUNC_DEF: 191 | return packl_destroy_func_def(node.as.func_def); 192 | case NODE_KIND_RETURN: 193 | return packl_destroy_expr(node.as.ret); 194 | case NODE_KIND_FOR: 195 | return packl_destroy_for(node.as.rof); 196 | case NODE_KIND_USE: 197 | return; 198 | case NODE_KIND_MOD_CALL: 199 | return packl_destroy_mod_call(node.as.mod_call); 200 | case NODE_KIND_CLASS: 201 | return packl_destroy_class(node.as.class); 202 | case NODE_KIND_METHOD_DEF: 203 | return packl_destroy_method_def(node.as.method_def); 204 | case NODE_KIND_METHOD_CALL: 205 | return packl_destroy_method_call(node.as.method_call); 206 | default: 207 | ASSERT(false, "unreachable"); 208 | } 209 | } 210 | 211 | void packl_destroy_ast(AST ast) { 212 | for (size_t i = 0; i < ast.count; ++i) { 213 | Node node = ast.items[i]; 214 | packl_destroy_node(node); 215 | } 216 | if (ast.size != 0) free(ast.items); 217 | } 218 | 219 | void packl_file_destroy(PACKL_File *self) { 220 | if (self->tokens.size != 0) free(self->tokens.items); 221 | if (self->lexer.source.count != 0) free(self->lexer.source.content); 222 | packl_destroy_ast(self->ast); 223 | 224 | // pop the global context 225 | if (self->contexts.count) { packl_pop_context(self); } 226 | 227 | if (self->contexts.size) { 228 | packl_remove_contexts(self); 229 | } 230 | 231 | for(size_t i = 0; i < self->used_files.count; ++i) { 232 | packl_file_destroy(&self->used_files.items[i]); 233 | free(self->used_files.items[i].filename); 234 | } 235 | } 236 | 237 | void packl_destroy(PACKL_Compiler *c) { 238 | packl_file_destroy(&c->root_file); 239 | } -------------------------------------------------------------------------------- /src/pvm-instructions.c: -------------------------------------------------------------------------------- 1 | #include "headers/pvm-instructions.h" 2 | 3 | size_t number_of_popped_values[] = { 4 | 2, // write 5 | 1, // read: 2 for reading and 1 for push 6 | 0, // alloc: 1 for the size and 1 for the push 7 | 1, // free 8 | 1, // open: 2 for the filepath and the mode and one of the file pointer (push) 9 | 1, // close 10 | 1, // exit 11 | }; 12 | 13 | void fprintfln(FILE *f) { 14 | fprintf(f, "\n"); 15 | } 16 | 17 | void fprint_indent(FILE *f, size_t indent) { 18 | for (size_t i = 0; i < indent; ++i) { 19 | fprintf(f, " "); 20 | } 21 | } 22 | 23 | void packl_generate_label(PACKL_Compiler *c, size_t label_value, size_t indent) { 24 | fprint_indent(c->f, indent); 25 | fprintf(c->f, "#label_%zu:\n", label_value); 26 | } 27 | 28 | void packl_generate_push(PACKL_Compiler *c, int64_t value, size_t indent) { 29 | fprint_indent(c->f, indent); 30 | fprintf(c->f, "push %ld\n", value); 31 | c->stack_size++; 32 | } 33 | 34 | void packl_generate_pushs(PACKL_Compiler *c, String_View value, size_t indent) { 35 | fprint_indent(c->f, indent); 36 | fprintf(c->f, "pushs \"" SV_FMT "\"\n", SV_UNWRAP(value)); 37 | c->stack_size++; 38 | } 39 | 40 | void packl_generate_nop(PACKL_Compiler *c, size_t indent) { 41 | fprint_indent(c->f, indent); 42 | fprintf(c->f, "nop\n"); 43 | } 44 | 45 | void packl_generate_halt(PACKL_Compiler *c, size_t indent) { 46 | fprint_indent(c->f, indent); 47 | fprintf(c->f, "halt\n"); 48 | } 49 | 50 | void packl_generate_pop(PACKL_Compiler *c, size_t indent) { 51 | fprint_indent(c->f, indent); 52 | fprintf(c->f, "pop\n"); 53 | c->stack_size--; 54 | } 55 | 56 | void packl_generate_add(PACKL_Compiler *c, size_t indent) { 57 | fprint_indent(c->f, indent); 58 | fprintf(c->f, "add\n"); 59 | c->stack_size -= 1; 60 | } 61 | 62 | void packl_generate_sub(PACKL_Compiler *c, size_t indent) { 63 | fprint_indent(c->f, indent); 64 | fprintf(c->f, "sub\n"); 65 | c->stack_size -= 1; 66 | } 67 | 68 | void packl_generate_mul(PACKL_Compiler *c, size_t indent) { 69 | fprint_indent(c->f, indent); 70 | fprintf(c->f, "mul\n"); 71 | c->stack_size -= 1; 72 | } 73 | 74 | void packl_generate_div(PACKL_Compiler *c, size_t indent) { 75 | fprint_indent(c->f, indent); 76 | fprintf(c->f, "div\n"); 77 | c->stack_size -= 1; 78 | } 79 | 80 | void packl_generate_mod(PACKL_Compiler *c, size_t indent) { 81 | fprint_indent(c->f, indent); 82 | fprintf(c->f, "mod\n"); 83 | c->stack_size -= 1; 84 | } 85 | 86 | void packl_generate_cmpl(PACKL_Compiler *c, size_t indent) { 87 | fprint_indent(c->f, indent); 88 | fprintf(c->f, "cmpl\n"); 89 | c->stack_size -= 1; 90 | } 91 | 92 | void packl_generate_cmpg(PACKL_Compiler *c, size_t indent) { 93 | fprint_indent(c->f, indent); 94 | fprintf(c->f, "cmpg\n"); 95 | c->stack_size -= 1; 96 | } 97 | 98 | void packl_generate_cmpge(PACKL_Compiler *c, size_t indent) { 99 | fprint_indent(c->f, indent); 100 | fprintf(c->f, "cmpge\n"); 101 | c->stack_size -= 1; 102 | } 103 | 104 | void packl_generate_cmple(PACKL_Compiler *c, size_t indent) { 105 | fprint_indent(c->f, indent); 106 | fprintf(c->f, "cmple\n"); 107 | c->stack_size -= 1; 108 | } 109 | 110 | void packl_generate_cmpe(PACKL_Compiler *c, size_t indent) { 111 | fprint_indent(c->f, indent); 112 | fprintf(c->f, "cmpe\n"); 113 | c->stack_size -= 1; 114 | } 115 | 116 | void packl_generate_cmpne(PACKL_Compiler *c, size_t indent) { 117 | fprint_indent(c->f, indent); 118 | fprintf(c->f, "cmpne\n"); 119 | c->stack_size -= 1; 120 | } 121 | 122 | void packl_generate_swap(PACKL_Compiler *c, size_t indent) { 123 | fprint_indent(c->f, indent); 124 | fprintf(c->f, "swap\n"); 125 | } 126 | 127 | void packl_generate_dup(PACKL_Compiler *c, size_t indent) { 128 | fprint_indent(c->f, indent); 129 | fprintf(c->f, "dup\n"); 130 | c->stack_size++; 131 | } 132 | 133 | void packl_generate_inswap(PACKL_Compiler *c, int64_t value, size_t indent) { 134 | fprint_indent(c->f, indent); 135 | fprintf(c->f, "inswap %ld\n", value); 136 | } 137 | 138 | void packl_generate_indup(PACKL_Compiler *c, int64_t value, size_t indent) { 139 | fprint_indent(c->f, indent); 140 | fprintf(c->f, "indup %ld\n", value); 141 | c->stack_size++; 142 | } 143 | 144 | void packl_generate_syscall(PACKL_Compiler *c, int64_t value, size_t indent) { 145 | fprint_indent(c->f, indent); 146 | fprintf(c->f, "syscall %ld\n", value); 147 | c->stack_size -= number_of_popped_values[value]; 148 | } 149 | 150 | void packl_generate_writei(PACKL_Compiler *c, size_t indent) { 151 | fprint_indent(c->f, indent); 152 | fprintf(c->f, "writei\n"); 153 | c->stack_size -= 2; 154 | } 155 | 156 | void packl_generate_jmp(PACKL_Compiler *c, size_t value, size_t indent) { 157 | fprint_indent(c->f, indent); 158 | fprintf(c->f, "jmp $label_%zu\n", value); 159 | } 160 | 161 | void packl_generate_cmp(PACKL_Compiler *c, size_t indent) { 162 | fprint_indent(c->f, indent); 163 | fprintf(c->f, "cmp\n"); 164 | c->stack_size -= 1; 165 | } 166 | 167 | void packl_generate_jz(PACKL_Compiler *c, size_t value, size_t indent) { 168 | fprint_indent(c->f, indent); 169 | fprintf(c->f, "jz $label_%zu\n", value); 170 | c->stack_size--; 171 | } 172 | 173 | 174 | void packl_generate_jle(PACKL_Compiler *c, size_t value, size_t indent) { 175 | fprint_indent(c->f, indent); 176 | fprintf(c->f, "jle $label_%zu\n", value); 177 | c->stack_size--; 178 | } 179 | 180 | 181 | void packl_generate_jl(PACKL_Compiler *c, size_t value, size_t indent) { 182 | fprint_indent(c->f, indent); 183 | fprintf(c->f, "jl $label_%zu\n", value); 184 | c->stack_size--; 185 | } 186 | 187 | 188 | void packl_generate_jge(PACKL_Compiler *c, size_t value, size_t indent) { 189 | fprint_indent(c->f, indent); 190 | fprintf(c->f, "jge $label_%zu\n", value); 191 | c->stack_size--; 192 | } 193 | 194 | 195 | void packl_generate_jg(PACKL_Compiler *c, size_t value, size_t indent) { 196 | fprint_indent(c->f, indent); 197 | fprintf(c->f, "jg $label_%zu\n", value); 198 | c->stack_size--; 199 | } 200 | 201 | void packl_generate_putc(PACKL_Compiler *c, size_t indent) { 202 | fprint_indent(c->f, indent); 203 | fprintf(c->f, "putc\n"); 204 | c->stack_size--; // TODO: see if you can change this line, i think it's not correct 205 | } 206 | 207 | void packl_generate_call(PACKL_Compiler *c, size_t value, size_t indent) { 208 | fprint_indent(c->f, indent); 209 | fprintf(c->f, "call $label_%zu\n", value); 210 | } 211 | 212 | void packl_generate_ret(PACKL_Compiler *c, size_t indent) { 213 | fprint_indent(c->f, indent); 214 | fprintf(c->f, "ret\n"); 215 | } 216 | 217 | void packl_generate_store(PACKL_Compiler *c, size_t indent) { 218 | fprint_indent(c->f, indent); 219 | fprintf(c->f, "store\n"); 220 | c->stack_size -= 3; 221 | } 222 | 223 | void packl_generate_load(PACKL_Compiler *c, size_t indent) { 224 | fprint_indent(c->f, indent); 225 | fprintf(c->f, "load\n"); 226 | c->stack_size -= 1; 227 | } 228 | 229 | void packl_generate_readc(PACKL_Compiler *c, size_t indent) { 230 | fprint_indent(c->f, indent); 231 | fprintf(c->f, "readc\n"); 232 | c->stack_size++; 233 | } 234 | 235 | void packl_generate_loadb(PACKL_Compiler *c, size_t indent) { 236 | fprint_indent(c->f, indent); 237 | fprintf(c->f, "loadb\n"); 238 | } 239 | 240 | void packl_generate_storeb(PACKL_Compiler *c, size_t indent) { 241 | fprint_indent(c->f, indent); 242 | fprintf(c->f, "strb\n"); 243 | c->stack_size -= 2; 244 | } 245 | 246 | void packl_generate_ssp(PACKL_Compiler *c, size_t indent) { 247 | fprint_indent(c->f, indent); 248 | fprintf(c->f, "ssp\n"); 249 | c->stack_size -= 1; 250 | } 251 | 252 | void packl_generate_not(PACKL_Compiler *c, size_t indent) { 253 | fprint_indent(c->f, indent); 254 | fprintf(c->f, "not\n"); 255 | } 256 | 257 | void packl_generate_and(PACKL_Compiler *c, size_t indent) { 258 | fprint_indent(c->f, indent); 259 | fprintf(c->f, "and\n"); 260 | c->stack_size -= 1; 261 | } 262 | 263 | void packl_generate_or(PACKL_Compiler *c, size_t indent) { 264 | fprint_indent(c->f, indent); 265 | fprintf(c->f, "or\n"); 266 | c->stack_size -= 1; 267 | } 268 | 269 | void packl_generate_xor(PACKL_Compiler *c, size_t indent) { 270 | fprint_indent(c->f, indent); 271 | fprintf(c->f, "xor\n"); 272 | c->stack_size -= 1; 273 | } 274 | -------------------------------------------------------------------------------- /std/array.packl: -------------------------------------------------------------------------------- 1 | func sum(nums: array(int, 5)): int { 2 | sum = 0; 3 | for i: int in (0, 4) { 4 | sum = sum + nums[i]; 5 | } 6 | } 7 | -------------------------------------------------------------------------------- /std/io.packl: -------------------------------------------------------------------------------- 1 | proc writeln(s: str) { 2 | write(0, s); 3 | write(0, "\n"); 4 | } -------------------------------------------------------------------------------- /std/string.packl: -------------------------------------------------------------------------------- 1 | func len(s: str): int { 2 | var i: int = 0; 3 | 4 | while(s[i]) { 5 | i++; 6 | } 7 | 8 | len = i; 9 | } 10 | 11 | func sum(s: str): int { 12 | sum = 0; 13 | var i: int = 0; 14 | 15 | while (s[i]) { 16 | sum = sum + s[i++]; 17 | } 18 | } 19 | 20 | func toupper(s: str): str { 21 | var i: int = 0; 22 | var current: int = 0; 23 | 24 | while (s[i]) { 25 | current = s[i]; 26 | if (current > 96) { 27 | if (current < 97 + 26 + 1) { current = current - 97 + 65; } 28 | s[i] = current; 29 | } 30 | i++; 31 | } 32 | 33 | toupper = s; 34 | } 35 | -------------------------------------------------------------------------------- /tests/expression-as-arg.packl: -------------------------------------------------------------------------------- 1 | proc main() { 2 | exit(1 + 2 * 3 / 2 + 1); 3 | } -------------------------------------------------------------------------------- /tests/expression.packl: -------------------------------------------------------------------------------- 1 | proc main() { 2 | var number: int = 10 * 21 + 1; 3 | exit(1); 4 | } -------------------------------------------------------------------------------- /tests/nested-ifs.packl: -------------------------------------------------------------------------------- 1 | proc foo() { 2 | write("foo\n"); 3 | } 4 | 5 | proc bar() { 6 | write("bar\n"); 7 | } 8 | 9 | proc hello() { 10 | write("Hello"); 11 | } 12 | 13 | proc main() { 14 | if (1) { 15 | if (1) { 16 | if (1) { 17 | if (1) { 18 | hello(); 19 | } else if (1) { 20 | hello(); 21 | } else if (1) { 22 | hello(); 23 | } else { 24 | bar(); 25 | } 26 | } else { 27 | hello(); 28 | } 29 | } else if (1) { 30 | hello(); 31 | } 32 | } 33 | 34 | exit(20); 35 | } 36 | 37 | 38 | 39 | 40 | 41 | -------------------------------------------------------------------------------- /tests/parse.packl: -------------------------------------------------------------------------------- 1 | # function definition 2 | func f(a: int, b: str): int { 3 | f = a + b; 4 | } 5 | 6 | # variable declaration 7 | var v: int = 10; 8 | var s: str = "packl"; 9 | var a: array(int, 3) = {1, 2, 3}; 10 | 11 | # variable re-assignement 12 | v = 20; 13 | s = "PACKL"; 14 | # a = {2, 3, 1}; 15 | a[0] = 1; 16 | s[1] = "D"; 17 | 18 | # if condition 19 | if (((a == b) and (v <= 20)) or (x == 20)) { 20 | } else if (a < b) { 21 | } else { 22 | } 23 | 24 | # while loop 25 | while (a >= b) { 26 | } 27 | 28 | # for loop 29 | for i: int in (1, 10) { 30 | i = i + 1; 31 | } 32 | 33 | # use files 34 | use "file.packl" as file 35 | 36 | # procedure defintion 37 | proc p() { 38 | println("Hello World"); 39 | } 40 | 41 | proc main() { 42 | if (!(a == b)) { 43 | a++; 44 | a = ++b; 45 | } 46 | } -------------------------------------------------------------------------------- /tests/proc-call.packl: -------------------------------------------------------------------------------- 1 | proc bar() { 2 | var number: int = 20; 3 | exit(number); 4 | } 5 | 6 | proc foo() { 7 | var number: int = 10; 8 | bar(); 9 | } 10 | 11 | proc main() { 12 | foo(); 13 | } -------------------------------------------------------------------------------- /tests/proc-declaration.packl: -------------------------------------------------------------------------------- 1 | proc main() { 2 | exit(1); 3 | } -------------------------------------------------------------------------------- /tests/string.packl: -------------------------------------------------------------------------------- 1 | proc main() { 2 | var s: str = "string\n"; 3 | write(s); 4 | exit(0); 5 | } -------------------------------------------------------------------------------- /tests/tokens.packl: -------------------------------------------------------------------------------- 1 | identifier 2 | 3 | write exit 4 | 5 | "packl" 10 6 | 7 | ; : , 8 | 9 | [ ] ( ) { } 10 | 11 | = 12 | 13 | + ++ - -- * / % 14 | 15 | == < > <= >= ! != 16 | 17 | proc func return var if else while for in use as 18 | 19 | or and xor 20 | 21 | array int str 22 | 23 | class 24 | 25 | new sizeof -------------------------------------------------------------------------------- /tests/variable-declaration.packl: -------------------------------------------------------------------------------- 1 | proc main() { 2 | var variable: int = 1; 3 | exit(variable); 4 | } -------------------------------------------------------------------------------- /tools/arena.c: -------------------------------------------------------------------------------- 1 | #include "arena.h" 2 | 3 | Region *region_init(size_t size) { 4 | Region *region = (Region *)malloc(sizeof(Region)); 5 | if(!region) { THROW_ERROR("could not allocate memory for the arena region\n"); } 6 | 7 | region->count = 0; 8 | region->size = MAX(REGION_MIN_SIZE, size); 9 | region->next = NULL; 10 | region->items = (char *)malloc(sizeof(char) * region->size); 11 | 12 | if (!region->items) { THROW_ERROR("could not allocate memory for the arena region\n"); } 13 | 14 | return region; 15 | } 16 | 17 | Arena arena_init(size_t size) { 18 | Arena arena = {0}; 19 | arena.head = region_init(size); 20 | arena.end = arena.head; 21 | return arena; 22 | } 23 | 24 | 25 | void arena_add_region(Arena *self, size_t size) { 26 | Region *current = self->head; 27 | 28 | while (current->next) { 29 | current = current->next; 30 | } 31 | 32 | current->next = region_init(size); 33 | 34 | self->end = current->next; 35 | } 36 | 37 | 38 | void *arena_alloc(Arena *self, size_t item_size) { 39 | Region *current = self->head; 40 | 41 | while(current) { 42 | if (current->count + item_size <= current->size) { break; } 43 | current = current->next; 44 | } 45 | 46 | if (!current) { arena_add_region(self, item_size); current = self->end; } 47 | 48 | void *ptr = ¤t->items[current->count]; 49 | current->count += item_size; 50 | 51 | return ptr; 52 | } 53 | 54 | void arena_reset(Arena *self) { 55 | Region *current = self->head; 56 | while (current) { 57 | current->count = 0; 58 | current = current->next; 59 | } 60 | } 61 | 62 | void arena_free(Arena *self) { 63 | Region *current = self->head; 64 | while (current) { 65 | Region *next = current->next; 66 | free(current->items); 67 | free(current); 68 | current = next; 69 | } 70 | self->head = NULL; 71 | self->end = NULL; 72 | } 73 | 74 | void arena_show(Arena self) { 75 | Region *current = self.head; 76 | while (current) { 77 | printf("(count) = %zu, (size) = %zu\n", current->count, current->size); 78 | current = current->next; 79 | } 80 | } 81 | -------------------------------------------------------------------------------- /tools/arena.h: -------------------------------------------------------------------------------- 1 | #ifndef ARENA_H 2 | #define ARENA_H 3 | 4 | #include 5 | #include 6 | #include "error.h" 7 | 8 | #define REGION_MIN_SIZE 1000 9 | #define ARENA_INIT_DEFAULT() arena_init(0) 10 | #define MAX(a, b) ((a) > (b) ? (a) : (b)) 11 | 12 | typedef struct Region Region; 13 | typedef struct Arena Arena; 14 | 15 | struct Region { 16 | char *items; 17 | size_t count; 18 | size_t size; 19 | Region *next; 20 | }; 21 | 22 | struct Arena { 23 | Region *head; 24 | Region *end; 25 | }; 26 | 27 | Region *region_init(size_t size); 28 | Arena arena_init(size_t size); 29 | void arena_add_region(Arena *self, size_t size); 30 | void *arena_alloc(Arena *self, size_t item_size); 31 | void arena_reset(Arena *self); 32 | void arena_free(Arena *self); 33 | void arena_show(Arena self); 34 | 35 | #endif // ARENA_H 36 | -------------------------------------------------------------------------------- /tools/dyn-arr.h: -------------------------------------------------------------------------------- 1 | #ifndef DYN_ARR_H 2 | #define DYN_ARR_H 3 | 4 | #include 5 | #include 6 | #include "error.h" 7 | 8 | /* 9 | Each struct should be defined in that way 10 | 11 | struct Dynamic_Array_Structure { 12 | Dynamic_Array_Type *items; 13 | size_t count; 14 | size_t size; 15 | } 16 | 17 | */ 18 | 19 | #define DA_INIT(arr, item_size) \ 20 | do { \ 21 | (arr)->size = 1; \ 22 | (arr)->count = 0; \ 23 | (arr)->items = malloc(item_size); \ 24 | if (!((arr)->items)) THROW_ERROR("Could not allocate memory"); \ 25 | } while(0) 26 | 27 | #define DA_RESIZE(arr) \ 28 | do { \ 29 | (arr)->size *= 2; \ 30 | (arr)->items = realloc((arr)->items, (arr)->size * sizeof((arr)->items[0])); \ 31 | if (!((arr)->items)) THROW_ERROR("Could not allocate memory"); \ 32 | } while(0) 33 | 34 | #define DA_FULL(arr) ((arr)->count >= (arr)->size) 35 | 36 | #define DA_APPEND(arr, item) \ 37 | do { \ 38 | if (DA_FULL(arr)) DA_RESIZE(arr); \ 39 | (arr)->items[(arr)->count++] = item; \ 40 | } while(0) 41 | 42 | #define DA_REMOVE(arr) free((arr)->items) 43 | 44 | #endif // DYN_ARR_H 45 | -------------------------------------------------------------------------------- /tools/error.h: -------------------------------------------------------------------------------- 1 | #ifndef ERROR_H 2 | #define ERROR_H 3 | 4 | #define ForeGround_Black "\033[30m" 5 | #define ForeGround_Red "\033[31m" 6 | #define ForeGround_Green "\033[32m" 7 | #define ForeGround_Yellow "\033[33m" 8 | #define ForeGround_Blue "\033[34m" 9 | #define ForeGround_Magenta "\033[35m" 10 | #define ForeGround_Cyan "\033[36m" 11 | #define ForeGround_White "\033[37m" 12 | #define ForeGround_Reset "\033[0m" 13 | 14 | #define BackGround_Black "\033[40m" 15 | #define BackGround_Red "\033[40m" 16 | #define BackGround_Green "\033[40m" 17 | #define BackGround_Yellow "\033[40m" 18 | #define BackGround_Blue "\033[40m" 19 | #define BackGround_Magenta "\033[40m" 20 | #define BackGround_Cyan "\033[40m" 21 | #define BackGround_White "\033[40m" 22 | #define BackGround_Reset "\033[49m" 23 | 24 | 25 | #define ERROR ForeGround_Red "[ERROR] " ForeGround_Reset 26 | #define INFO ForeGround_Yellow "[INFO] " ForeGround_Reset 27 | #define ASRT ForeGround_Cyan "[ASSERT] " ForeGround_Reset 28 | #define TD BackGround_Red ForeGround_White "[TODO]" ForeGround_Reset BackGround_Reset " " 29 | 30 | #define THROW_ERROR(...) \ 31 | do { \ 32 | fprintf(stderr, ERROR); \ 33 | fprintf(stderr, __VA_ARGS__); \ 34 | fprintf(stderr, "\n"); \ 35 | exit(EXIT_FAILURE); \ 36 | } while(0) 37 | 38 | #define LOG_INFO(...) \ 39 | do { \ 40 | printf(INFO __VA_ARGS__); \ 41 | printf("\n"); \ 42 | } while(0) 43 | 44 | #define ASSERT(condition, ...) \ 45 | do { \ 46 | if (condition) { break; } \ 47 | fprintf(stderr, "%s:%d: ", __FILE__, __LINE__); \ 48 | fprintf(stderr, ASRT); \ 49 | fprintf(stderr, __VA_ARGS__); \ 50 | fprintf(stderr, "\n"); \ 51 | exit(EXIT_FAILURE); \ 52 | } while(0) 53 | 54 | #define TODO(...) \ 55 | do { \ 56 | fprintf(stdout, "%s:%d: ", __FILE__, __LINE__); \ 57 | fprintf(stdout, TD); \ 58 | fprintf(stdout, __VA_ARGS__); \ 59 | fprintf(stdout, "\n"); \ 60 | exit(EXIT_FAILURE); \ 61 | } while(0) 62 | 63 | #endif // ERROR_H -------------------------------------------------------------------------------- /tools/hashmap.c: -------------------------------------------------------------------------------- 1 | #include "hashmap.h" 2 | 3 | HashMap_Node *hashnode_init(char *key, size_t item_size, void *value) { 4 | HashMap_Node *node = (HashMap_Node *) malloc(sizeof(HashMap_Node)); 5 | if (!node) { return NULL; } 6 | 7 | if (!value) { node->value = NULL; } 8 | else { 9 | node->value = malloc(item_size); 10 | if (!node->value) { free(node); return NULL; } 11 | } 12 | 13 | size_t key_length = strlen(key); 14 | node->key = (char *)malloc(sizeof(char) * (key_length + 1)); 15 | if (!node->key) { free(node->value); free(node); return NULL; } 16 | 17 | if (node->value) { memcpy(node->value, value, item_size); } 18 | 19 | memcpy(node->key, key, key_length); 20 | node->key[key_length] = 0; 21 | 22 | node->prev = NULL; 23 | node->next = NULL; 24 | 25 | return node; 26 | } 27 | 28 | void hashnode_destroy(HashMap_Node *node) { 29 | if (!node) return; 30 | if (node->key) { free(node->key); } 31 | if (node->value) { free(node->value); } 32 | free(node); 33 | } 34 | 35 | 36 | void hashmap_init(HashMap *self, size_t item_size) { 37 | self->item_size = item_size; 38 | for (size_t i = 0; i < HASH_MAP_SIZE; ++i) { 39 | self->nodes[i] = NULL; 40 | } 41 | } 42 | 43 | void hashmap_destroy(HashMap *self) { 44 | for (size_t i = 0; i < HASH_MAP_SIZE; ++i) { 45 | HashMap_Node *current = self->nodes[i]; 46 | while (current) { 47 | HashMap_Node *next = current->next; 48 | hashnode_destroy(current); 49 | current = next; 50 | } 51 | } 52 | } 53 | 54 | size_t hash(char *key) { 55 | if (!key) { THROW_ERROR("ERROR: `hash` function failed, key == NULL passed to the function\n"); } 56 | size_t result = 0; 57 | for (char c = *key; c != '\0'; ++key) { 58 | c = *key; 59 | result += c; 60 | } 61 | return result % HASH_MAP_SIZE; 62 | } 63 | 64 | HashMap_Node *hashmap_get_node(HashMap *self, char *key) { 65 | size_t index = hash(key); 66 | HashMap_Node *current = self->nodes[index]; 67 | while (current) { 68 | if (strcmp(current->key, key) == 0) { return current; } 69 | current = current->next; 70 | } 71 | return NULL; 72 | } 73 | 74 | int hashmap_get(HashMap *self, char *key, void *value) { 75 | HashMap_Node *node = hashmap_get_node(self, key); 76 | if (!node) { return 0; } 77 | if (!value) { return 1; } // found it 78 | if (!node->value) { return 0; } 79 | memcpy(value, node->value, self->item_size); 80 | return 1; 81 | } 82 | 83 | int hashmap_find(HashMap *self, char *key) { 84 | return (hashmap_get_node(self, key) != NULL); 85 | } 86 | 87 | int hashmap_add(HashMap *self, char *key, void *value) { 88 | if (hashmap_find(self, key)) { return 0; } 89 | 90 | HashMap_Node *node = hashnode_init(key, self->item_size, value); 91 | if (!node) { return 0; } 92 | 93 | size_t index = hash(key); 94 | node->next = self->nodes[index]; 95 | 96 | if (self->nodes[index]) self->nodes[index]->prev = node; 97 | 98 | self->nodes[index] = node; 99 | return 1; 100 | } 101 | 102 | int hashmap_remove(HashMap *self, char *key) { 103 | HashMap_Node *node = hashmap_get_node(self, key); 104 | if (!node) { return 0; } 105 | 106 | size_t index = hash(key); 107 | HashMap_Node *prev = node->prev; 108 | HashMap_Node *next = node->next; 109 | 110 | if (prev) { prev->next = next; } 111 | else { self->nodes[index] = next; } 112 | 113 | if (next) { next->prev = prev; } 114 | 115 | hashnode_destroy(node); 116 | 117 | return 1; 118 | } 119 | 120 | int hashmap_update(HashMap *self, char *key, void *value) { 121 | HashMap_Node *node = hashmap_get_node(self, key); 122 | if (!node) { return 0; } 123 | if (!value) { node->value = NULL; return 1; } 124 | memcpy(node->value, value, self->item_size); 125 | return 1; 126 | } 127 | 128 | int hashmap_empty(HashMap *self) { 129 | for (size_t i = 0; i < HASH_MAP_SIZE; ++i) { 130 | if (self->nodes[i]) { return 0; } 131 | } 132 | return 1; 133 | } -------------------------------------------------------------------------------- /tools/hashmap.h: -------------------------------------------------------------------------------- 1 | #ifndef HASHMAP_H 2 | #define HASHMAP_H 3 | 4 | #include 5 | #include 6 | #include 7 | #include "error.h" 8 | 9 | #define HASH_MAP_SIZE 20 10 | 11 | typedef struct HashMap HashMap; 12 | typedef struct HashMap_Node HashMap_Node; 13 | 14 | struct HashMap_Node { 15 | char *key; 16 | void *value; 17 | HashMap_Node *prev, *next; 18 | }; 19 | 20 | struct HashMap { 21 | HashMap_Node *nodes[HASH_MAP_SIZE]; 22 | size_t item_size; 23 | }; 24 | 25 | void hashmap_init(HashMap *self, size_t item_size); 26 | void hashmap_destroy(HashMap *self); 27 | int hashmap_get(HashMap *self, char *key, void *value); 28 | int hashmap_find(HashMap *self, char *key); 29 | int hashmap_add(HashMap *self, char *key, void *value); 30 | int hashmap_remove(HashMap *self, char *key); 31 | int hashmap_update(HashMap *self, char *key, void *value); 32 | int hashmap_empty(HashMap *self); 33 | 34 | #endif -------------------------------------------------------------------------------- /tools/sv.c: -------------------------------------------------------------------------------- 1 | #include "sv.h" 2 | 3 | String_View sv_from_cstr(char *s) { 4 | String_View sv = {0}; 5 | sv.content = s; 6 | if (s) sv.count = strlen(s); 7 | return sv; 8 | } 9 | 10 | char *cstr_from_sv(String_View s) { 11 | if (!(s.content && s.count)) { return NULL; } 12 | char *content = (char *)malloc(sizeof(char) * (s.count + 1)); 13 | if (!content) THROW_ERROR("`cstr_from_sv` failed, Couldn't allocate memory for the string\n"); 14 | memcpy(content, s.content, s.count * sizeof(char)); 15 | content[s.count] = '\0'; 16 | return content; 17 | } 18 | 19 | String_View sv_from_file(char *filename) { 20 | if (!filename) THROW_ERROR("file name not provided\n"); 21 | 22 | FILE *f = fopen(filename, "r"); 23 | if (!f) THROW_ERROR("could not open the file %s\n", filename); 24 | 25 | fseek(f, 0, SEEK_END); 26 | size_t fsize = ftell(f); 27 | fseek(f, 0, SEEK_SET); 28 | 29 | char *fcontent = (char *)malloc(sizeof(char) * (fsize + 1)); 30 | fread(fcontent, sizeof(char), fsize, f); 31 | 32 | fcontent[fsize] = '\0'; 33 | 34 | fclose(f); 35 | 36 | return sv_from_cstr(fcontent); 37 | } 38 | 39 | String_View sv_trim_left(String_View s) { 40 | while (s.count) { 41 | if (isspace(*s.content)) { s.content++; s.count--; } 42 | else { break; } 43 | } 44 | 45 | return s; 46 | } 47 | 48 | String_View sv_trim_right(String_View s) { 49 | while (s.count) { 50 | if (isspace(*(s.content + s.count - 1))) { s.count--; } 51 | else { break; } 52 | } 53 | return s; 54 | } 55 | 56 | String_View sv_trim(String_View s) { 57 | return sv_trim_right(sv_trim_left(s)); 58 | } 59 | 60 | int sv_eq(String_View s, String_View t) { 61 | if (s.count != t.count) { return 0; } 62 | return memcmp(s.content, t.content, s.count) == 0; 63 | } 64 | 65 | String_View sv_from_char(char c) { 66 | char *s = (char *)malloc(sizeof(char)); 67 | *s = c; 68 | return SV_GET(s, 1); 69 | } 70 | 71 | bool sv_empty(String_View s) { 72 | return (s.count == 0 || !s.content); 73 | } 74 | 75 | char is_after_escape(char ch) { 76 | switch (ch) { 77 | case 'a': 78 | return '\a'; 79 | case 'b': 80 | return '\b'; 81 | case 'f': 82 | return '\f'; 83 | case 'n': 84 | return '\n'; 85 | case 'r': 86 | return '\r'; 87 | case 't': 88 | return '\t'; 89 | case 'v': 90 | return '\v'; 91 | case '\\': 92 | return '\\'; 93 | case '\'': 94 | return '\''; 95 | case '"': 96 | return '\"'; 97 | case '?': 98 | return '\?'; 99 | case '0': 100 | return '\0'; 101 | default: 102 | return 0; 103 | } 104 | } 105 | 106 | bool is_escape_character(char ch) { 107 | switch (ch) { 108 | case '\a': 109 | case '\b': 110 | case '\f': 111 | case '\n': 112 | case '\r': 113 | case '\t': 114 | case '\v': 115 | case '\\': 116 | case '\'': 117 | case '\"': 118 | case '\?': 119 | case '\0': 120 | return true; 121 | default: 122 | return false; 123 | } 124 | } 125 | 126 | char escape_to_char(char ch) { 127 | switch (ch) { 128 | case '\a': 129 | return 'a'; 130 | case '\b': 131 | return 'b'; 132 | case '\f': 133 | return 'f'; 134 | case '\n': 135 | return 'n'; 136 | case '\r': 137 | return 'r'; 138 | case '\t': 139 | return 't'; 140 | case '\v': 141 | return 'v'; 142 | case '\\': 143 | return '\\'; 144 | case '\'': 145 | return '\''; 146 | case '\"': 147 | return '"'; 148 | case '\?': 149 | return '?'; 150 | case '\0': 151 | return '0'; 152 | default: 153 | ASSERT(false, "unreachable"); 154 | } 155 | } 156 | 157 | char *unescape_string(char *s, size_t s_size) { 158 | char result[1024]; 159 | size_t size = 0; 160 | 161 | for (size_t i = 0; i < s_size; ++i) { 162 | if (is_escape_character(s[i])) { 163 | result[size++] = '\\'; 164 | result[size++] = escape_to_char(s[i]); 165 | } else { result[size++] = s[i]; } 166 | } 167 | 168 | char *content = malloc(sizeof(char) *(size + 1)); 169 | memcpy(content, result, size); 170 | content[size] = 0; 171 | 172 | return content; 173 | } 174 | 175 | String_View unescape_string_to_sv(String_View s) { 176 | char *string = unescape_string(s.content, s.count); 177 | return SV(string); 178 | } 179 | 180 | char *sv_escape(String_View s) { 181 | char result[1024]; 182 | size_t size = 0; 183 | size_t i = 0; 184 | 185 | while (i < s.count) { 186 | if (sv_at(s, i) == '\\') { 187 | char c = sv_at(s, i + 1); 188 | 189 | if (c == EOF) { result[size++] = sv_at(s, i); break; } 190 | 191 | if ((c = is_after_escape(c)) != 0) { 192 | result[size++] = c; 193 | i++; 194 | } else { 195 | result[size++] = sv_at(s, i); 196 | } 197 | } else { result[size++] = sv_at(s, i); } 198 | i++; 199 | } 200 | 201 | char *content = malloc(sizeof(char) * (size + 1)); 202 | memcpy(content, result, size); 203 | content[size] = 0; 204 | return content; 205 | } 206 | 207 | char sv_at(String_View s, size_t index) { 208 | if (index >= s.count) { return EOF; } 209 | return s.content[index]; 210 | } 211 | 212 | int64_t sv_find_index(String_View s, char c) { 213 | for (size_t i = 0; i < s.count; ++i) { 214 | if (s.content[i] == c) { return i; } 215 | } 216 | return -1; 217 | } 218 | 219 | size_t sv_count_char(String_View s, char c) { 220 | size_t result = 0; 221 | for(size_t i = 0; i < s.count; ++i) { 222 | if (sv_at(s, i) == c) { result++; } 223 | } 224 | return result; 225 | } 226 | 227 | bool sv_starts_with(String_View s, char c) { 228 | if (sv_empty(s)) return false; 229 | return (s.content[0] == c); 230 | } 231 | 232 | bool sv_ends_with(String_View s, String_View t) { 233 | if (sv_empty(t)) { return true; } 234 | if (s.count < t.count) { return false; } 235 | 236 | String_View view = SV_GET(s.content + s.count - t.count, t.count); 237 | return sv_eq(view, t); 238 | } 239 | 240 | String_View sv_chop_left(String_View s) { 241 | if (sv_empty(s)) { return SV_NULL; } 242 | return SV_GET(s.content + 1, s.count - 1); 243 | } 244 | 245 | String_View sv_chop_right(String_View s) { 246 | if (sv_empty(s)) { return SV_NULL; } 247 | return SV_GET(s.content, s.count - 1); 248 | } 249 | 250 | String_View sv_chop_both(String_View s) { 251 | return sv_chop_left(sv_chop_right(s)); 252 | } 253 | 254 | String_View sv_get_before(String_View s, size_t index) { 255 | if(sv_empty(s) || index >= s.count) { return SV_NULL; } 256 | return SV_GET(s.content, index); 257 | } 258 | 259 | String_View sv_get_after(String_View s, size_t index) { 260 | if(sv_empty(s) || index >= s.count) { return SV_NULL; } 261 | 262 | return SV_GET(s.content + index + 1, s.count - index - 1); 263 | } 264 | 265 | bool sv_is_unsigned(String_View s) { 266 | if(sv_empty(s)) { return false; } 267 | for (size_t i = 0; i < s.count; ++i) { 268 | if (!isdigit(sv_at(s, i))) { return false; } 269 | } 270 | return true; 271 | } 272 | 273 | bool sv_is_integer(String_View s) { 274 | if (sv_empty(s)) return false; 275 | 276 | size_t i = 0; 277 | if (sv_starts_with(s, '-')) { ++i; } 278 | 279 | String_View abs = SV_GET(s.content + i, s.count - i); 280 | 281 | return sv_is_unsigned(abs); 282 | } 283 | 284 | bool sv_is_float(String_View s) { 285 | if (sv_empty(s)) return false; 286 | 287 | if (sv_count_char(s, '.') > 1) { return false; } 288 | 289 | int64_t index = sv_find_index(s, '.'); 290 | 291 | if (index == -1) { return sv_is_integer(s); } 292 | 293 | String_View before_point = sv_get_before(s, index); 294 | String_View after_point = sv_get_after(s, index); 295 | 296 | return sv_is_integer(before_point) && sv_is_unsigned(after_point); 297 | } 298 | 299 | uint64_t sv_parse_uint(String_View s) { 300 | uint64_t result = 0; 301 | for (size_t i = 0; i < s.count; ++i) { 302 | result *= 10; 303 | result += sv_at(s, i) - '0'; 304 | } 305 | return result; 306 | } 307 | 308 | bool sv_parse_integer(String_View s, int64_t *result) { 309 | if (!sv_is_integer(s)) { return true; } 310 | 311 | String_View abs = s; 312 | if (sv_starts_with(s, '-')) { abs = sv_get_after(s, 0); } 313 | 314 | uint64_t unsigned_int = sv_parse_uint(abs); 315 | 316 | *result = (int64_t) unsigned_int; 317 | 318 | if (sv_starts_with(s, '-')) { *result = -(*result); } 319 | return true; 320 | } 321 | 322 | /* Helper function */ 323 | double get_float(bool is_signed, uint64_t int_part, uint64_t float_part, size_t precision) { 324 | uint64_t power = 1; 325 | for (size_t i = 0; i < precision; ++i) { 326 | power *= 10; 327 | } 328 | 329 | double float_part_to_double = (double)float_part / power; 330 | double abs = (double)int_part + float_part_to_double; 331 | 332 | if (!is_signed) { return abs; } 333 | return -abs; 334 | } 335 | 336 | bool sv_parse_float(String_View s, double *result) { 337 | if (!sv_is_float(s)) { return false; } 338 | 339 | String_View abs = s; 340 | if (sv_starts_with(s, '-')) { abs = sv_get_after(s, 0); } 341 | 342 | int64_t index = sv_find_index(abs, '.'); 343 | 344 | if (index < 0) { 345 | *result = (double)sv_parse_uint(abs); 346 | if (sv_starts_with(s, '-')) { *result = -(*result); } 347 | return true; 348 | } 349 | 350 | String_View before_point = sv_get_before(abs, index); 351 | String_View after_point = sv_get_after(abs, index); 352 | 353 | uint64_t unsigned_before = sv_parse_uint(before_point); 354 | uint64_t unsigned_after = sv_parse_uint(after_point); 355 | 356 | 357 | 358 | *result = get_float(sv_starts_with(s, '-'), unsigned_before, unsigned_after, after_point.count); 359 | 360 | return true; 361 | } 362 | 363 | String_Slices sv_split_by_delim(String_View s, int (*compare)(int)) { 364 | String_Slices slices; 365 | DA_INIT(&slices, sizeof(String_View)); 366 | 367 | size_t begin = 0; 368 | size_t size = 0; 369 | 370 | String_View slice = SV_NULL; 371 | 372 | for (size_t i = 0; i < s.count; ++i) { 373 | if (compare(sv_at(s, i))) { 374 | if (size != 0) { 375 | slice = SV_GET(s.content + begin, size); 376 | begin += size + 1; 377 | size = 0; 378 | DA_APPEND(&slices, slice); 379 | } else { 380 | begin += 1; 381 | } 382 | } else { size++; } 383 | } 384 | 385 | if (size != 0) { 386 | slice = SV_GET(s.content + begin, size); 387 | DA_APPEND(&slices, slice); 388 | } 389 | 390 | return slices; 391 | } 392 | 393 | int isnewline(int c) { 394 | return c == '\n'; 395 | } 396 | 397 | String_Slices sv_get_lines(String_View s) { 398 | return sv_split_by_delim(s, isnewline); 399 | } 400 | 401 | String_Slices sv_split(String_View s) { 402 | return sv_split_by_delim(s, isspace); 403 | } 404 | 405 | int64_t integer_from_sv(String_View s) { 406 | int64_t number = 0; 407 | sv_parse_integer(s, &number); 408 | return number; 409 | } -------------------------------------------------------------------------------- /tools/sv.h: -------------------------------------------------------------------------------- 1 | #ifndef STRING_VIEW_H 2 | #define STRING_VIEW_H 3 | 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | #include 11 | #include "error.h" 12 | #include "dyn-arr.h" 13 | 14 | #define SV(s) sv_from_cstr(s) 15 | #define SV_GET(b, s) (String_View) { .content = b, .count = s } 16 | #define SV_FROM_CHAR(c) sv_from_char(c) 17 | #define SV_NULL (String_View) { .content = NULL, .count = 0 } 18 | 19 | #define SV_FMT "%.*s" 20 | #define SV_UNWRAP(s) (int)s.count, s.content 21 | 22 | typedef struct String_View String_View; 23 | 24 | struct String_View { 25 | char *content; 26 | size_t count; 27 | }; 28 | 29 | typedef struct String_Slices String_Slices; 30 | 31 | struct String_Slices { 32 | String_View *items; 33 | size_t count; 34 | size_t size; 35 | }; 36 | 37 | String_View sv_from_cstr(char *s); 38 | char *cstr_from_sv(String_View s); 39 | String_View sv_from_file(char *filename); 40 | String_View sv_trim_left(String_View s); 41 | String_View sv_trim_right(String_View s); 42 | String_View sv_trim(String_View s); 43 | int sv_eq(String_View s, String_View t); 44 | String_View sv_from_char(char c); 45 | bool sv_empty(String_View s); 46 | char sv_at(String_View s, size_t index); 47 | int64_t sv_find_index(String_View s, char c); 48 | size_t sv_count_char(String_View s, char c); 49 | bool sv_starts_with(String_View s, char c); 50 | bool sv_ends_with(String_View s, String_View t); 51 | bool sv_is_integer(String_View s); 52 | bool sv_is_float(String_View s); 53 | bool sv_parse_integer(String_View s, int64_t *result); 54 | bool sv_parse_float(String_View s, double *result); 55 | String_Slices sv_split_by_delim(String_View s, int (*compare)(int)); 56 | String_Slices sv_get_lines(String_View s); 57 | String_Slices sv_split(String_View s); 58 | String_View sv_chop_left(String_View s); 59 | String_View sv_chop_right(String_View s); 60 | String_View sv_chop_both(String_View s); 61 | char *unescape_string(char *s, size_t s_size); 62 | String_View unescape_string_to_sv(String_View s); 63 | char *sv_escape(String_View s); 64 | int64_t integer_from_sv(String_View s); 65 | 66 | #endif // STRING_VIEW_H -------------------------------------------------------------------------------- /tools/vector.h: -------------------------------------------------------------------------------- 1 | #ifndef VECTOR_H 2 | #define VECTOR_H 3 | 4 | #include 5 | #include 6 | #include 7 | #include 8 | 9 | /* 10 | THE VECTOR STRUCTURE 11 | { 12 | void *header; 13 | void *items; 14 | } 15 | */ 16 | 17 | #define VECTOR(T) T* 18 | #define VECTOR_PUSH(v, i) vector_push((void **)&(v), sizeof(i), (void *)&(i)) 19 | #define VECTOR_RESET(v) vector_reset((void **)&(v)) 20 | #define VECTOR_REMOVE(v) vector_remove((void **)&(v)) 21 | 22 | #define VECTOR_INITIAL_SIZE 100 23 | 24 | typedef struct Vector_Header Vector_Header; 25 | 26 | struct Vector_Header { 27 | size_t count; 28 | size_t size; 29 | }; 30 | 31 | Vector_Header *vect_header_init() { 32 | Vector_Header *header = (Vector_Header *)malloc(sizeof(*header)); 33 | assert(header != NULL && "ERROR: `vect_header_init` failed to allocate memory\n"); 34 | header->count = 0; 35 | header->size = VECTOR_INITIAL_SIZE; 36 | return header; 37 | } 38 | 39 | void **vector_init() { 40 | void **vector = (void **)malloc(2 * sizeof(void *)); 41 | assert(vector != NULL && "ERROR: `vector_init` failed\n"); 42 | return vector; 43 | } 44 | 45 | Vector_Header *vector_get_header(void **vect) { 46 | assert(*vect != NULL && "ERROR: `vector_get_header` failed, cannot get the header of a NULL ptr\n"); 47 | Vector_Header *header = (Vector_Header *)(*vect - 1); 48 | return header; 49 | } 50 | 51 | void vector_resize(void **vect, size_t item_size) { 52 | Vector_Header *header = vector_get_header(vect); 53 | header->size *= 2; 54 | *vect = realloc(*vect, header->size * item_size); 55 | assert(*vect != NULL && "ERROR: `vector_resize` failed\n"); 56 | } 57 | 58 | void vector_push(void **vect, size_t item_size, void *item) { 59 | void **structure = 0; 60 | 61 | if (!*vect) { 62 | structure = vector_init(); 63 | 64 | // SET THE HEADER 65 | structure[0] = (void *)vect_header_init(); 66 | 67 | // SET THE ARRAY 68 | structure[1] = malloc(VECTOR_INITIAL_SIZE * item_size); 69 | assert(structure[1] != NULL && "ERROR: `vector_push` failed\n"); 70 | 71 | // UPDATE THE ARRAY POINTER 72 | *vect = structure[1]; 73 | } else { 74 | Vector_Header *header = vector_get_header(vect); 75 | if(header->count >= header->size) { vector_resize(vect, item_size); } 76 | } 77 | 78 | memcpy(*vect + header->count * item_size, item, item_size); 79 | header->count++; 80 | } 81 | 82 | void vector_reset(void **vect) { 83 | assert(*vect && "ERROR: `vector_reset` failed\n"); 84 | Vector_Header *header = vector_get_header(vect); 85 | header->count = 0; 86 | } 87 | 88 | void vector_remove(void **vect) { 89 | assert(*vect && "ERROR: `vector_remove` failed\n"); 90 | Vector_Header *header = vector_get_header(vect); 91 | void *items = *vect; 92 | free(header); 93 | free(items); 94 | } 95 | 96 | 97 | #endif // VECTOR_H --------------------------------------------------------------------------------