]> mj.ucw.cz Git - umpf.git/blob - lex.c
35b5b00f67073f012ad45ad9f68e72fb75610a88
[umpf.git] / lex.c
1 #include <stdio.h>
2 #include <ctype.h>
3 #include <string.h>
4 #include <stdlib.h>
5 #include <stdarg.h>
6
7 #include "cond.tab.h"
8
9 #define BUFSIZE 4096
10 #define KLEN 10 
11
12 struct keys {
13         char* keywords;
14         enum yytokentype keytoks;
15 };
16
17 static int line;
18
19 static struct keys k[] = 
20         {       {"copy", KW_COPY},
21                 {"else", KW_ELSE},
22                 {"if", KW_IF}, 
23                 {"mail", KW_MAIL}, 
24                 {"pipe", KW_PIPE}
25         };
26
27 void __attribute__ ((noreturn)) 
28 die(char* msg, ...)
29 {
30         va_list args;
31
32         va_start(args, msg);
33         vfprintf(stderr, msg, args);
34         fputc('\n', stderr);
35         va_end(args);
36         exit(1);
37 }
38
39 void*
40 xmalloc(size_t size)
41 {
42         void* ret;
43
44         if (!(ret = malloc(size)))
45                 die("Low memory");
46
47         return ret;
48 }
49
50 static void __attribute__ ((noreturn)) 
51 parse_err(char* msg, ...)
52 {
53         va_list args;
54
55         va_start(args, msg);
56         fprintf(stderr, "Line %d: ", line);
57         vfprintf(stderr, msg, args);
58         fputc('\n', stderr);
59         va_end(args);
60         exit(1);
61 }
62
63 static char*
64 xstrdup(char* s)
65 {
66         void* ret;
67
68         if (!(ret = strdup(s)))
69                 die("Low memory");
70
71         return ret;
72 }
73
74 static char*
75 get_string_out(int delim)
76 {
77         int last = delim; 
78         int i = 0;
79         int c;
80         char buf[BUFSIZE];
81
82         while ((c = getchar()) != delim || last == '\\'){
83                 if (last=='\\' && c != delim)
84                         buf[i-1] = c;
85                 else {          
86                         buf[i] = c;
87                         i++;
88                 }
89                 last = c;
90                 if (i >= BUFSIZE-1)
91                         parse_err("Too long string, max allowed length is %d",BUFSIZE-1);       
92         }       
93         buf[i] = '\0';
94
95         return xstrdup(buf);
96 }
97
98 static int
99 is_var_id(int c)
100 {
101         return  (c >= '0' && c <= '9' ) ||
102                 (c >= 'a' && c <= 'z') ||
103                 (c >= 'A' && c <= 'Z') ||
104                 c == '_' ||
105                 c == '-'; 
106 }
107
108 static int
109 is_alpha(int c)
110 {
111         return (c >= 'a' && c <= 'z') ||
112                 (c >= 'A' && c <= 'Z');
113 }
114
115 int
116 yylex(void)
117 {
118         int c;
119         
120         while ((c = getchar ()) == ' ' || c == '\t' || c =='\n'){
121                 if (c == '\n')
122                         line++;
123         }
124         
125         if (c == EOF)
126                 return 0;
127         
128 #define CC(a,b) ((a<<8)|b)
129         int d = getchar();
130         if (d >= 0) {
131                 switch (CC(c,d)) {
132                 case CC('!','='): yylval.n = CC('!','='); return NEQ;
133                 case CC('!','~'): yylval.n = CC('!','='); return NRE;
134                 case CC('<','='): yylval.n = CC('<','='); return LE;
135                 case CC('>','='): yylval.n = CC('>','='); return GE;
136                 case CC('=','='): yylval.n = CC('=','='); return EQ;
137                 case CC('~','~'): yylval.n = CC('~','~'); return RE;
138                 case CC('-','>'): yylval.n = CC('-','>'); return ARROW;
139                 }
140                 ungetc(d,stdin);
141         }
142
143         switch (c) {
144                 case '!':
145                 case '(':
146                 case ')':
147                 case '-':
148                 case '+':
149                 case '*':
150                 case '/':
151                 case '{':
152                 case '}':
153                 case '<':
154                 case '>':
155                 case '=':
156                 case ';':
157                 case '.':
158                         yylval.n = c;
159                         return c;
160                 
161                 case '"':
162                 case '\'':
163                         yylval.str = get_string_out(c);
164                         return CONST;   
165         }
166
167         if (c >= '0' && c <= '9'){
168                 ungetc(c,stdin);
169                 scanf("%d",&yylval.n);
170                 return NUM;
171         }
172
173         if (c == '$'){
174                 int i = 0;
175                 char buf[BUFSIZE];
176         
177                 while (is_var_id(c = getchar())){
178                         buf[i]=c;
179                         i++;
180                         if (i >= BUFSIZE-1)
181                                 parse_err("Too long identifier, max allowed length is %d",BUFSIZE-1);   
182                 }
183                 ungetc(c,stdin);
184                 buf[i] = 0;
185                 yylval.str = xstrdup(buf);
186
187                 return VAR;
188         }
189
190         if (is_alpha(c)){
191                 char buf[KLEN]; 
192                 int n, i = 0;
193
194                 ungetc(c,stdin);
195                 while (is_alpha(c = getchar())){
196                         buf[i++] = c;
197                         if (i >= KLEN)
198                                 parse_err("Keyword too long");
199                 }
200                 buf[i] = 0;
201                 ungetc(c,stdin);
202
203                 n = (sizeof(k)/sizeof(struct keys));
204                 for (i = 0; i < n; i++){
205                         if (!strcmp(buf,k[i].keywords))
206                                 return k[i].keytoks;
207                 }
208
209                 parse_err("Unknown keyword %s", buf);
210         }
211
212         parse_err("Unknown character %c", c);
213 }