]> git.xonotic.org Git - xonotic/gmqcc.git/blob - assembler.c
AUTHORS
[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 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         while (**skip == ' ' || **skip == '\t')
90             (*skip)++;
91         
92         if (!isalpha(**skip)) {
93             printf("%li: Invalid identififer: %s\n", line, *skip);
94             exit(1);
95         } else {
96             assembly_constants_add((globals) {
97                 .name   = util_strdup("empty"),
98                 .offset = code_globals_elements
99             });
100             return 1;
101         }
102     }
103     return 0;
104 }
105
106 void asm_parse(FILE *fp) {
107     char     *data  = NULL;
108     char     *skip  = NULL;
109     long      line  = 1; /* current line */
110     size_t    size  = 0; /* size of line */
111     asm_state state = ASM_NULL;
112     
113     while ((data = skip = asm_getline(&size, fp)) != NULL) {
114         /* remove any whitespace at start  */
115         while (*skip == ' ' || *skip == '\t')
116             skip++;
117         /* remove newline at end of string */
118         *(skip+*(&size)-1) = '\0';
119         
120         if (asm_parsetype(asm_keys[5], &skip, line)) {
121             if (state != ASM_NULL) {
122                 printf("%li: Error unfinished function block, expected DONE or RETURN\n", line);
123                 goto end;
124             }
125             state = ASM_FUNCTION;
126             code_defs_add((prog_section_def){
127                 .type   = TYPE_VOID,
128                 .offset = code_globals_elements,
129                 .name   = code_chars_elements
130             });
131             code_globals_add(code_functions_elements);
132             code_functions_add((prog_section_function) {
133                 .entry      =  code_statements_elements,      
134                 .firstlocal =  0,
135                 .locals     =  0,
136                 .profile    =  0,
137                 .name       =  code_chars_elements,
138                 .file       =  0,
139                 .nargs      =  0,
140                 .argsize    = {0}
141             });
142             code_strings_add(skip);
143         };
144
145         #if 0
146         /* if we make it this far then we have statements */
147         {
148             size_t i = 0;    /* counter   */
149             size_t o = 0;    /* operands  */
150             size_t c = 0;    /* copy      */
151             char  *t = NULL; /* token     */
152             
153             /*
154              * Most ops a single statement can have is three.
155              * lets allocate some space for all of those here.
156              */
157             char op[3][32768] = {{0},{0},{0}};
158             for (; i < sizeof(asm_instr)/sizeof(*asm_instr); i++) {
159                 if (!strncmp(skip, asm_instr[i].m, asm_instr[i].l)) {
160                     if (state != ASM_FUNCTION) {
161                         printf("%li: Statement not inside function block\n", line);
162                         goto end;
163                     }
164                     
165                     /* update parser state */
166                     if (i == INSTR_DONE || i == INSTR_RETURN) {
167                         goto end;
168                         state = ASM_NULL;
169                     }
170                     
171                     /* parse the statement */
172                     c     = i;
173                     o     = asm_instr[i].o; /* operands         */
174                     skip += asm_instr[i].l; /* skip instruction */
175                     t     = strtok(skip, " ,");
176                     i     = 0;
177                     while (t != NULL && i < 3) {
178                         strcpy(op[i], t);
179                         t = strtok(NULL, " ,");
180                         i ++;
181                     }
182                     
183                     /* check */
184                     if (i != o) {
185                         printf("not enough operands, expected: %li, got %li\n", o, i);
186                     }
187                     
188                     /* TODO: hashtable value LOAD .... etc */
189                     code_statements_add((prog_section_statement){
190                         c,
191                         { atof(op[0]) },
192                         { atof(op[1]) },
193                         { atof(op[2]) }
194                     });
195                     goto end;
196                 }
197             }
198         }
199         #endif
200         
201         /* if we made it this far something is wrong */
202         if (*skip != '\0')
203             printf("%li: Invalid statement %s, expression, or decleration\n", line, skip);
204         
205         end:
206         mem_d(data);
207         line ++;
208     }
209         asm_clear();
210 }