7f6527666a63c29a1735353a9400a1a958c355c1
[henge/apc.git] / src / lexer.rl
1 #include <stdio.h>
2 #include <stdint.h>
3 #include <stdlib.h>
4 #include <errno.h>
5 #include "parser.tab.h"
6 #include "apc.h"
7 #include <unistdio.h>
8 #include <unistr.h>
9 /* Public */
10 int lexer_init(void);
11 void lexer_quit(void);
12 int lexer_lexfile(uint8_t*);
13 int lexer_lexdir(uint8_t*);
14 int lexer_lexstring(uint8_t*, int);
15 //apc.c
16 static
17 yypstate* pstate;
18 static
19 yycstate* cstate;
20 /* Ring buffer for keeping lexical tokens valid for up to 255 tokens */
21 static
22 YYSTYPE lval_stack[0xFF + 1];
23 static
24 uint8_t lval_offs;
25 #define PUSHTOK(T,L) yypush_parse(pstate, T, (L), cstate)
26 #define LEXTOK(T,Y,L) do { \
27 lval_stack[lval_offs].Y = L; \
28 PUSHTOK(T,lval_stack + lval_offs); \
29 lval_offs++; \
30 ntok++; \
31 } while (0)
32 #define PUSHFACE(F) LEXTOK(FACING, face, F)
33 #define PUSHREF(R) LEXTOK(REF, ref, R)
34 #define PUSHLINK() LEXTOK(LINK, val, 0)
35 #define PUSHNUM(N) LEXTOK(NUM, val, N)
36 #define PUSHNAME(N) LEXTOK(NAME, str, N)
37 #define PUSHOP(O) LEXTOK(O, val, 0)
38 #define PUSHPATH(P) LEXTOK(PATH, str, P)
39
40 #define DEBUG 1
41 #define dprintf(_B, ...) do { \
42 if(_B) printf(__VA_ARGS__); \
43 } while (0)
44
45
46 /* Lexstring is the main lexer for APC and is generated by ragel. It lexes file names of files
47 that have been scanned and pushes their types and values into the tok_stack, which yyparse
48 eventually calls during parsing. */
49
50 %%{
51 machine lexstring;
52
53 # set up yylval and tok_t to be pushed to stack
54 action push_ref { errno = 0;
55 lval.ref = strtoll((char*)ts,NULL,16);
56 if (errno)
57 { fprintf(stderr, "Invalid hex number in file %s\n",(char*)str);
58 exit(1);
59 }
60 PUSHREF(lval.ref);
61 }
62 action push_link { PUSHLINK(); }
63 action push_val { errno = 0;
64 lval.val = strtoll((char*)ts,NULL,10);
65 if (errno)
66 { fprintf(stderr, "strtoll could not parse %s\n", (char*)str);
67 exit(1);
68 }
69 PUSHNUM(lval.val);
70 }
71 action push_name { dprintf(DEBUG, "Lexer_lexstring:: action:push_name: from %s to %s\n", ts, p);
72 PUSHNAME(ts);
73 }
74 action push_map { dprintf(DEBUG, "Lexer_lexstring:: action:push_map: pushing map token\n");
75 PUSHOP(MAP);
76 }
77 action set_ts { dprintf(DEBUG, "Lexer_lexstring:: action:set_ts. ts = %s\n", p);
78 ts = p; }
79 action push_SS { dprintf(DEBUG, "Lexer_lexstring:: action:push_SS. p = %s\n",p);
80 PUSHOP(SS);
81 }
82 action push_S { dprintf(DEBUG, "Lexer_lexstring:: action:push_S. p = %s\n", p);
83 PUSHFACE(SFACE);
84 }
85 action push_SW { dprintf(DEBUG, "Lexer_lexstring:: action:push_SW. p = %s\n", p);
86 PUSHFACE(SWFACE);
87 }
88 action push_W { dprintf(DEBUG, "Lexer_lexstring:: action:push_W. p = %s\n", p);
89 PUSHFACE(WFACE);
90 }
91 action push_NW { dprintf(DEBUG, "Lexer_lexstring:: action:push_NW. p = %s\n", p);
92 PUSHFACE(NWFACE);
93 }
94 action push_N { dprintf(DEBUG, "Lexer_lexstring:: action:push_N. p = %s\n", p);
95 PUSHFACE(NFACE);
96 }
97 action push_NE { dprintf(DEBUG, "Lexer_lexstring:: action:push_NE. p = %s\n", p);
98 PUSHFACE(NEFACE);
99 }
100 action push_E { dprintf(DEBUG, "Lexer_lexstring:: action:push_N. p = %s\n", p);
101 PUSHFACE(EFACE);
102 }
103 action push_SE { dprintf(DEBUG, "Lexer_lexstring:: action:push_N. p = %s\n", p);
104 PUSHFACE(SEFACE);
105 }
106 action ref_error { dprintf(DEBUG, "ref from %s to %s has an inappropriate amount of hex digits, it must have eight.\n", ts, p);
107 exit(1);
108 }
109 action p { dprintf("Lexer_lexstring:: p = %s\n", p);
110 }
111
112 N = 'N' %push_N;
113 W = 'W' %push_W;
114 S = 'S' %push_S;
115 E = 'E' %push_E;
116 NW = 'NW' %push_NW;
117 NE = 'NE' %push_NW;
118 SW = 'SW' %push_SW;
119 SE = 'SE' %push_SE;
120
121 tok_delimiter = [_\0];
122
123 direction = (N | W | S | E | NW | NE | SW | SE) ;
124 dimensions = (digit+ - '0') >set_ts %push_val 'x' (digit+ - '0') >set_ts %push_val;
125 link = '#' %push_link;
126 SS = ('+SS' %to(push_SS)) | ('+SS' %to(push_SS) link ) ;
127 ref = '0x' >set_ts alnum{8} $err(ref_error) %push_ref ;
128 val = digit+ >set_ts %push_val ;
129 name = lower >set_ts (lower | digit)* %push_name ;
130 map = '+MAP' %to(push_map);
131 tok = (name | val | ref | dimensions | map | link | SS | direction);
132
133
134 main := (tok tok_delimiter)* tok [\0];
135
136 write data nofinal noerror noprefix;
137
138 }%%
139
140 int lexer_init
141 ( void )
142 { pstate = yypstate_new();
143 cstate = yycstate_new();
144 lval_offs = 0;
145 return !pstate || !cstate;
146 }
147
148 void lexer_quit
149 ( void )
150 { if (pstate) yypstate_delete(pstate);
151 if (cstate) yycstate_delete(cstate);
152 }
153
154 int lexer_lexstring
155 ( uint8_t* str,
156 int size
157 )
158 { uint8_t* p, * ts, * pe, * eof;
159 int cs, ntok;
160 YYSTYPE lval;
161
162 ntok = 0;
163 p = ts = str;
164 pe = eof = p + size + 1;
165
166 dprintf("|---Begin lexstring on p = %s, pe = %s.\n", (char*)p, pe);
167
168 %%write init;
169 %%write exec;
170
171 dprintf("Ending lexstring of file %s, pushed %d tokens.\n", (char*)str, ntok);
172
173 return ntok;
174 }
175
176 /* Lexical analysis of a file
177 Strips a filename to its base name, then sends it to lexer_lexstring before
178 pushing a PATH token with the filename
179 Returns the number of tokens pushed to the parser.
180 */
181 int lexer_lexfile
182 ( uint8_t* filename )
183 { uint8_t* last_period,* iter,* filename_end;
184 int ntok;
185 last_period = NULL;
186 for (iter = filename; *iter; iter++)
187 switch (*iter)
188 { // Keep track of the last 'dot' in the name
189 case '.' : last_period = iter; continue;
190 // replace '_' with '\0' so bison can use strlen on them as tokens.
191 case '_' : *iter = '\0';
192 default: continue;
193 }
194 // Mark the end of the filename
195 filename_end = iter;
196 // Lex from either the last period, if present, or filename end
197 ntok = (last_period) ?
198 lexer_lexstring(filename, (int)(last_period - filename))
199 : lexer_lexstring(filename, (int)(iter - filename));
200 // Replace nulls with their original '_'
201 for (iter = filename; iter < filename_end; iter++)
202 if (*iter == '\0')
203 *iter = '_';
204 PUSHPATH(filename);
205 return ntok + 1;
206 return en_main == 1;
207 }
208
209 int lexer_lexdir
210 ( uint8_t* dirname )
211 { uint8_t* de = dirname;
212 int ntok;
213 ntok = 0;
214 de = dirname;
215 if (*de) while (*++de);
216 ntok = lexer_lexstring(dirname, (int)(de - dirname));
217 PUSHOP(CLOPEN);
218 return ntok;
219 }
220
221 int lexer_closedir
222 ( void )
223 { int ntok = 0;
224 PUSHOP(CLCLOSE);
225 return ntok;
226 }