]> git.xonotic.org Git - xonotic/gmqcc.git/blob - assembler.c
6a4ec461a9f9848ec557d1946155dc04c27f7a3d
[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  * Some assembler keywords not part of the opcodes above: these are
26  * for creating functions, or constants.
27  */
28 const char *const asm_keys[] = {
29     "FLOAT"    , /* define float  */
30     "VECTOR"   , /* define vector */
31     "ENTITY"   , /* define ent    */
32     "FIELD"    , /* define field  */
33     "STRING"   , /* define string */
34     "FUNCTION"
35 };
36
37 static char *const asm_getline(size_t *byte, FILE *fp) {
38     char   *line = NULL;
39     ssize_t read = util_getline(&line, byte, fp);
40     *byte = read;
41     if (read == -1) {
42         mem_d (line);
43         return NULL;
44     }
45     return line;
46 }
47
48 #define asm_rmnewline(L,S) *((L)+*(S)-1) = '\0'
49 #define asm_skipwhite(L)             \
50     while((*(L)==' '||*(L)=='\t')) { \
51         (L)++;                       \
52     }
53     
54 void asm_init(const char *file, FILE **fp) {
55     *fp = fopen(file, "r");
56     code_init();
57 }
58
59 void asm_close(FILE *fp) {
60     fclose(fp);
61     code_write();
62 }
63
64 /*
65  * Following parse states:
66  *     ASM_FUNCTION -- in a function accepting input statements
67  *     ....
68  */
69 typedef enum {
70     ASM_NULL,
71     ASM_FUNCTION
72 } asm_state;
73
74 typedef struct {
75     char *name;   /* name of constant    */
76     int   offset; /* location in globals */
77 } globals;
78 VECTOR_MAKE(globals, assembly_constants);
79
80 void asm_clear() {
81     size_t i = 0;
82     for (; i < assembly_constants_elements; i++)
83         mem_d(assembly_constants_data[i].name);
84     mem_d(assembly_constants_data);
85 }
86
87 int asm_parsetype(const char *key, char **skip, long line) {
88     size_t keylen = strlen(key);
89     if (!strncmp(key, *skip, keylen)) {
90         if ((*skip)[keylen] != ':'){
91             printf("%li: Missing `:` after decltype\n", line);
92             exit(1);
93         }
94         *skip += keylen+1;
95         while (**skip == ' ' || **skip == '\t')
96             (*skip)++;
97         
98         if (!isalpha(**skip)) {
99             printf("%li: Invalid identififer: %s\n", line, *skip);
100             exit(1);
101         } else {
102             assembly_constants_add((globals) {
103                 .name   = util_strdup("empty"),
104                 .offset = code_globals_elements
105             });
106             return 1;
107         }
108     }
109     return 0;
110 }
111
112 void asm_parse(FILE *fp) {
113     char     *data  = NULL;
114     char     *skip  = NULL;
115     long      line  = 1; /* current line */
116     size_t    size  = 0; /* size of line */
117     asm_state state = ASM_NULL;
118     
119     while ((data = skip = asm_getline(&size, fp)) != NULL) {
120         /* remove any whitespace at start  */
121         while (*skip == ' ' || *skip == '\t')
122             skip++;
123         /* remove newline at end of string */
124         *(skip+*(&size)-1) = '\0';
125         
126         if (asm_parsetype(asm_keys[5], &skip, line)) {
127             if (state != ASM_NULL) {
128                 printf("%li: Error unfinished function block, expected DONE or RETURN\n", line);
129                 goto end;
130             }
131             state = ASM_FUNCTION;
132             code_defs_add((prog_section_def){
133                 .type   = TYPE_VOID,
134                 .offset = code_globals_elements,
135                 .name   = code_chars_elements
136             });
137             code_globals_add(code_functions_elements);
138             code_functions_add((prog_section_function) {
139                 .entry      =  code_statements_elements,      
140                 .firstlocal =  0,
141                 .locals     =  0,
142                 .profile    =  0,
143                 .name       =  code_chars_elements,
144                 .file       =  0,
145                 .nargs      =  0,
146                 .argsize    = {0}
147             });
148             code_strings_add(skip);
149         };
150
151         #if 0
152         /* if we make it this far then we have statements */
153         {
154             size_t i = 0;    /* counter   */
155             size_t o = 0;    /* operands  */
156             size_t c = 0;    /* copy      */
157             char  *t = NULL; /* token     */
158             
159             /*
160              * Most ops a single statement can have is three.
161              * lets allocate some space for all of those here.
162              */
163             char op[3][32768] = {{0},{0},{0}};
164             for (; i < sizeof(asm_instr)/sizeof(*asm_instr); i++) {
165                 if (!strncmp(skip, asm_instr[i].m, asm_instr[i].l)) {
166                     if (state != ASM_FUNCTION) {
167                         printf("%li: Statement not inside function block\n", line);
168                         goto end;
169                     }
170                     
171                     /* update parser state */
172                     if (i == INSTR_DONE || i == INSTR_RETURN) {
173                         goto end;
174                         state = ASM_NULL;
175                     }
176                     
177                     /* parse the statement */
178                     c     = i;
179                     o     = asm_instr[i].o; /* operands         */
180                     skip += asm_instr[i].l; /* skip instruction */
181                     t     = strtok(skip, " ,");
182                     i     = 0;
183                     while (t != NULL && i < 3) {
184                         strcpy(op[i], t);
185                         t = strtok(NULL, " ,");
186                         i ++;
187                     }
188                     
189                     /* check */
190                     if (i != o) {
191                         printf("not enough operands, expected: %li, got %li\n", o, i);
192                     }
193                     
194                     /* TODO: hashtable value LOAD .... etc */
195                     code_statements_add((prog_section_statement){
196                         c,
197                         { atof(op[0]) },
198                         { atof(op[1]) },
199                         { atof(op[2]) }
200                     });
201                     goto end;
202                 }
203             }
204         }
205         #endif
206         
207         /* if we made it this far something is wrong */
208         if (*skip != '\0')
209             printf("%li: Invalid statement, expression, or decleration\n", line);
210         
211         end:
212         mem_d(data);
213         line ++;
214     }
215         asm_clear();
216 }