1 %{
2 /*
3 conf-lex.l - Part of libsensors, a Linux library for reading sensor data.
4 Copyright (c) 1998, 1999 Frodo Looijaard <frodol@dds.nl>
6 This library is free software; you can redistribute it and/or
7 modify it under the terms of the GNU Lesser General Public
8 License as published by the Free Software Foundation; either
9 version 2.1 of the License, or (at your option) any later version.
11 This library is distributed in the hope that it will be useful,
12 but WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 GNU Lesser General Public License for more details.
16 You should have received a copy of the GNU General Public License
17 along with this program; if not, write to the Free Software
18 Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
19 MA 02110-1301 USA.
20 */
22 #include <stdlib.h>
23 #include <string.h>
25 #include "general.h"
26 #include "data.h"
27 #include "conf-parse.h"
28 #include "error.h"
29 #include "scanner.h"
31 static int buffer_count;
32 static int buffer_max;
33 static char *buffer;
35 char sensors_lex_error[100];
37 const char *sensors_yyfilename;
38 int sensors_yylineno;
40 #define buffer_malloc() sensors_malloc_array(&buffer,&buffer_count,\
41 &buffer_max,1)
42 #define buffer_free() sensors_free_array(&buffer,&buffer_count,\
43 &buffer_max)
44 #define buffer_add_char(c) sensors_add_array_el(c,&buffer,\
45 &buffer_count,\
46 &buffer_max,1)
47 #define buffer_add_string(s) sensors_add_array_els(s,strlen(s),\
48 &buffer, \
49 &buffer_count,&buffer_max,1)
51 %}
53 /* Scanner for configuration files */
55 %option nodefault
56 %option noyywrap
57 %option nounput
59 /* All states are exclusive */
61 %x MIDDLE
62 %x STRING
63 %x ERR
65 /* Any whitespace-like character */
67 BLANK [ \f\r\t\v]
69 IDCHAR [[:alnum:]_]
71 /* Note: `10', `10.4' and `.4' are valid, `10.' is not */
73 FLOAT [[:digit:]]*\.?[[:digit:]]+
75 /* Only positive whole numbers are recognized here */
77 NUM 0|([1-9][[:digit:]]*)
80 %%
82 /*
83 * STATE: INITIAL
84 */
86 <INITIAL>{
88 <<EOF>> { /* EOF from this state terminates */
89 return 0;
90 }
92 {BLANK}+ ; /* eat as many blanks as possible at once */
94 {BLANK}*\n { /* eat a bare newline (possibly preceded by blanks) */
95 sensors_yylineno++;
96 }
98 /* comments */
100 #.* ; /* eat the rest of the line after comment char */
102 #.*\n { /* eat the rest of the line after comment char */
103 sensors_yylineno++;
104 }
106 /*
107 * Keywords must be followed by whitespace - eat that too.
108 * If there isn't trailing whitespace, we still need to
109 * accept it as lexically correct (even though the parser
110 * will reject it anyway.)
111 */
113 label{BLANK}* {
114 sensors_yylval.line.filename = sensors_yyfilename;
115 sensors_yylval.line.lineno = sensors_yylineno;
116 BEGIN(MIDDLE);
117 return LABEL;
118 }
120 set{BLANK}* {
121 sensors_yylval.line.filename = sensors_yyfilename;
122 sensors_yylval.line.lineno = sensors_yylineno;
123 BEGIN(MIDDLE);
124 return SET;
125 }
127 compute{BLANK}* {
128 sensors_yylval.line.filename = sensors_yyfilename;
129 sensors_yylval.line.lineno = sensors_yylineno;
130 BEGIN(MIDDLE);
131 return COMPUTE;
132 }
134 bus{BLANK}* {
135 sensors_yylval.line.filename = sensors_yyfilename;
136 sensors_yylval.line.lineno = sensors_yylineno;
137 BEGIN(MIDDLE);
138 return BUS;
139 }
141 chip{BLANK}* {
142 sensors_yylval.line.filename = sensors_yyfilename;
143 sensors_yylval.line.lineno = sensors_yylineno;
144 BEGIN(MIDDLE);
145 return CHIP;
146 }
148 ignore{BLANK}* {
149 sensors_yylval.line.filename = sensors_yyfilename;
150 sensors_yylval.line.lineno = sensors_yylineno;
151 BEGIN(MIDDLE);
152 return IGNORE;
153 }
155 /* Anything else at the beginning of a line is an error */
157 [a-z]+ |
158 . {
159 BEGIN(ERR);
160 strcpy(sensors_lex_error,"Invalid keyword");
161 return ERROR;
162 }
163 }
165 /*
166 * STATE: ERROR
167 */
169 <ERR>{
171 .* ; /* eat whatever is left on this line */
173 \n {
174 BEGIN(INITIAL);
175 sensors_yylineno++;
176 return EOL;
177 }
178 }
180 /*
181 * STATE: MIDDLE
182 */
184 <MIDDLE>{
186 {BLANK}+ ; /* eat as many blanks as possible at once */
188 \n { /* newline here sends EOL token to parser */
189 BEGIN(INITIAL);
190 sensors_yylineno++;
191 return EOL;
192 }
194 <<EOF>> { /* EOF here sends EOL token to parser also */
195 BEGIN(INITIAL);
196 return EOL;
197 }
199 \\{BLANK}*\n { /* eat an escaped newline with no state change */
200 sensors_yylineno++;
201 }
203 /* comments */
205 #.* ; /* eat the rest of the line after comment char */
207 #.*\n { /* eat the rest of the line after comment char */
208 BEGIN(INITIAL);
209 sensors_yylineno++;
210 return EOL;
211 }
213 /* A number */
215 {FLOAT} {
216 sensors_yylval.value = atof(sensors_yytext);
217 return FLOAT;
218 }
220 /* Some operators */
222 "+" return '+';
223 "-" return '-';
224 "*" return '*';
225 "/" return '/';
226 "(" return '(';
227 ")" return ')';
228 "," return ',';
229 "@" return '@';
230 "^" return '^';
231 "`" return '`';
233 /* Quoted string */
235 \" {
236 buffer_malloc();
237 BEGIN(STRING);
238 }
240 /* A normal, unquoted identifier */
242 {IDCHAR}+ {
243 sensors_yylval.name = strdup(sensors_yytext);
244 if (! sensors_yylval.name)
245 sensors_fatal_error("conf-lex.l",
246 "Allocating a new string");
248 return NAME;
249 }
251 /* anything else is bogus */
253 . |
254 [[:digit:]]*\. |
255 \\{BLANK}* {
256 BEGIN(ERR);
257 return ERROR;
258 }
259 }
261 /*
262 * STATE: STRING
263 */
265 <STRING>{
267 /* Oops, newline or EOF while in a string is not good */
269 \n |
270 \\\n {
271 buffer_add_char("\0");
272 strcpy(sensors_lex_error,
273 "No matching double quote.");
274 buffer_free();
275 yyless(0);
276 BEGIN(ERR);
277 return ERROR;
278 }
280 <<EOF>> {
281 strcpy(sensors_lex_error,
282 "Reached end-of-file without a matching double quote.");
283 buffer_free();
284 BEGIN(MIDDLE);
285 return ERROR;
286 }
288 /* At the end */
290 \"\" {
291 buffer_add_char("\0");
292 strcpy(sensors_lex_error,
293 "Quoted strings must be separated by whitespace.");
294 buffer_free();
295 BEGIN(ERR);
296 return ERROR;
297 }
299 \" {
300 buffer_add_char("\0");
301 sensors_yylval.name = strdup(buffer);
302 if (! sensors_yylval.name)
303 sensors_fatal_error("conf-lex.l",
304 "Allocating a new string");
305 buffer_free();
306 BEGIN(MIDDLE);
307 return NAME;
308 }
310 \\a buffer_add_char("\a");
311 \\b buffer_add_char("\b");
312 \\f buffer_add_char("\f");
313 \\n buffer_add_char("\n");
314 \\r buffer_add_char("\r");
315 \\t buffer_add_char("\t");
316 \\v buffer_add_char("\v");
318 /* Other escapes: just copy the character behind the slash */
320 \\. {
321 buffer_add_char(&sensors_yytext[1]);
322 }
324 /* Anything else (including a bare '\' which may be followed by EOF) */
326 \\ |
327 [^\\\n\"]+ {
328 buffer_add_string(sensors_yytext);
329 }
330 }
332 %%
334 /*
335 Do the buffer handling manually. This allows us to scan as many
336 config files as we need to, while cleaning up properly after each
337 one. The "BEGIN(0)" line ensures that we start in the default state,
338 even if e.g. the previous config file was syntactically broken.
340 Returns 0 if successful, !0 otherwise.
341 */
343 static YY_BUFFER_STATE scan_buf = (YY_BUFFER_STATE)0;
345 int sensors_scanner_init(FILE *input, const char *filename)
346 {
347 BEGIN(0);
348 if (!(scan_buf = sensors_yy_create_buffer(input, YY_BUF_SIZE)))
349 return -1;
351 sensors_yy_switch_to_buffer(scan_buf);
352 sensors_yyfilename = filename;
353 sensors_yylineno = 1;
354 return 0;
355 }
357 void sensors_scanner_exit(void)
358 {
359 sensors_yy_delete_buffer(scan_buf);
360 scan_buf = (YY_BUFFER_STATE)0;
362 /* As of flex 2.5.9, yylex_destroy() must be called when done with the
363 scaller, otherwise we'll leak memory. */
364 #if defined(YY_FLEX_MAJOR_VERSION) && defined(YY_FLEX_MINOR_VERSION) && defined(YY_FLEX_SUBMINOR_VERSION)
365 #if YY_FLEX_MAJOR_VERSION > 2 || \
366 (YY_FLEX_MAJOR_VERSION == 2 && (YY_FLEX_MINOR_VERSION > 5 || \
367 (YY_FLEX_MINOR_VERSION == 5 && YY_FLEX_SUBMINOR_VERSION >= 9)))
368 sensors_yylex_destroy();
369 #endif
370 #endif
371 }