summaryrefslogtreecommitdiffstats
path: root/bitbake/lib/bb/parse/parse_c/bitbakescanner.l
blob: 782bc57a0fadc64b2d329ad5b703258e0a4db3c3 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
/* bbf.flex 

   written by Marc Singer
   6 January 2005

   This program is free software; you can redistribute it and/or
   modify it under the terms of the GNU General Public License as
   published by the Free Software Foundation; either version 2 of the
   License, or (at your option) any later version.

   This program is distributed in the hope that it will be useful, but
   WITHOUT ANY WARRANTY; without even the implied warranty of
   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
   General Public License for more details.

   You should have received a copy of the GNU General Public License
   along with this program; if not, write to the Free Software
   Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
   USA.

   DESCRIPTION
   -----------

   flex lexer specification for a BitBake input file parser.

   Unfortunately, flex doesn't welcome comments within the rule sets.
   I say unfortunately because this lexer is unreasonably complex and
   comments would make the code much easier to comprehend.

   The BitBake grammar is not regular.  In order to interpret all
   of the available input files, the lexer maintains much state as it
   parses.  There are places where this lexer will emit tokens that
   are invalid.  The parser will tend to catch these. 

   The lexer requires C++ at the moment.  The only reason for this has
   to do with a very small amount of managed state.  Producing a C
   lexer should be a reasonably easy task as long as the %reentrant
   option is used.


   NOTES
   -----

   o RVALUES.  There are three kinds of RVALUES.  There are unquoted
     values, double quote enclosed strings, and single quote 
     strings.  Quoted strings may contain unescaped quotes (of either
     type), *and* any type may span more than one line by using a
     continuation '\' at the end of the line.  This requires us to
     recognize all types of values with a single expression.
     Moreover, the only reason to quote a value is to include
     trailing or leading whitespace.  Whitespace within a value is
     preserved, ugh.

   o CLASSES.  C_ patterns define classes.  Classes ought not include
     a repitition operator, instead letting the reference to the class
     define the repitition count.

     C_SS - symbol start
     C_SB - symbol body
     C_SP - whitespace

*/

%option never-interactive
%option yylineno
%option noyywrap
%option reentrant stack


%{

#include "token.h"
#include "lexer.h"
#include "bitbakeparser.h"
#include <ctype.h>

extern void *bbparseAlloc(void *(*mallocProc)(size_t));
extern void bbparseFree(void *p, void (*freeProc)(void*));
extern void *bbparseAlloc(void *(*mallocProc)(size_t));
extern void *bbparse(void*, int, token_t, lex_t*);
extern void bbparseTrace(FILE *TraceFILE, char *zTracePrompt);

//static const char* rgbInput;
//static size_t cbInput;


int lineError;
int errorParse;

enum {
  errorNone = 0,
  errorUnexpectedInput,
  errorUnsupportedFeature, 
};

#define YY_EXTRA_TYPE lex_t*

	/* Read from buffer */
#define YY_INPUT(buf,result,max_size) \
 { yyextra->input(buf, &result, max_size); }

//#define YY_DECL static size_t yylex ()

#define ERROR(e) \
  do { lineError = yylineno; errorParse = e; yyterminate (); } while (0)

static const char* fixup_escapes (const char* sz);

%}


C_SP            [ \t]
COMMENT         #.*\n
OP_ASSIGN       "="
OP_IMMEDIATE    ":="
OP_PREPEND      "=+"
OP_APPEND       "+="
OP_COND         "?="
B_OPEN          "{"
B_CLOSE         "}"

K_ADDTASK       "addtask"
K_ADDHANDLER    "addhandler"
K_AFTER         "after"
K_BEFORE        "before"
K_DEF           "def"
K_INCLUDE       "include"
K_REQUIRE       "require"
K_INHERIT       "inherit"
K_PYTHON        "python"
K_FAKEROOT      "fakeroot"
K_EXPORT        "export"
K_EXPORT_FUNC   "EXPORT_FUNCTIONS"

STRING          \"([^\n\r]|"\\\n")*\"
SSTRING         \'([^\n\r]|"\\\n")*\'
VALUE           ([^'" \t\n])|([^'" \t\n]([^\n]|(\\\n))*[^'" \t\n])

C_SS            [a-zA-Z_]
C_SB            [a-zA-Z0-9_+-.]
REF             $\{{C_SS}{C_SB}*\}
SYMBOL          {C_SS}{C_SB}*
VARIABLE        $?{C_SS}({C_SB}*|{REF})*(\[[a-zA-Z0-9_]*\])?
FILENAME        ([a-zA-Z_./]|{REF})(([-+a-zA-Z0-9_./]*)|{REF})*

PROC            \({C_SP}*\)

%s S_DEF
%s S_DEF_ARGS
%s S_DEF_BODY
%s S_FUNC
%s S_INCLUDE
%s S_INHERIT
%s S_REQUIRE
%s S_PROC
%s S_RVALUE
%s S_TASK

%%

{OP_APPEND}                     { BEGIN S_RVALUE;
                                  yyextra->accept (T_OP_APPEND); }
{OP_PREPEND}                    { BEGIN S_RVALUE;
                                  yyextra->accept (T_OP_PREPEND); }
{OP_IMMEDIATE}                  { BEGIN S_RVALUE;
                                  yyextra->accept (T_OP_IMMEDIATE); }
{OP_ASSIGN}                     { BEGIN S_RVALUE;
                                  yyextra->accept (T_OP_ASSIGN); }
{OP_COND}                       { BEGIN S_RVALUE;
                                  yyextra->accept (T_OP_COND); }

<S_RVALUE>\\\n{C_SP}*           {  }
<S_RVALUE>{STRING}              { BEGIN INITIAL;
                                  size_t cb = yyleng;
                                  while (cb && isspace (yytext[cb - 1]))
                                      --cb;
                                  yytext[cb - 1] = 0;
                                  yyextra->accept (T_STRING, yytext + 1); }
<S_RVALUE>{SSTRING}             { BEGIN INITIAL;
                                  size_t cb = yyleng;
                                  while (cb && isspace (yytext[cb - 1]))
                                      --cb;
                                  yytext[cb - 1] = 0;
                                  yyextra->accept (T_STRING, yytext + 1); }

<S_RVALUE>{VALUE}               { ERROR (errorUnexpectedInput);  }
<S_RVALUE>{C_SP}*\n+            { BEGIN INITIAL;
                                  yyextra->accept (T_STRING, NULL); }

{K_INCLUDE}                     { BEGIN S_INCLUDE;
                                  yyextra->accept (T_INCLUDE); }
{K_REQUIRE}                     { BEGIN S_REQUIRE;
                                  yyextra->accept (T_REQUIRE); }
{K_INHERIT}                     { BEGIN S_INHERIT;
                                  yyextra->accept (T_INHERIT); }
{K_ADDTASK}                     { BEGIN S_TASK;
                                  yyextra->accept (T_ADDTASK); }
{K_ADDHANDLER}                  { yyextra->accept (T_ADDHANDLER); }
{K_EXPORT_FUNC}                 { BEGIN S_FUNC;
                                  yyextra->accept (T_EXPORT_FUNC); }
<S_TASK>{K_BEFORE}              { yyextra->accept (T_BEFORE); }
<S_TASK>{K_AFTER}               { yyextra->accept (T_AFTER); }
<INITIAL>{K_EXPORT}             { yyextra->accept (T_EXPORT); }

<INITIAL>{K_FAKEROOT}           { yyextra->accept (T_FAKEROOT); }
<INITIAL>{K_PYTHON}             { yyextra->accept (T_PYTHON); }
{PROC}{C_SP}*{B_OPEN}{C_SP}*\n*  { BEGIN S_PROC;
                                  yyextra->accept (T_PROC_OPEN); }
<S_PROC>{B_CLOSE}{C_SP}*\n*      { BEGIN INITIAL;
                                  yyextra->accept (T_PROC_CLOSE); }
<S_PROC>([^}][^\n]*)?\n*        { yyextra->accept (T_PROC_BODY, yytext); }

{K_DEF}                         { BEGIN S_DEF; }
<S_DEF>{SYMBOL}                 { BEGIN S_DEF_ARGS;
                                  yyextra->accept (T_SYMBOL, yytext); }
<S_DEF_ARGS>[^\n:]*:            { yyextra->accept (T_DEF_ARGS, yytext); }
<S_DEF_ARGS>{C_SP}*\n           { BEGIN S_DEF_BODY; }
<S_DEF_BODY>{C_SP}+[^\n]*\n     { yyextra->accept (T_DEF_BODY, yytext); }
<S_DEF_BODY>\n                  { yyextra->accept (T_DEF_BODY, yytext); }
<S_DEF_BODY>.                   { BEGIN INITIAL; unput (yytext[0]); }

{COMMENT}                       { }

<INITIAL>{SYMBOL}               { yyextra->accept (T_SYMBOL, yytext); }
<INITIAL>{VARIABLE}             { yyextra->accept (T_VARIABLE, yytext); }

<S_TASK>{SYMBOL}                { yyextra->accept (T_TSYMBOL, yytext); }
<S_FUNC>{SYMBOL}                { yyextra->accept (T_FSYMBOL, yytext); }
<S_INHERIT>{SYMBOL}             { yyextra->accept (T_ISYMBOL, yytext); }
<S_INCLUDE>{FILENAME}           { BEGIN INITIAL;
                                  yyextra->accept (T_ISYMBOL, yytext); }
<S_REQUIRE>{FILENAME}           { BEGIN INITIAL;
                                  yyextra->accept (T_ISYMBOL, yytext); }
<S_TASK>\n                      { BEGIN INITIAL; }
<S_FUNC>\n                      { BEGIN INITIAL; }
<S_INHERIT>\n                   { BEGIN INITIAL; }

[ \t\r\n]                       /* Insignificant whitespace */

.                               { ERROR (errorUnexpectedInput); }

                                /* Check for premature termination */
<<EOF>>                         { return T_EOF; }

%%

void lex_t::accept (int token, const char* sz) 
{
    token_t t;
    memset (&t, 0, sizeof (t));
    t.copyString(sz);

    /* tell lemon to parse the token */
    parse (parser, token, t, this);
}

int lex_t::line ()const
{
    return yyget_lineno (scanner);
}

void parse (FILE* file, PyObject* data)
{
    void* parser = bbparseAlloc (malloc);
    yyscan_t scanner;
    lex_t lex;

    yylex_init (&scanner);

    lex.parser = parser;
    lex.scanner = scanner;
    lex.file = file;
    lex.data = data;
    lex.parse = bbparse;
    yyset_extra (&lex, scanner);


    int result = yylex (scanner);

    lex.accept (0);
    bbparseTrace (NULL, NULL);

    if (result != T_EOF)
        printf ("premature end of file\n");

    yylex_destroy (scanner);
    bbparseFree (parser, free);
}