blob: 80896d11f253d5bf5c97eacc108edd8efbe5799b [file] [log] [blame]
The Android Open Source Projectc24a8e62009-03-03 19:28:42 -08001/*
2 * Copyright (C) 2007 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17%{
18 #include <stdio.h>
19 #include <stdlib.h>
20 #include "ast.h"
21 #include "lexer.h"
22 #include "parser.h"
23
24 const char *tokenToString(int token)
25 {
26 static char scratch[128];
27
28 switch (token) {
29 case TOK_AND:
30 return "&&";
31 case TOK_OR:
32 return "||";
33 case TOK_EQ:
34 return "==";
35 case TOK_NE:
36 return "!=";
37 case TOK_GE:
38 return ">=";
39 case TOK_LE:
40 return "<=";
41 case TOK_EOF:
42 return "EOF";
43 case TOK_EOL:
44 return "EOL\n";
45 case TOK_STRING:
46 snprintf(scratch, sizeof(scratch),
47 "STRING<%s>", yylval.literalString);
48 return scratch;
49 case TOK_IDENTIFIER:
50 snprintf(scratch, sizeof(scratch), "IDENTIFIER<%s>",
51 yylval.literalString);
52 return scratch;
53 case TOK_WORD:
54 snprintf(scratch, sizeof(scratch), "WORD<%s>",
55 yylval.literalString);
56 return scratch;
57 default:
58 if (token > ' ' && token <= '~') {
59 scratch[0] = (char)token;
60 scratch[1] = '\0';
61 } else {
62 snprintf(scratch, sizeof(scratch), "??? <%d>", token);
63 }
64 return scratch;
65 }
66 }
67
68 typedef struct {
69 char *value;
70 char *nextc;
71 unsigned int alloc_size;
72 } AmString;
73
74 static int addCharToString(AmString *str, char c)
75 {
76 if ((unsigned int)(str->nextc - str->value) >= str->alloc_size) {
77 char *new_value;
78 unsigned int new_size;
79
80 new_size = (str->alloc_size + 1) * 2;
81 if (new_size < 64) {
82 new_size = 64;
83 }
84
85 new_value = (char *)realloc(str->value, new_size);
86 if (new_value == NULL) {
87 yyerror("out of memory");
88 return -1;
89 }
90 str->nextc = str->nextc - str->value + new_value;
91 str->value = new_value;
92 str->alloc_size = new_size;
93 }
94 *str->nextc++ = c;
95 return 0;
96 }
97
98 static int setString(AmString *str, const char *p)
99 {
100 str->nextc = str->value;
101 while (*p != '\0') {
102//TODO: add the whole string at once
103 addCharToString(str, *p++);
104 }
105 return addCharToString(str, '\0');
106 }
107
108 static AmString gStr = { NULL, NULL, 0 };
109 static int gLineNumber = 1;
110 static AmArgumentType gArgumentType = AM_UNKNOWN_ARGS;
111 static const char *gErrorMessage = NULL;
112
113#if AMEND_LEXER_BUFFER_INPUT
114 static const char *gInputBuffer;
115 static const char *gInputBufferNext;
116 static const char *gInputBufferEnd;
117
118# define YY_INPUT(buf, result, max_size) \
119 do { \
120 int nbytes = gInputBufferEnd - gInputBufferNext; \
121 if (nbytes > 0) { \
122 if (nbytes > max_size) { \
123 nbytes = max_size; \
124 } \
125 memcpy(buf, gInputBufferNext, nbytes); \
126 gInputBufferNext += nbytes; \
127 result = nbytes; \
128 } else { \
129 result = YY_NULL; \
130 } \
131 } while (false)
132#endif // AMEND_LEXER_BUFFER_INPUT
133
134%}
135
136%option noyywrap
137
138%x QUOTED_STRING BOOLEAN WORDS
139
140ident [a-zA-Z_][a-zA-Z_0-9]*
141word [^ \t\r\n"]+
142
143%%
144 /* This happens at the beginning of each call to yylex().
145 */
146 if (gArgumentType == AM_WORD_ARGS) {
147 BEGIN(WORDS);
148 } else if (gArgumentType == AM_BOOLEAN_ARGS) {
149 BEGIN(BOOLEAN);
150 }
151
152 /*xxx require everything to be 7-bit-clean, printable characters */
153<INITIAL>{
154 {ident}/[ \t\r\n] {
155 /* The only token we recognize in the initial
156 * state is an identifier followed by whitespace.
157 */
158 setString(&gStr, yytext);
159 yylval.literalString = gStr.value;
160 return TOK_IDENTIFIER;
161 }
162 }
163
164<BOOLEAN>{
165 {ident} {
166 /* Non-quoted identifier-style string */
167 setString(&gStr, yytext);
168 yylval.literalString = gStr.value;
169 return TOK_IDENTIFIER;
170 }
171 "&&" return TOK_AND;
172 "||" return TOK_OR;
173 "==" return TOK_EQ;
174 "!=" return TOK_NE;
175 ">=" return TOK_GE;
176 "<=" return TOK_LE;
177 [<>()!,] return yytext[0];
178 }
179
180 /* Double-quoted string handling */
181
182<WORDS,BOOLEAN>\" {
183 /* Initial quote */
184 gStr.nextc = gStr.value;
185 BEGIN(QUOTED_STRING);
186 }
187
188<QUOTED_STRING>{
189 \" {
190 /* Closing quote */
191 BEGIN(INITIAL);
192 addCharToString(&gStr, '\0');
193 yylval.literalString = gStr.value;
194 if (gArgumentType == AM_WORD_ARGS) {
195 return TOK_WORD;
196 } else {
197 return TOK_STRING;
198 }
199 }
200
201 <<EOF>> |
202 \n {
203 /* Unterminated string */
204 yyerror("unterminated string");
205 return TOK_ERROR;
206 }
207
208 \\\" {
209 /* Escaped quote */
210 addCharToString(&gStr, '"');
211 }
212
213 \\\\ {
214 /* Escaped backslash */
215 addCharToString(&gStr, '\\');
216 }
217
218 \\. {
219 /* No other escapes allowed. */
220 gErrorMessage = "illegal escape";
221 return TOK_ERROR;
222 }
223
224 [^\\\n\"]+ {
225 /* String contents */
226 char *p = yytext;
227 while (*p != '\0') {
228 /* TODO: add the whole string at once */
229 addCharToString(&gStr, *p++);
230 }
231 }
232 }
233
234<WORDS>{
235 /*xxx look out for backslashes; escape backslashes and quotes */
236 /*xxx if a quote is right against a char, we should append */
237 {word} {
238 /* Whitespace-separated word */
239 setString(&gStr, yytext);
240 yylval.literalString = gStr.value;
241 return TOK_WORD;
242 }
243 }
244
245<INITIAL,WORDS,BOOLEAN>{
246 \n {
247 /* Count lines */
248 gLineNumber++;
249 gArgumentType = AM_UNKNOWN_ARGS;
250 BEGIN(INITIAL);
251 return TOK_EOL;
252 }
253
254 /*xxx backslashes to extend lines? */
255 /* Skip whitespace and comments.
256 */
257 [ \t\r]+ ;
258 #.* ;
259
260 . {
261 /* Fail on anything we didn't expect. */
262 gErrorMessage = "unexpected character";
263 return TOK_ERROR;
264 }
265 }
266%%
267
268void
269yyerror(const char *msg)
270{
271 if (!strcmp(msg, "syntax error") && gErrorMessage != NULL) {
272 msg = gErrorMessage;
273 gErrorMessage = NULL;
274 }
275 fprintf(stderr, "line %d: %s at '%s'\n", gLineNumber, msg, yytext);
276}
277
278#if AMEND_LEXER_BUFFER_INPUT
279void
280setLexerInputBuffer(const char *buf, size_t buflen)
281{
282 gLineNumber = 1;
283 gInputBuffer = buf;
284 gInputBufferNext = gInputBuffer;
285 gInputBufferEnd = gInputBuffer + buflen;
286}
287#endif // AMEND_LEXER_BUFFER_INPUT
288
289void
290setLexerArgumentType(AmArgumentType type)
291{
292 gArgumentType = type;
293}
294
295int
296getLexerLineNumber(void)
297{
298 return gLineNumber;
299}