5 * Permission is hereby granted, free of charge, to any person obtaining a copy of
6 * this software and associated documentation files (the "Software"), to deal in
7 * the Software without restriction, including without limitation the rights to
8 * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
9 * of the Software, and to permit persons to whom the Software is furnished to do
10 * so, subject to the following conditions:
12 * The above copyright notice and this permission notice shall be included in all
13 * copies or substantial portions of the Software.
15 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
25 * This is the assembler, gmqas, this is being implemented because I'm
26 * not exactly sure how codegen would work for the C compiler as of yet
27 * and also I plan to allow inline assembly for the compiler.
30 const char *m; /* menomic */
31 const size_t o; /* operands */
32 const size_t l; /* menomic len */
33 } const asm_instr[] = {
34 [INSTR_DONE] = { "DONE" , 1, 4 },
35 [INSTR_MUL_F] = { "MUL_F" , 3, 5 },
36 [INSTR_MUL_V] = { "MUL_V" , 3, 5 },
37 [INSTR_MUL_FV] = { "MUL_FV" , 3, 6 },
38 [INSTR_MUL_VF] = { "MUL_VF" , 3, 6 },
39 [INSTR_DIV_F] = { "DIV" , 0, 3 },
40 [INSTR_ADD_F] = { "ADD_F" , 3, 5 },
41 [INSTR_ADD_V] = { "ADD_V" , 3, 5 },
42 [INSTR_SUB_F] = { "SUB_F" , 3, 5 },
43 [INSTR_SUB_V] = { "DUB_V" , 3, 5 },
44 [INSTR_EQ_F] = { "EQ_F" , 0, 4 },
45 [INSTR_EQ_V] = { "EQ_V" , 0, 4 },
46 [INSTR_EQ_S] = { "EQ_S" , 0, 4 },
47 [INSTR_EQ_E] = { "EQ_E" , 0, 4 },
48 [INSTR_EQ_FNC] = { "ES_FNC" , 0, 6 },
49 [INSTR_NE_F] = { "NE_F" , 0, 4 },
50 [INSTR_NE_V] = { "NE_V" , 0, 4 },
51 [INSTR_NE_S] = { "NE_S" , 0, 4 },
52 [INSTR_NE_E] = { "NE_E" , 0, 4 },
53 [INSTR_NE_FNC] = { "NE_FNC" , 0, 6 },
54 [INSTR_LE] = { "LE" , 0, 2 },
55 [INSTR_GE] = { "GE" , 0, 2 },
56 [INSTR_LT] = { "LT" , 0, 2 },
57 [INSTR_GT] = { "GT" , 0, 2 },
58 [INSTR_LOAD_F] = { "FIELD_F" , 0, 7 },
59 [INSTR_LOAD_V] = { "FIELD_V" , 0, 7 },
60 [INSTR_LOAD_S] = { "FIELD_S" , 0, 7 },
61 [INSTR_LOAD_ENT] = { "FIELD_ENT" , 0, 9 },
62 [INSTR_LOAD_FLD] = { "FIELD_FLD" , 0, 9 },
63 [INSTR_LOAD_FNC] = { "FIELD_FNC" , 0, 9 },
64 [INSTR_ADDRESS] = { "ADDRESS" , 0, 7 },
65 [INSTR_STORE_F] = { "STORE_F" , 0, 7 },
66 [INSTR_STORE_V] = { "STORE_V" , 0, 7 },
67 [INSTR_STORE_S] = { "STORE_S" , 0, 7 },
68 [INSTR_STORE_ENT] = { "STORE_ENT" , 0, 9 },
69 [INSTR_STORE_FLD] = { "STORE_FLD" , 0, 9 },
70 [INSTR_STORE_FNC] = { "STORE_FNC" , 0, 9 },
71 [INSTR_STOREP_F] = { "STOREP_F" , 0, 8 },
72 [INSTR_STOREP_V] = { "STOREP_V" , 0, 8 },
73 [INSTR_STOREP_S] = { "STOREP_S" , 0, 8 },
74 [INSTR_STOREP_ENT] = { "STOREP_ENT", 0, 10},
75 [INSTR_STOREP_FLD] = { "STOREP_FLD", 0, 10},
76 [INSTR_STOREP_FNC] = { "STOREP_FNC", 0, 10},
77 [INSTR_RETURN] = { "RETURN" , 0, 6 },
78 [INSTR_NOT_F] = { "NOT_F" , 0, 5 },
79 [INSTR_NOT_V] = { "NOT_V" , 0, 5 },
80 [INSTR_NOT_S] = { "NOT_S" , 0, 5 },
81 [INSTR_NOT_ENT] = { "NOT_ENT" , 0, 7 },
82 [INSTR_NOT_FNC] = { "NOT_FNC" , 0, 7 },
83 [INSTR_IF] = { "IF" , 0, 2 },
84 [INSTR_IFNOT] = { "IFNOT" , 0, 5 },
85 [INSTR_CALL0] = { "CALL0" , 0, 5 },
86 [INSTR_CALL1] = { "CALL1" , 0, 5 },
87 [INSTR_CALL2] = { "CALL2" , 0, 5 },
88 [INSTR_CALL3] = { "CALL3" , 0, 5 },
89 [INSTR_CALL4] = { "CALL4" , 0, 5 },
90 [INSTR_CALL5] = { "CALL5" , 0, 5 },
91 [INSTR_CALL6] = { "CALL6" , 0, 5 },
92 [INSTR_CALL7] = { "CALL7" , 0, 5 },
93 [INSTR_CALL8] = { "CALL8" , 0, 5 },
94 [INSTR_STATE] = { "STATE" , 0, 5 },
95 [INSTR_GOTO] = { "GOTO" , 0, 4 },
96 [INSTR_AND] = { "AND" , 0, 3 },
97 [INSTR_OR] = { "OR" , 0, 2 },
98 [INSTR_BITAND] = { "BITAND" , 0, 6 },
99 [INSTR_BITOR] = { "BITOR" , 0, 5 }
103 * Some assembler keywords not part of the opcodes above: these are
104 * for creating functions, or constants.
106 const char *const asm_keys[] = {
107 "FLOAT" , /* define float */
108 "VECTOR" , /* define vector */
109 "ENTITY" , /* define ent */
110 "FIELD" , /* define field */
111 "STRING" , /* define string */
115 static char *const asm_getline(size_t *byte, FILE *fp) {
117 ssize_t read = util_getline(&line, byte, fp);
126 #define asm_rmnewline(L,S) *((L)+*(S)-1) = '\0'
127 #define asm_skipwhite(L) \
128 while((*(L)==' '||*(L)=='\t')) { \
132 void asm_init(const char *file, FILE **fp) {
133 *fp = fopen(file, "r");
137 void asm_close(FILE *fp) {
143 * Following parse states:
144 * ASM_FUNCTION -- in a function accepting input statements
153 char *name; /* name of constant */
154 int offset; /* location in globals */
156 VECTOR_MAKE(globals, assembly_constants);
160 for (; i < assembly_constants_elements; i++)
161 mem_d(assembly_constants_data[i].name);
162 mem_d(assembly_constants_data);
165 void asm_parse(FILE *fp) {
168 long line = 1; /* current line */
169 size_t size = 0; /* size of line */
170 asm_state state = ASM_NULL;
172 while ((data = asm_getline(&size, fp)) != NULL) {
175 asm_rmnewline(skip, &size);
177 #define DECLTYPE(X, CODE) \
178 if (!strncmp(X, skip, strlen(X))) { \
179 if (skip[strlen(X)] != ':') { \
180 printf("%li: Missing `:` after decltype\n",line); \
183 skip += strlen(X)+1; \
184 asm_skipwhite(skip); \
185 if(!isalpha(*skip)) { \
186 printf("%li: Invalid identififer: %s\n", line, skip); \
189 size_t offset_code = code_statements_elements+1; \
190 size_t offset_chars = code_chars_elements +1; \
191 size_t offset_globals = code_globals_elements +1; \
192 size_t offset_functions = code_functions_elements +1; \
193 size_t offset_fields = code_fields_elements +1; \
194 size_t offset_defs = code_defs_elements +1; \
196 /* silent unused warnings */ \
198 (void)offset_chars; \
199 (void)offset_globals; \
200 (void)offset_functions; \
201 (void)offset_fields; \
203 assembly_constants_add((globals){ \
204 .name = util_strdup("empty"), \
205 .offset = offset_globals \
212 DECLTYPE(asm_keys[0], {
213 //util_debug("ASM", "Constant FLOAT\n");
214 code_defs_add((prog_section_def){
216 .offset = offset_globals, /* global table */
217 .name = offset_chars /* string table TODO */
219 float f = 0; /*TODO*/
220 code_globals_add(*(int*)&f);
224 DECLTYPE(asm_keys[1], {
225 //util_debug("ASM", "Constant VECTOR\n");
226 code_defs_add((prog_section_def){
228 .offset = offset_globals, /* global table */
229 .name = offset_chars /* string table TODO */
234 code_globals_add(*(int*)&f1);
235 code_globals_add(*(int*)&f2);
236 code_globals_add(*(int*)&f3);
238 /* ENTITY */ DECLTYPE(asm_keys[2], {util_debug("ASM", "Constant ENTITY\n");});
239 /* FIELD */ DECLTYPE(asm_keys[3], {util_debug("ASM", "Constant FIELD\n");});
241 DECLTYPE(asm_keys[4], {
242 //util_debug("ASM", "Constant STRING\n");
243 code_defs_add((prog_section_def){
245 .offset = offset_globals, /* offset to offset in string table (for data)*/
246 .name = offset_chars /* location of name in string table (for name)*/
248 code_strings_add("hello world");
251 DECLTYPE(asm_keys[5], {
252 //util_debug("ASM", "Constant FUNCTION\n");
254 if (state != ASM_NULL) {
255 printf("%li: Error unfinished function block, expected DONE or RETURN\n", line);
259 state = ASM_FUNCTION;
260 code_defs_add((prog_section_def){
262 .offset = offset_globals,
265 code_globals_add(offset_functions);
266 code_functions_add((prog_section_function){
267 .entry = offset_code,
271 .name = offset_chars,
278 /* if we make it this far then we have statements */
280 size_t i = 0; /* counter */
281 size_t o = 0; /* operands */
282 char *t = NULL; /* token */
285 * Most ops a single statement can have is three.
286 * lets allocate some space for all of those here.
288 char op[3][32768] = {{0},{0},{0}};
289 for (; i < sizeof(asm_instr)/sizeof(*asm_instr); i++) {
290 if (!strncmp(skip, asm_instr[i].m, asm_instr[i].l)) {
291 if (state != ASM_FUNCTION) {
292 printf("%li: Statement not inside function block\n", line);
296 /* update parser state */
297 if (i == INSTR_DONE || i == INSTR_RETURN) {
302 /* parse the statement */
303 o = asm_instr[i].o; /* operands */
304 skip += asm_instr[i].l; /* skip instruction */
305 t = strtok(skip, " ,");
307 while (t != NULL && i < 3) {
309 t = strtok(NULL, " ,");
313 // util_debug("ASM", "Operand 1: %s\n", util_strrnl(op[0]));
314 // util_debug("ASM", "Operand 2: %s\n", util_strrnl(op[1]));
315 // util_debug("ASM", "Operand 3: %s\n", util_strrnl(op[2]));
319 printf("not enough operands, expected: %li, got %li\n", o, i);
322 /* TODO: hashtable value LOAD .... etc */
323 code_statements_add((prog_section_statement){
331 /* if we made it this far something is wrong */
333 printf("%li: Invalid statement, expression, or decleration\n", line);