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