61038a4fc7e4061cdc76b7630e9c05c841bfea68
[zilutils.git] / zilasm / parser.c
1 /*
2  * parser.c -- part of ZilUtils/ZilAsm
3  *
4  * Copyright (C) 2016 Jason Self <j@jxself.org>
5  *
6  * This program is free software: you can redistribute it and/or modify
7  * it under the terms of the GNU Affero General Public License as
8  * published by the Free Software Foundation, either version 3 of the
9  * License, or (at your option) any later version.
10  *
11  * This program is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14  * GNU Affero General Public License for more details.
15  *
16  * You should have received a copy of the GNU Affero General Public License
17  * along with this program.  If not, see <http://www.gnu.org/licenses/>
18  *
19  * SPDX-License-Identifier: AGPL-3.0-or-later
20  */
21
22 #include <stdio.h>   /* fopen, fgets */
23 #include <string.h>  /* strlen */
24
25 #include "parser.h"
26 #include "directives.h"
27 #include "opcodes.h"
28 #include "labels.h"
29
30 #define iscomment(c)   ((c) == '#')
31 #define isbindigit(c)  ((c) == '0' || (c) == '1')
32
33 /* !!! TODO !!! */
34 #define fatal_error(errmsg)
35 #define PC NULL
36
37 void checksep(const char *p)
38 {
39         if (!*p || iscomment(*p) || isspace(*p)) return;
40         fatal_error("wrong chars");
41 }
42
43 const char *pass_spaces(const char *p)
44 {
45         while(p && isspace(*p)) p++;
46         return (p && *p) ? p : NULL;
47 }
48
49 const char *pass_alnums(const char *p)
50 {
51         while(p && isalnum(*p)) p++;
52         return (p && *p) ? p : NULL;
53 }
54
55 int tryparse_directive(const char *p)
56 {
57         if (*p != '.')
58                 return 0;
59         const char *a = p+1;
60         const char *b = pass_alnums(a);
61         checksep(b);
62         Directive_handler f = directive_lookup(a, b - a);
63         if (!f) return 0;
64         return (*f)(b);
65 }
66
67 int tryparse_assignment(const char *a, const char *b, const char *c)
68 {
69         return 0;
70 }
71
72 int tryparse_label(const char *a, const char *b, const char *c)
73 {
74         if (*(c+1) != ':') {
75                 symtable_add2(Local_labels, a, b - a, PC);
76         } else if (*(c+2) != ':') {
77                 symtable_add2(Global_labels, a, b - a, PC);
78         } else {
79                 fatal_error("wrong label type");
80         }
81
82         while (*c++ == ':');
83         if (*c && ((c = pass_spaces(c)) != NULL) && *c)
84                 return tryparse_instruction(c);
85         return 1;
86 }
87
88 int tryparse_name(const char *a)
89 {
90         const char *b = pass_alnums(a);
91         const char *c = pass_spaces(b);
92
93         if (!c)        return 0;
94         if (*c == '=') return tryparse_assignment(a, b, c + 1);
95         if (*c == ':') return tryparse_label(a, b, c);
96         return 0;
97 }
98
99 int tryparse_instruction(const char *a)
100 {
101         const char *b = pass_alnums(a);
102         ZOpcode *op = symtable_lookup2(Opcodes, a, b - a);
103         if (!op) return 0;
104         ZOpcode_flags flags = op->flags;
105         /* !!! TODO !!! */
106         return 0;
107 }
108
109 /*
110  *  Line can be one from: Comment, Global label, Local label, Directive, Name=Value, Instruction
111  */
112 int parse_line(const char *p)
113 {
114         for (; *p; p++) {
115                 char c = *p;
116                 int n;
117                 if (isspace(c))                  continue;
118                 if (iscomment(c))                return 0;
119                 if (n = tryparse_directive(p))   return n;
120                 if (n = tryparse_name(p))        return n;  // ..label or assignment
121                 if (n = tryparse_instruction(p)) return n;
122                 fatal_error("wrong line");
123         }
124         return 0;
125 }
126
127 int parse_file(const char *filename)
128 {
129         FILE *fp = fopen(filename, "r");
130         if (!fp) fatal_error("wrong file");
131
132         const int MAX_LINESIZE = 1024;
133         char line[MAX_LINESIZE];
134         int newline_missing = 0;
135
136         while (fgets(line, MAX_LINESIZE, fp)) {
137                 if (newline_missing) fatal_error("line too long");
138
139                 int n = strlen(line);
140                 if (!n) continue;
141
142                 parse_line(line);
143
144                 newline_missing = (line[n-1] != '\n');
145         }
146
147         close(fp);
148 }
149
150 /*
151
152 line_passed() {
153     skip_spaces();
154     return (current_token == LINE_END || current_token == LINE_COMMENT);
155 }
156
157 if (line_passed()) continue;
158 if (current_token == DIRECTIVE) {
159     if (!try_next_token(NAME))
160         fatal_error("directive contains incorrect chars")
161     handler = get_directive_handler(current_token);
162     if (!handler)
163         fatal error("unknown directive");
164     (*handler)(remaining_line);
165     if (line_passed()) continue;
166     fatal_error("unexpected line tail");
167 } else if (current_token == NAME) {
168     skip_spaces();
169     if (current_token == ASSIGNMENT)
170 }
171     
172
173 */