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