Fixes to README
[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 char *const asm_instr[] = {
30         [INSTR_DONE]       = "DONE",
31         [INSTR_MUL_F]      = "MUL_F",
32         [INSTR_MUL_V]      = "MUL_V",
33         [INSTR_MUL_FV]     = "MUL_FV",
34         [INSTR_MUL_VF]     = "MUL_VF",
35         [INSTR_DIV_F]      = "DIV",
36         [INSTR_ADD_F]      = "ADD_F",
37         [INSTR_ADD_V]      = "ADD_V",
38         [INSTR_SUB_F]      = "SUB_F",
39         [INSTR_SUB_V]      = "DUB_V",
40         [INSTR_EQ_F]       = "EQ_F",
41         [INSTR_EQ_V]       = "EQ_V",
42         [INSTR_EQ_S]       = "EQ_S",
43         [INSTR_EQ_E]       = "EQ_E",
44         [INSTR_EQ_FNC]     = "ES_FNC",
45         [INSTR_NE_F]       = "NE_F",
46         [INSTR_NE_V]       = "NE_V",
47         [INSTR_NE_S]       = "NE_S",
48         [INSTR_NE_E]       = "NE_E",
49         [INSTR_NE_FNC]     = "NE_FNC",
50         [INSTR_LE]         = "LE",
51         [INSTR_GE]         = "GE",
52         [INSTR_LT]         = "LT",
53         [INSTR_GT]         = "GT",
54         [INSTR_LOAD_F]     = "FIELD_F",
55         [INSTR_LOAD_V]     = "FIELD_V",
56         [INSTR_LOAD_S]     = "FIELD_S",
57         [INSTR_LOAD_ENT]   = "FIELD_ENT",
58         [INSTR_LOAD_FLD]   = "FIELD_FLD",
59         [INSTR_LOAD_FNC]   = "FIELD_FNC",
60         [INSTR_ADDRESS]    = "ADDRESS",
61         [INSTR_STORE_F]    = "STORE_F",
62         [INSTR_STORE_V]    = "STORE_V",
63         [INSTR_STORE_S]    = "STORE_S",
64         [INSTR_STORE_ENT]  = "STORE_ENT",
65         [INSTR_STORE_FLD]  = "STORE_FLD",
66         [INSTR_STORE_FNC]  = "STORE_FNC",
67         [INSTR_STOREP_F]   = "STOREP_F",
68         [INSTR_STOREP_V]   = "STOREP_V",
69         [INSTR_STOREP_S]   = "STOREP_S",
70         [INSTR_STOREP_ENT] = "STOREP_ENT",
71         [INSTR_STOREP_FLD] = "STOREP_FLD",
72         [INSTR_STOREP_FNC] = "STOREP_FNC",
73         [INSTR_RETURN]     = "RETURN",
74         [INSTR_NOT_F]      = "NOT_F",
75         [INSTR_NOT_V]      = "NOT_V",
76         [INSTR_NOT_S]      = "NOT_S",
77         [INSTR_NOT_ENT]    = "NOT_ENT",
78         [INSTR_NOT_FNC]    = "NOT_FNC",
79         [INSTR_IF]         = "IF",
80         [INSTR_IFNOT]      = "IFNOT",
81         [INSTR_CALL0]      = "CALL0",
82         [INSTR_CALL1]      = "CALL1",
83         [INSTR_CALL2]      = "CALL2",
84         [INSTR_CALL3]      = "CALL3",
85         [INSTR_CALL4]      = "CALL4",
86         [INSTR_CALL5]      = "CALL5",
87         [INSTR_CALL6]      = "CALL6",
88         [INSTR_CALL7]      = "CALL7",
89         [INSTR_CALL8]      = "CALL8",
90         [INSTR_STATE]      = "STATE",
91         [INSTR_GOTO]       = "GOTO",
92         [INSTR_AND]        = "AND",
93         [INSTR_OR]         = "OR",
94         [INSTR_BITAND]     = "AND",
95         [INSTR_BITOR]      = "OR"
96 };
97
98 /*
99  * Some assembler keywords not part of the opcodes above: these are
100  * for creating functions, or constants.
101  */
102 const char *const asm_keys[] = {
103         "FLOAT"    , /* define float  */
104         "VECTOR"   , /* define vector */
105         "ENTITY"   , /* define ent    */
106         "FIELD"    , /* define field  */
107         "STRING"   , /* define string */
108         "FUNCTION"
109 };
110
111 static char *const asm_getline(size_t *byte, FILE *fp) {
112         char   *line = NULL;
113         ssize_t read = getline(&line, byte, fp);
114         *byte = read;
115         if (read == -1) {
116                 free (line);
117                 //exit (1);
118                 return NULL;
119         }
120         return line;
121 }
122
123 #define asm_rmnewline(L,S) *((L)+*(S)-1) = '\0'
124 #define asm_skipwhite(L)             \
125     while((*(L)==' '||*(L)=='\t')) { \
126         (L)++;                       \
127     }
128     
129 void asm_init(const char *file, FILE **fp) {
130         *fp = fopen(file, "r");
131         code_init();
132 }
133
134 void asm_close(FILE *fp) {
135         fclose(fp);
136         code_write();
137 }
138         
139 void asm_parse(FILE *fp) {
140         char  *data = NULL;
141         char  *skip = NULL;
142         long   line = 1; /* current line */
143         size_t size = 0; /* size of line */
144         
145         while ((data = asm_getline(&size, fp)) != NULL) {
146                 skip = data;
147                 asm_skipwhite(skip);
148                 asm_rmnewline(skip, &size);
149                 
150                 #define DECLTYPE(X, CODE)                                         \
151                     if (!strncmp(X, skip, strlen(X))) {                           \
152                         if (skip[strlen(X)] != ':') {                             \
153                             printf("%li: Missing `:` after decltype\n",line);     \
154                             exit (1);                                             \
155                         }                                                         \
156                         skip += strlen(X)+1;                                      \
157                         asm_skipwhite(skip);                                      \
158                         if(!isalpha(*skip)) {                                     \
159                             printf("%li: Invalid identififer: %s\n", line, skip); \
160                             exit (1);                                             \
161                         } else {                                                  \
162                             size_t offset_code      = code_statements_elements+1; \
163                             size_t offset_chars     = code_strings_elements   +1; \
164                             size_t offset_globals   = code_globals_elements   +1; \
165                             size_t offset_functions = code_functions_elements +1; \
166                             size_t offset_fields    = code_fields_elements    +1; \
167                             size_t offset_defs      = code_defs_elements      +1; \
168                             CODE                                                  \
169                             /* silent unused warnings */                          \
170                             (void)offset_code;                                    \
171                             (void)offset_chars;                                   \
172                             (void)offset_globals;                                 \
173                             (void)offset_functions;                               \
174                             (void)offset_fields;                                  \
175                             (void)offset_defs;                                    \
176                         }                                                         \
177                         goto end;                                                 \
178                     }
179                 
180                 /* FLOAT    */
181                 DECLTYPE(asm_keys[0], {
182                         code_defs_add((prog_section_def){
183                                 .type   = TYPE_FLOAT,
184                                 .offset = offset_globals, /* global table */
185                                 .name   = offset_chars    /* string table TODO */
186                         });
187                         float f = 0; /*TODO*/
188                         code_globals_add(*(int*)&f);
189                         
190                 });
191                 DECLTYPE(asm_keys[1], {
192                         code_defs_add((prog_section_def){
193                                 .type   = TYPE_FLOAT,
194                                 .offset = offset_globals, /* global table */
195                                 .name   = offset_chars    /* string table TODO */
196                         });
197                         float f1 = 0;
198                         float f2 = 0;
199                         float f3 = 0;
200                         code_globals_add(*(int*)&f1);
201                         code_globals_add(*(int*)&f2);
202                         code_globals_add(*(int*)&f3);
203                 });
204                 /* ENTITY   */ DECLTYPE(asm_keys[2], {});
205                 /* FIELD    */ DECLTYPE(asm_keys[3], {});
206                 /* STRING   */
207                 DECLTYPE(asm_keys[4], {
208                         code_defs_add((prog_section_def){
209                                 .type   = TYPE_STRING,    
210                                 .offset = offset_globals, /* offset to offset in string table (for data)*/
211                                 .name   = offset_chars    /* location of name in string table (for name)*/
212                         });
213                 });
214                 /* FUNCTION */ DECLTYPE(asm_keys[5], {});
215                 
216                 /* if we make it this far then we have statements */
217                 {
218                         size_t i = 0;
219                         for (; i < sizeof(asm_instr)/sizeof(*asm_instr); i++) {
220                                 if (!strncmp(skip, asm_instr[i], strlen(asm_instr[i]))) {
221                                         /* TODO */
222                                         goto end;
223                                 }
224                         }
225                 }
226                 
227                 /* if we made it this far something is wrong */
228                 printf("ERROR");
229                 
230                 end:
231                 free(data);
232         }
233 }