]> git.xonotic.org Git - xonotic/gmqcc.git/blob - assembler.c
More information about assembler instructions
[xonotic/gmqcc.git] / assembler.c
1 /*
2  * Copyright (C) 2012 
3  *      Dale Weiler
4  *
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:
11  *
12  * The above copyright notice and this permission notice shall be included in all
13  * copies or substantial portions of the Software.
14  *
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
21  * SOFTWARE.
22  */
23 #include "gmqcc.h"
24 /*
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.
28  */
29 static const struct {
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"      , 0, 4 },
35         [INSTR_MUL_F]      = { "MUL_F"     , 0, 5 },
36         [INSTR_MUL_V]      = { "MUL_V"     , 0, 5 },
37         [INSTR_MUL_FV]     = { "MUL_FV"    , 0, 6 },
38         [INSTR_MUL_VF]     = { "MUL_VF"    , 0, 6 },
39         [INSTR_DIV_F]      = { "DIV"       , 0, 3 },
40         [INSTR_ADD_F]      = { "ADD_F"     , 0, 5 },
41         [INSTR_ADD_V]      = { "ADD_V"     , 0, 5 },
42         [INSTR_SUB_F]      = { "SUB_F"     , 0, 5 },
43         [INSTR_SUB_V]      = { "DUB_V"     , 0, 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 }
100 };
101
102 /*
103  * Some assembler keywords not part of the opcodes above: these are
104  * for creating functions, or constants.
105  */
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 */
112         "FUNCTION"
113 };
114
115 static char *const asm_getline(size_t *byte, FILE *fp) {
116         char   *line = NULL;
117         ssize_t read = getline(&line, byte, fp);
118         *byte = read;
119         if (read == -1) {
120                 free (line);
121                 return NULL;
122         }
123         return line;
124 }
125
126 #define asm_rmnewline(L,S) *((L)+*(S)-1) = '\0'
127 #define asm_skipwhite(L)             \
128     while((*(L)==' '||*(L)=='\t')) { \
129         (L)++;                       \
130     }
131     
132 void asm_init(const char *file, FILE **fp) {
133         *fp = fopen(file, "r");
134         code_init();
135 }
136
137 void asm_close(FILE *fp) {
138         fclose(fp);
139         code_write();
140 }
141         
142 void asm_parse(FILE *fp) {
143         char  *data = NULL;
144         char  *skip = NULL;
145         long   line = 1; /* current line */
146         size_t size = 0; /* size of line */
147         
148         while ((data = asm_getline(&size, fp)) != NULL) {
149                 skip = data;
150                 asm_skipwhite(skip);
151                 asm_rmnewline(skip, &size);
152                 
153                 #define DECLTYPE(X, CODE)                                         \
154                     if (!strncmp(X, skip, strlen(X))) {                           \
155                         if (skip[strlen(X)] != ':') {                             \
156                             printf("%li: Missing `:` after decltype\n",line);     \
157                             exit (1);                                             \
158                         }                                                         \
159                         skip += strlen(X)+1;                                      \
160                         asm_skipwhite(skip);                                      \
161                         if(!isalpha(*skip)) {                                     \
162                             printf("%li: Invalid identififer: %s\n", line, skip); \
163                             exit (1);                                             \
164                         } else {                                                  \
165                             size_t offset_code      = code_statements_elements+1; \
166                             size_t offset_chars     = code_strings_elements   +1; \
167                             size_t offset_globals   = code_globals_elements   +1; \
168                             size_t offset_functions = code_functions_elements +1; \
169                             size_t offset_fields    = code_fields_elements    +1; \
170                             size_t offset_defs      = code_defs_elements      +1; \
171                             CODE                                                  \
172                             /* silent unused warnings */                          \
173                             (void)offset_code;                                    \
174                             (void)offset_chars;                                   \
175                             (void)offset_globals;                                 \
176                             (void)offset_functions;                               \
177                             (void)offset_fields;                                  \
178                             (void)offset_defs;                                    \
179                         }                                                         \
180                         goto end;                                                 \
181                     }
182                 
183                 /* FLOAT    */
184                 DECLTYPE(asm_keys[0], {
185                         code_defs_add((prog_section_def){
186                                 .type   = TYPE_FLOAT,
187                                 .offset = offset_globals, /* global table */
188                                 .name   = offset_chars    /* string table TODO */
189                         });
190                         float f = 0; /*TODO*/
191                         code_globals_add(*(int*)&f);
192                         
193                 });
194                 DECLTYPE(asm_keys[1], {
195                         code_defs_add((prog_section_def){
196                                 .type   = TYPE_FLOAT,
197                                 .offset = offset_globals, /* global table */
198                                 .name   = offset_chars    /* string table TODO */
199                         });
200                         float f1 = 0;
201                         float f2 = 0;
202                         float f3 = 0;
203                         code_globals_add(*(int*)&f1);
204                         code_globals_add(*(int*)&f2);
205                         code_globals_add(*(int*)&f3);
206                 });
207                 /* ENTITY   */ DECLTYPE(asm_keys[2], {});
208                 /* FIELD    */ DECLTYPE(asm_keys[3], {});
209                 /* STRING   */
210                 DECLTYPE(asm_keys[4], {
211                         code_defs_add((prog_section_def){
212                                 .type   = TYPE_STRING,    
213                                 .offset = offset_globals, /* offset to offset in string table (for data)*/
214                                 .name   = offset_chars    /* location of name in string table (for name)*/
215                         });
216                 });
217                 /* FUNCTION */
218                 DECLTYPE(asm_keys[5], {
219                         /* TODO: parse */
220                         code_defs_add((prog_section_def){
221                                 .type   = TYPE_VOID,
222                                 .offset = offset_globals,
223                                 .name   = offset_chars
224                         });
225                         code_globals_add(offset_functions);
226                         code_functions_add((prog_section_function){
227                                 .entry      =  offset_code,      
228                                 .firstlocal =  0,
229                                 .locals     =  0,
230                                 .profile    =  0,
231                                 .name       =  offset_chars,
232                                 .file       =  0,
233                                 .nargs      =  0,
234                                 .argsize    = {0}
235                         });
236                 });
237                 
238                 /* if we make it this far then we have statements */
239                 {
240                         size_t i = 0;
241                         for (; i < sizeof(asm_instr)/sizeof(*asm_instr); i++) {
242                                 if (!strncmp(skip, asm_instr[i].m, asm_instr[i].l)) {
243                                         /* TODO */
244                                         goto end;
245                                 }
246                         }
247                 }
248                 
249                 /* if we made it this far something is wrong */
250                 printf("ERROR");
251                 
252                 end:
253                 free(data);
254         }
255 }