]> git.lizzy.rs Git - plan9front.git/blob - sys/src/cmd/dtracy/lex.c
fix filetype detecton by suffix so that multiple dots dont confuse it. (thanks kvik)
[plan9front.git] / sys / src / cmd / dtracy / lex.c
1 #include <u.h>
2 #include <libc.h>
3 #include <ctype.h>
4 #include <dtracy.h>
5 #include <bio.h>
6 #include "dat.h"
7 #include "fns.h"
8 #include "y.tab.h"
9
10 char *str, *strp, *stre;
11 int lineno = 1;
12 int errors;
13
14 typedef struct Keyword Keyword;
15 struct Keyword {
16         char *name;
17         int tok;
18 };
19 /* both tables must be sorted */
20 Keyword kwtab[] = {
21         "if", TIF,
22         "print", TPRINT,
23         "printf", TPRINTF,
24         "s16", TS16,
25         "s32", TS32,
26         "s64", TS64,
27         "s8", TS8,
28         "string", TSTRING,
29         "u16", TU16,
30         "u32", TU32,
31         "u64", TU64,
32         "u8", TU8,
33 };
34 Keyword optab[] = {
35         "!=", TNE,
36         "&&", TAND,
37         "<<", TLSL,
38         "<=", TLE,
39         "==", TEQ,
40         ">=", TGE,
41         ">>", TLSR,
42         "||", TOR,
43 };
44 Keyword *kwchar[128], *opchar[128];
45
46 void
47 lexinit(void)
48 {
49         Keyword *kw;
50         
51         for(kw = kwtab; kw < kwtab + nelem(kwtab); kw++)
52                 if(kwchar[*kw->name] == nil)
53                         kwchar[*kw->name] = kw;
54         for(kw = optab; kw < optab + nelem(optab); kw++)
55                 if(opchar[*kw->name] == nil)
56                         opchar[*kw->name] = kw;
57 }
58
59 void
60 lexstring(char *s)
61 {
62         str = strp = s;
63         stre = str + strlen(str);
64 }
65
66 void
67 error(char *fmt, ...)
68 {
69         Fmt f;
70         char buf[128];
71         va_list va;
72         
73         fmtfdinit(&f, 2, buf, sizeof(buf));
74         fmtprint(&f, "%d ", lineno);
75         va_start(va, fmt);
76         fmtvprint(&f, fmt, va);
77         fmtrune(&f, '\n');
78         va_end(va);
79         fmtfdflush(&f);
80         errors++;
81 }
82
83 void
84 yyerror(char *msg)
85 {
86         error("%s", msg);
87 }
88
89 static int
90 getch(void)
91 {
92         if(strp >= stre){
93                 strp++;
94                 return -1;
95         }
96         return *strp++;
97 }
98
99 static void
100 ungetch(void)
101 {
102         assert(strp > str);
103         strp--;
104 }
105
106 int
107 yylex(void)
108 {
109         int ch;
110         static char buf[512];
111         char *p;
112         Keyword *kw;
113         u64int v;
114
115 again:
116         while(ch = getch(), ch >= 0 && isspace(ch)){
117                 if(ch == '\n')
118                         lineno++;
119         }
120         if(ch < 0)
121                 return -1;
122         if(ch == '/'){
123                 ch = getch();
124                 if(ch == '/'){
125                         while(ch = getch(), ch >= 0 && ch != '\n')
126                                 ;
127                         if(ch == '\n')
128                                 lineno++;
129                         goto again;
130                 }
131                 if(ch == '*'){
132                 s1:
133                         ch = getch();
134                         if(ch < 0) return -1;
135                         if(ch == '\n') lineno++;
136                         if(ch != '*') goto s1;
137                 s2:
138                         ch = getch();
139                         if(ch < 0) return -1;
140                         if(ch == '\n') lineno++;
141                         if(ch == '*') goto s2;
142                         if(ch != '/') goto s1;
143                         goto again;
144                 }
145                 ungetch();
146                 return '/';
147         }
148         if(isalnum(ch) || ch == '_' || ch >= 0x80 || ch == ':'){
149                 p = buf;
150                 *p++ = ch;
151                 while(ch = getch(), isalnum(ch) || ch == '_' || ch >= 0x80 || ch == ':')
152                         if(p < buf + sizeof(buf) - 1)
153                                 *p++ = ch;
154                 *p = 0;
155                 ungetch();
156                 v = strtoull(buf, &p, 0);
157                 if(p != buf && *p == 0){
158                         yylval.num = v;
159                         return TNUM;
160                 }
161                 if(strcmp(buf, ":") == 0)
162                         return ':';
163                 if((uchar)buf[0] < 0x80 && kwchar[buf[0]] != nil)
164                         for(kw = kwchar[buf[0]]; kw < kwtab + nelem(kwtab) && kw->name[0] == buf[0]; kw++)
165                                 if(strcmp(kw->name, buf) == 0)
166                                         return kw->tok;
167                 yylval.sym = getsym(buf);
168                 return TSYM;
169         }
170         if(ch == '"'){
171                 p = buf;
172                 while(ch = getch(), ch >= 0 && ch != '"'){
173                         if(ch == '\n')
174                                 error("unterminated string");
175                         if(ch == '\\')
176                                 switch(ch = getch()){
177                                 case 'n': ch = '\n'; break;
178                                 case 'r': ch = '\r'; break;
179                                 case 't': ch = '\t'; break;
180                                 case 'v': ch = '\v'; break;
181                                 case 'b': ch = '\b'; break;
182                                 case 'a': ch = '\a'; break;
183                                 case '"': case '\\': break;
184                                 default: error("unknown escape code \\%c", ch);
185                                 }
186                         if(p < buf + sizeof(buf) - 1)
187                                 *p++ = ch;
188                 }
189                 if(ch < 0) error("unterminated string");
190                 *p = 0;
191                 yylval.str = strdup(buf);
192                 return TSTR;
193         }
194         if(opchar[ch] != nil){
195                 buf[0] = ch;
196                 buf[1] = getch();
197                 for(kw = opchar[buf[0]]; kw < optab + nelem(optab) && kw->name[0] == buf[0]; kw++)
198                         if(buf[1] == kw->name[1]){
199                                 buf[2] = getch();
200                                 buf[3] = 0;
201                                 if(kw + 1 < optab + nelem(optab) && strcmp(kw[1].name, buf) == 0)
202                                         return kw[1].tok;
203                                 ungetch();
204                                 return kw->tok;
205                         }
206                 ungetch();
207         }
208         return ch;
209 }
210
211 int
212 nodetfmt(Fmt *f)
213 {
214         int t;
215         static char *nodestr[] = {
216                 [OINVAL] "OINVAL",
217                 [OBIN] "OBIN",
218                 [OLNOT] "OLNOT",
219                 [OSYM] "OSYM",
220                 [ONUM] "ONUM",
221                 [OSTR] "OSTR",
222                 [OTERN] "OTERN",
223                 [ORECORD] "ORECORD",
224                 [OCAST] "OCAST",
225         };
226         
227         t = va_arg(f->args, int);
228         if(t >= nelem(nodestr) || nodestr[t] == nil)
229                 return fmtprint(f, "??? (%d)", t);
230         else
231                 return fmtprint(f, "%s", nodestr[t]);
232 }
233
234 Node *
235 node(int type, ...)
236 {
237         va_list va;
238         Node *n;
239         
240         n = emalloc(sizeof(Node));
241         n->type = type;
242         va_start(va, type);
243         switch(type){
244         case OBIN:
245                 n->op = va_arg(va, int);
246                 n->n1 = va_arg(va, Node *);
247                 n->n2 = va_arg(va, Node *);
248                 break;
249         case OLNOT:
250                 n->n1 = va_arg(va, Node *);
251                 break;
252         case OSYM:
253                 n->sym = va_arg(va, Symbol *);
254                 break;
255         case ONUM:
256                 n->num = va_arg(va, s64int);
257                 break;
258         case OTERN:
259                 n->n1 = va_arg(va, Node *);
260                 n->n2 = va_arg(va, Node *);
261                 n->n3 = va_arg(va, Node *);
262                 break;
263         case ORECORD:
264                 n->n1 = va_arg(va, Node *);
265                 break;
266         case OCAST:
267                 n->typ = va_arg(va, Type *);
268                 n->n1 = va_arg(va, Node *);
269                 break;
270         case OSTR:
271                 n->str = va_arg(va, char *);
272                 break;
273         default:
274                 sysfatal("node: unknown type %α", type);
275         }
276         va_end(va);
277         return n;
278 }
279
280 SymTab globals;
281
282 static u64int
283 hash(char *s)
284 {
285         u64int h;
286         
287         h = 0xcbf29ce484222325ULL;
288         for(; *s != 0; s++){
289                 h ^= *s;
290                 h *= 0x100000001b3ULL;
291         }
292         return h;
293 }
294
295 Symbol *
296 getsym(char *name)
297 {
298         u64int h;
299         Symbol **sp, *s;
300         
301         h = hash(name);
302         for(sp = &globals.sym[h % SYMHASH]; s = *sp, s != nil; sp = &s->next)
303                 if(strcmp(s->name, name) == 0)
304                         return s;
305         *sp = s = emalloc(sizeof(Symbol));
306         s->name = strdup(name);
307         return s;
308 }
309
310 int
311 typetfmt(Fmt *f)
312 {
313         int t;
314         static char *tstr[] = {
315                 [TYPINVAL] "TYPINVAL",
316                 [TYPINT] "TYPINT",
317                 [TYPPTR] "TYPPTR",
318                 [TYPSTRING] "TYPSTRING",
319         };
320         
321         t = va_arg(f->args, int);
322         if(t >= nelem(tstr) || tstr[t] == nil)
323                 return fmtprint(f, "??? (%d)", t);
324         else
325                 return fmtprint(f, "%s", tstr[t]);
326 }
327
328 int
329 typefmt(Fmt *f)
330 {
331         Type *t;
332         
333         t = va_arg(f->args, Type *);
334         switch(t->type){
335         case TYPINT: return fmtprint(f, "%c%d", t->sign ? 's' : 'u', t->size * 8);
336         case TYPSTRING: return fmtprint(f, "string");
337         case TYPPTR: return fmtprint(f, "%τ*", t->ref);
338         default: return fmtprint(f, "%t", t->type);
339         }
340 }
341
342 static Type typu8 = {.type TYPINT, .size 1, .sign 0};
343 static Type typs8 = {.type TYPINT, .size 1, .sign 1};
344 static Type typu16 = {.type TYPINT, .size 2, .sign 0};
345 static Type typs16 = {.type TYPINT, .size 2, .sign 1};
346 static Type typu32 = {.type TYPINT, .size 4, .sign 0};
347 static Type typs32 = {.type TYPINT, .size 4, .sign 1};
348 static Type typu64 = {.type TYPINT, .size 8, .sign 0};
349 static Type typs64 = {.type TYPINT, .size 8, .sign 1};
350 static Type typstr = {.type TYPSTRING, .size DTSTRMAX };
351 static Type *typereg;
352
353 static Type *
354 mkptr(Type *t)
355 {
356         Type *s;
357         
358         for(s = typereg; s != nil; s = s->typenext)
359                 if(s->type == TYPPTR && s->ref == t)
360                         return s;
361         s = emalloc(sizeof(Type));
362         s->type = TYPPTR;
363         s->ref = t;
364         return s;
365 }
366
367 Type *
368 type(int typ, ...)
369 {
370         int size, sign;
371         va_list va;
372         
373         va_start(va, typ);
374         switch(typ){
375         case TYPINT:
376                 size = va_arg(va, int);
377                 sign = va_arg(va, int);
378                 switch(size << 4 | sign){
379                 case 0x10: return &typu8;
380                 case 0x11: return &typs8;
381                 case 0x20: return &typu16;
382                 case 0x21: return &typs16;
383                 case 0x40: return &typu32;
384                 case 0x41: return &typs32;
385                 case 0x80: return &typu64;
386                 case 0x81: return &typs64;
387                 default: sysfatal("type: invalid (size,sign) = (%d,%d)\n", size, sign); return nil;
388                 }
389         case TYPSTRING: return &typstr;
390         case TYPPTR: return mkptr(va_arg(va, Type *));
391         default: sysfatal("type: unknown %t", typ); return nil;
392         }
393 }