xref: /haiku/src/bin/rc/lexer.l (revision e221c09e508ffc3c62738140c9b6fc4fa211662a)
1*e221c09eSPhilippe Houdoin /*
2*e221c09eSPhilippe Houdoin  * Copyright (c) 2003 Matthijs Hollemans
3*e221c09eSPhilippe Houdoin  *
4*e221c09eSPhilippe Houdoin  * Permission is hereby granted, free of charge, to any person obtaining a
5*e221c09eSPhilippe Houdoin  * copy of this software and associated documentation files (the "Software"),
6*e221c09eSPhilippe Houdoin  * to deal in the Software without restriction, including without limitation
7*e221c09eSPhilippe Houdoin  * the rights to use, copy, modify, merge, publish, distribute, sublicense,
8*e221c09eSPhilippe Houdoin  * and/or sell copies of the Software, and to permit persons to whom the
9*e221c09eSPhilippe Houdoin  * Software is furnished to do so, subject to the following conditions:
10*e221c09eSPhilippe Houdoin  *
11*e221c09eSPhilippe Houdoin  * The above copyright notice and this permission notice shall be included in
12*e221c09eSPhilippe Houdoin  * all copies or substantial portions of the Software.
13*e221c09eSPhilippe Houdoin  *
14*e221c09eSPhilippe Houdoin  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
15*e221c09eSPhilippe Houdoin  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
16*e221c09eSPhilippe Houdoin  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
17*e221c09eSPhilippe Houdoin  * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
18*e221c09eSPhilippe Houdoin  * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
19*e221c09eSPhilippe Houdoin  * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
20*e221c09eSPhilippe Houdoin  * DEALINGS IN THE SOFTWARE.
21*e221c09eSPhilippe Houdoin  */
22*e221c09eSPhilippe Houdoin 
23*e221c09eSPhilippe Houdoin %{
24*e221c09eSPhilippe Houdoin //------------------------------------------------------------------------------
25*e221c09eSPhilippe Houdoin 
26*e221c09eSPhilippe Houdoin #include <stack>
27*e221c09eSPhilippe Houdoin #include <string.h>
28*e221c09eSPhilippe Houdoin 
29*e221c09eSPhilippe Houdoin #include "rdef.h"
30*e221c09eSPhilippe Houdoin #include "compile.h"
31*e221c09eSPhilippe Houdoin #include "private.h"
32*e221c09eSPhilippe Houdoin #include "parser.hpp"
33*e221c09eSPhilippe Houdoin 
34*e221c09eSPhilippe Houdoin #define LEXERROR(msg) abort_compile(RDEF_COMPILE_ERR, msg);
35*e221c09eSPhilippe Houdoin 
36*e221c09eSPhilippe Houdoin // Initial size (and increment) of lexbuf.
37*e221c09eSPhilippe Houdoin #define LEX_BUF_SIZE  (64*1024)
38*e221c09eSPhilippe Houdoin 
39*e221c09eSPhilippe Houdoin // Temporary buffer that the lexer uses to parse string and raw literals.
40*e221c09eSPhilippe Houdoin // The buffer will grow if necessary, to accommodate large data blocks.
41*e221c09eSPhilippe Houdoin static uint8* lexbuf;
42*e221c09eSPhilippe Houdoin 
43*e221c09eSPhilippe Houdoin static uint8* lexptr;   // current write position in lexbuf
44*e221c09eSPhilippe Houdoin static size_t lexsize;  // current size of the lex buffer
45*e221c09eSPhilippe Houdoin static size_t lexcnt;   // how full lexbuf currently is
46*e221c09eSPhilippe Houdoin 
47*e221c09eSPhilippe Houdoin static void resetbuf();     // resets lexptr and lexcnt
48*e221c09eSPhilippe Houdoin static void addbuf(uint8);  // appends byte to lexbuf
49*e221c09eSPhilippe Houdoin 
50*e221c09eSPhilippe Houdoin // When we encounter an #include directive, we push the current
51*e221c09eSPhilippe Houdoin // buffer, filename, and line number on the include stack, so we
52*e221c09eSPhilippe Houdoin // can resume lexing that file when we're done with the include.
53*e221c09eSPhilippe Houdoin struct include_t {
54*e221c09eSPhilippe Houdoin 	YY_BUFFER_STATE buffer;
55*e221c09eSPhilippe Houdoin 	char* filename;
56*e221c09eSPhilippe Houdoin 	int lineno;
57*e221c09eSPhilippe Houdoin };
58*e221c09eSPhilippe Houdoin 
59*e221c09eSPhilippe Houdoin static std::stack<include_t> include_stack;
60*e221c09eSPhilippe Houdoin 
61*e221c09eSPhilippe Houdoin static void open_include();
62*e221c09eSPhilippe Houdoin static void close_include();
63*e221c09eSPhilippe Houdoin 
64*e221c09eSPhilippe Houdoin //------------------------------------------------------------------------------
65*e221c09eSPhilippe Houdoin %}
66*e221c09eSPhilippe Houdoin 
67*e221c09eSPhilippe Houdoin %option noyywrap
68*e221c09eSPhilippe Houdoin %option yylineno
69*e221c09eSPhilippe Houdoin 
70*e221c09eSPhilippe Houdoin LETTER      [a-zA-Z]
71*e221c09eSPhilippe Houdoin BIN         [01]
72*e221c09eSPhilippe Houdoin OCT         [0-7]
73*e221c09eSPhilippe Houdoin DEC         [0-9]
74*e221c09eSPhilippe Houdoin HEX         [0-9a-fA-F]
75*e221c09eSPhilippe Houdoin IDENT       [a-zA-Z_][a-zA-Z0-9_]*
76*e221c09eSPhilippe Houdoin WSPACE      [ \r\t\n\f]
77*e221c09eSPhilippe Houdoin EXP         [eE][+-]?{DEC}+
78*e221c09eSPhilippe Houdoin 
79*e221c09eSPhilippe Houdoin %x COMMENT
80*e221c09eSPhilippe Houdoin %x STRDATA
81*e221c09eSPhilippe Houdoin %x RAWDATA
82*e221c09eSPhilippe Houdoin %x INCLUDE
83*e221c09eSPhilippe Houdoin 
84*e221c09eSPhilippe Houdoin %%
85*e221c09eSPhilippe Houdoin 
86*e221c09eSPhilippe Houdoin enum                     return ENUM;
87*e221c09eSPhilippe Houdoin resource                 return RESOURCE;
88*e221c09eSPhilippe Houdoin array                    return ARRAY;
89*e221c09eSPhilippe Houdoin message                  return MESSAGE;
90*e221c09eSPhilippe Houdoin archive                  return ARCHIVE;
91*e221c09eSPhilippe Houdoin type                     return RTYPE;
92*e221c09eSPhilippe Houdoin import                   return IMPORT;
93*e221c09eSPhilippe Houdoin 
94*e221c09eSPhilippe Houdoin false                    yylval.b = false; return BOOL;
95*e221c09eSPhilippe Houdoin true                     yylval.b = true;  return BOOL;
96*e221c09eSPhilippe Houdoin 
97*e221c09eSPhilippe Houdoin 0[xX]{HEX}{1,16}         { yylval.i = strtoull(yytext + 2, NULL, 16);
98*e221c09eSPhilippe Houdoin                            return INTEGER; }
99*e221c09eSPhilippe Houdoin 0{OCT}{1,24}             { yylval.i = strtoull(yytext, NULL, 8);
100*e221c09eSPhilippe Houdoin                            return INTEGER; }
101*e221c09eSPhilippe Houdoin 0[bB]{BIN}{1,64}         { yylval.i = strtoull(yytext + 2, NULL, 2);
102*e221c09eSPhilippe Houdoin                            return INTEGER; }
103*e221c09eSPhilippe Houdoin {DEC}+                   { yylval.i = strtoull(yytext, NULL, 10);
104*e221c09eSPhilippe Houdoin                            return INTEGER; }
105*e221c09eSPhilippe Houdoin '....'                   { yylval.i = (yytext[1] << 24)
106*e221c09eSPhilippe Houdoin                                     | (yytext[2] << 16)
107*e221c09eSPhilippe Houdoin                                     | (yytext[3] << 8)
108*e221c09eSPhilippe Houdoin                                     |  yytext[4];
109*e221c09eSPhilippe Houdoin                            return INTEGER; }
110*e221c09eSPhilippe Houdoin 
111*e221c09eSPhilippe Houdoin {DEC}+{EXP}              yylval.f = strtod(yytext, NULL); return FLOAT;
112*e221c09eSPhilippe Houdoin {DEC}*\.{DEC}+{EXP}?     yylval.f = strtod(yytext, NULL); return FLOAT;
113*e221c09eSPhilippe Houdoin {DEC}+\.{DEC}*{EXP}?     yylval.f = strtod(yytext, NULL); return FLOAT;
114*e221c09eSPhilippe Houdoin 
115*e221c09eSPhilippe Houdoin #{DEC}+                  { yylval.t = strtoul(yytext + 1, NULL, 10);
116*e221c09eSPhilippe Houdoin                            return TYPECODE; }
117*e221c09eSPhilippe Houdoin #0[xX]{HEX}{1,8}         { yylval.t = strtoul(yytext + 3, NULL, 16);
118*e221c09eSPhilippe Houdoin                            return TYPECODE; }
119*e221c09eSPhilippe Houdoin #'....'                  { yylval.t = (yytext[2] << 24)
120*e221c09eSPhilippe Houdoin                                     | (yytext[3] << 16)
121*e221c09eSPhilippe Houdoin                                     | (yytext[4] << 8)
122*e221c09eSPhilippe Houdoin                                     |  yytext[5];
123*e221c09eSPhilippe Houdoin                            return TYPECODE; }
124*e221c09eSPhilippe Houdoin 
125*e221c09eSPhilippe Houdoin {IDENT}                  { yylval.I = (char*) alloc_mem(yyleng + 1);
126*e221c09eSPhilippe Houdoin                            memcpy(yylval.I, yytext, yyleng + 1);
127*e221c09eSPhilippe Houdoin                            return IDENT; }
128*e221c09eSPhilippe Houdoin 
129*e221c09eSPhilippe Houdoin \"                       BEGIN(STRDATA); resetbuf();
130*e221c09eSPhilippe Houdoin <STRDATA>\"{WSPACE}+\"   /* concatenate two literals */
131*e221c09eSPhilippe Houdoin <STRDATA>\"              { BEGIN(INITIAL);
132*e221c09eSPhilippe Houdoin                            addbuf('\0');
133*e221c09eSPhilippe Houdoin                            yylval.d.type = get_type("string");
134*e221c09eSPhilippe Houdoin                            yylval.d.size = lexcnt;
135*e221c09eSPhilippe Houdoin                            yylval.d.ptr  = alloc_mem(lexcnt);
136*e221c09eSPhilippe Houdoin                            memcpy(yylval.d.ptr, lexbuf, lexcnt);
137*e221c09eSPhilippe Houdoin                            return STRING; }
138*e221c09eSPhilippe Houdoin <STRDATA>\n              LEXERROR("string not terminated")
139*e221c09eSPhilippe Houdoin <STRDATA>\\{OCT}{3}      addbuf(strtol(yytext + 1, NULL, 8));
140*e221c09eSPhilippe Houdoin <STRDATA>\\0[xX]{HEX}{2} addbuf(strtol(yytext + 3, NULL, 16));
141*e221c09eSPhilippe Houdoin <STRDATA>\\[xX]{HEX}{2}  addbuf(strtol(yytext + 2, NULL, 16));
142*e221c09eSPhilippe Houdoin <STRDATA>\\b             addbuf('\b');
143*e221c09eSPhilippe Houdoin <STRDATA>\\f             addbuf('\f');
144*e221c09eSPhilippe Houdoin <STRDATA>\\n             addbuf('\n');
145*e221c09eSPhilippe Houdoin <STRDATA>\\r             addbuf('\r');
146*e221c09eSPhilippe Houdoin <STRDATA>\\t             addbuf('\t');
147*e221c09eSPhilippe Houdoin <STRDATA>\\v             addbuf('\v');
148*e221c09eSPhilippe Houdoin <STRDATA>\\0             addbuf('\0');
149*e221c09eSPhilippe Houdoin <STRDATA>\\.             addbuf(yytext[1]);
150*e221c09eSPhilippe Houdoin <STRDATA>.               addbuf(yytext[0]);
151*e221c09eSPhilippe Houdoin 
152*e221c09eSPhilippe Houdoin $\"                      BEGIN(RAWDATA); resetbuf();
153*e221c09eSPhilippe Houdoin <RAWDATA>\"{WSPACE}+$\"  /* concatenate two literals */
154*e221c09eSPhilippe Houdoin <RAWDATA>\"              { BEGIN(INITIAL);
155*e221c09eSPhilippe Houdoin                            yylval.d.type = get_type("raw");
156*e221c09eSPhilippe Houdoin                            yylval.d.size = lexcnt;
157*e221c09eSPhilippe Houdoin                            yylval.d.ptr  = alloc_mem(lexcnt);
158*e221c09eSPhilippe Houdoin                            memcpy(yylval.d.ptr, lexbuf, lexcnt);
159*e221c09eSPhilippe Houdoin                            return RAW; }
160*e221c09eSPhilippe Houdoin <RAWDATA>\n              LEXERROR("raw data not terminated")
161*e221c09eSPhilippe Houdoin <RAWDATA>{HEX}{2}        addbuf(strtol(yytext, NULL, 16));
162*e221c09eSPhilippe Houdoin <RAWDATA>{HEX}           LEXERROR("number of characters must be even")
163*e221c09eSPhilippe Houdoin <RAWDATA>.               LEXERROR("invalid character in raw data")
164*e221c09eSPhilippe Houdoin 
165*e221c09eSPhilippe Houdoin "/*"                     BEGIN(COMMENT);  /* eat multi-line comment */
166*e221c09eSPhilippe Houdoin <COMMENT>[^*\n]*         /* eat anything that is not a '*' */
167*e221c09eSPhilippe Houdoin <COMMENT>"*"+[^*/\n]*    /* eat up '*'s not followed by '/'s */
168*e221c09eSPhilippe Houdoin <COMMENT>\n
169*e221c09eSPhilippe Houdoin <COMMENT>"*"+"/"         BEGIN(INITIAL);
170*e221c09eSPhilippe Houdoin <COMMENT><<EOF>>         LEXERROR("forgot to close /*..*/ comment")
171*e221c09eSPhilippe Houdoin 
172*e221c09eSPhilippe Houdoin "//"[^\n]*               /* eat single-line comment */
173*e221c09eSPhilippe Houdoin {WSPACE}+                /* eat whitespace */
174*e221c09eSPhilippe Houdoin 
175*e221c09eSPhilippe Houdoin \#include[ \t]+\"        BEGIN(INCLUDE);
176*e221c09eSPhilippe Houdoin <INCLUDE>[ \t]*          /* eat the whitespace */
177*e221c09eSPhilippe Houdoin <INCLUDE>[^ \t\n\"]+\"   open_include();
178*e221c09eSPhilippe Houdoin <INCLUDE>\n              LEXERROR("error in include statement")
179*e221c09eSPhilippe Houdoin <INCLUDE><<EOF>>         LEXERROR("error in include statement")
180*e221c09eSPhilippe Houdoin <<EOF>>                  { if (include_stack.empty())
181*e221c09eSPhilippe Houdoin                                yyterminate();
182*e221c09eSPhilippe Houdoin                            else
183*e221c09eSPhilippe Houdoin                                close_include(); }
184*e221c09eSPhilippe Houdoin 
185*e221c09eSPhilippe Houdoin .                        return yytext[0];
186*e221c09eSPhilippe Houdoin 
187*e221c09eSPhilippe Houdoin %%
188*e221c09eSPhilippe Houdoin //------------------------------------------------------------------------------
189*e221c09eSPhilippe Houdoin 
190*e221c09eSPhilippe Houdoin void
191*e221c09eSPhilippe Houdoin resetbuf()
192*e221c09eSPhilippe Houdoin {
193*e221c09eSPhilippe Houdoin 	lexptr = lexbuf;
194*e221c09eSPhilippe Houdoin 	lexcnt = 0;
195*e221c09eSPhilippe Houdoin }
196*e221c09eSPhilippe Houdoin 
197*e221c09eSPhilippe Houdoin 
198*e221c09eSPhilippe Houdoin void
199*e221c09eSPhilippe Houdoin addbuf(uint8 b)
200*e221c09eSPhilippe Houdoin {
201*e221c09eSPhilippe Houdoin 	if (lexcnt == lexsize) {
202*e221c09eSPhilippe Houdoin 		lexsize += LEX_BUF_SIZE;
203*e221c09eSPhilippe Houdoin 		lexbuf = (uint8*) realloc(lexbuf, lexsize);
204*e221c09eSPhilippe Houdoin 		if (lexbuf == NULL)
205*e221c09eSPhilippe Houdoin 			abort_compile(B_NO_MEMORY, "out of memory");
206*e221c09eSPhilippe Houdoin 
207*e221c09eSPhilippe Houdoin 		lexptr = lexbuf + lexcnt;
208*e221c09eSPhilippe Houdoin 	}
209*e221c09eSPhilippe Houdoin 
210*e221c09eSPhilippe Houdoin 	*lexptr++ = b;
211*e221c09eSPhilippe Houdoin 	++lexcnt;
212*e221c09eSPhilippe Houdoin }
213*e221c09eSPhilippe Houdoin 
214*e221c09eSPhilippe Houdoin 
215*e221c09eSPhilippe Houdoin void
216*e221c09eSPhilippe Houdoin open_include()
217*e221c09eSPhilippe Houdoin {
218*e221c09eSPhilippe Houdoin 	yytext[yyleng - 1] = '\0';  // remove trailing " quote
219*e221c09eSPhilippe Houdoin 
220*e221c09eSPhilippe Houdoin 	char tmpname[B_PATH_NAME_LENGTH];
221*e221c09eSPhilippe Houdoin 	if (open_file_from_include_dir(yytext, tmpname)) {
222*e221c09eSPhilippe Houdoin 		yyin = fopen(tmpname, "r");
223*e221c09eSPhilippe Houdoin 		if (yyin != NULL) {
224*e221c09eSPhilippe Houdoin 			include_t incl;
225*e221c09eSPhilippe Houdoin 			incl.buffer   = YY_CURRENT_BUFFER;
226*e221c09eSPhilippe Houdoin 			incl.lineno   = yylineno;
227*e221c09eSPhilippe Houdoin 			incl.filename = strdup(lexfile);
228*e221c09eSPhilippe Houdoin 			include_stack.push(incl);
229*e221c09eSPhilippe Houdoin 
230*e221c09eSPhilippe Houdoin 			strcpy(lexfile, tmpname);
231*e221c09eSPhilippe Houdoin 			yy_switch_to_buffer(yy_create_buffer(yyin, YY_BUF_SIZE));
232*e221c09eSPhilippe Houdoin 			yylineno = 1;
233*e221c09eSPhilippe Houdoin 
234*e221c09eSPhilippe Houdoin 			BEGIN(INITIAL);
235*e221c09eSPhilippe Houdoin 			return;
236*e221c09eSPhilippe Houdoin 		}
237*e221c09eSPhilippe Houdoin 	}
238*e221c09eSPhilippe Houdoin 
239*e221c09eSPhilippe Houdoin 	abort_compile(RDEF_COMPILE_ERR, "cannot open include %s", yytext);
240*e221c09eSPhilippe Houdoin }
241*e221c09eSPhilippe Houdoin 
242*e221c09eSPhilippe Houdoin 
243*e221c09eSPhilippe Houdoin void
244*e221c09eSPhilippe Houdoin close_include()
245*e221c09eSPhilippe Houdoin {
246*e221c09eSPhilippe Houdoin 	fclose(yyin);
247*e221c09eSPhilippe Houdoin 	yy_delete_buffer(YY_CURRENT_BUFFER);
248*e221c09eSPhilippe Houdoin 
249*e221c09eSPhilippe Houdoin 	include_t incl = include_stack.top();
250*e221c09eSPhilippe Houdoin 	include_stack.pop();
251*e221c09eSPhilippe Houdoin 
252*e221c09eSPhilippe Houdoin 	yy_switch_to_buffer(incl.buffer);
253*e221c09eSPhilippe Houdoin 	yylineno = incl.lineno;
254*e221c09eSPhilippe Houdoin 	strcpy(lexfile, incl.filename);
255*e221c09eSPhilippe Houdoin 
256*e221c09eSPhilippe Houdoin 	free(incl.filename);
257*e221c09eSPhilippe Houdoin }
258*e221c09eSPhilippe Houdoin 
259*e221c09eSPhilippe Houdoin 
260*e221c09eSPhilippe Houdoin void
261*e221c09eSPhilippe Houdoin init_lexer()
262*e221c09eSPhilippe Houdoin {
263*e221c09eSPhilippe Houdoin 	lexsize = LEX_BUF_SIZE;
264*e221c09eSPhilippe Houdoin 	lexbuf = (uint8*) malloc(lexsize);
265*e221c09eSPhilippe Houdoin 	if (lexbuf == NULL)
266*e221c09eSPhilippe Houdoin 		abort_compile(B_NO_MEMORY, "out of memory");
267*e221c09eSPhilippe Houdoin 
268*e221c09eSPhilippe Houdoin 	yyrestart(yyin);  // necessary for multiple input files
269*e221c09eSPhilippe Houdoin 	yylineno = 1;
270*e221c09eSPhilippe Houdoin }
271*e221c09eSPhilippe Houdoin 
272*e221c09eSPhilippe Houdoin 
273*e221c09eSPhilippe Houdoin void
274*e221c09eSPhilippe Houdoin clean_up_lexer()
275*e221c09eSPhilippe Houdoin {
276*e221c09eSPhilippe Houdoin 	while (!include_stack.empty()) {
277*e221c09eSPhilippe Houdoin 		close_include();
278*e221c09eSPhilippe Houdoin 	}
279*e221c09eSPhilippe Houdoin 
280*e221c09eSPhilippe Houdoin 	if (stdin != yyin)
281*e221c09eSPhilippe Houdoin 		fclose(yyin);
282*e221c09eSPhilippe Houdoin 	yy_delete_buffer(YY_CURRENT_BUFFER);
283*e221c09eSPhilippe Houdoin 
284*e221c09eSPhilippe Houdoin 	free(lexbuf);
285*e221c09eSPhilippe Houdoin }
286*e221c09eSPhilippe Houdoin 
287