1/*
2 * Copyright 1993, 2000 Christopher Seiwald.
3 *
4 * This file is part of Jam - see jam.c for Copyright information.
5 */
6
7/*  This file is ALSO:
8 *  Copyright 2001-2004 David Abrahams.
9 *  Distributed under the Boost Software License, Version 1.0.
10 *  (See accompanying file LICENSE_1_0.txt or http://www.boost.org/LICENSE_1_0.txt)
11 */
12
13/*
14 * jamgram.yy - jam grammar
15 *
16 * 04/13/94 (seiwald) - added shorthand L0 for null list pointer
17 * 06/01/94 (seiwald) - new 'actions existing' does existing sources
18 * 08/23/94 (seiwald) - Support for '+=' (append to variable)
19 * 08/31/94 (seiwald) - Allow ?= as alias for "default =".
20 * 09/15/94 (seiwald) - if conditionals take only single arguments, so
21 *			that 'if foo == bar' gives syntax error (use =).
22 * 02/11/95 (seiwald) - when scanning arguments to rules, only treat
23 *			punctuation keywords as keywords.  All arg lists
24 *			are terminated with punctuation keywords.
25 *
26 * 09/11/00 (seiwald) - Support for function calls:
27 *
28 *		Rules now return lists (LIST *), rather than void.
29 *
30 *		New "[ rule ]" syntax evals rule into a LIST.
31 *
32 *		Lists are now generated by compile_list() and
33 *		compile_append(), and any other rule that indirectly
34 *		makes a list, rather than being built directly here,
35 *		so that lists values can contain rule evaluations.
36 *
37 *		New 'return' rule sets the return value, though
38 *		other statements also may have return values.
39 *
40 *		'run' production split from 'block' production so
41 *		that empty blocks can be handled separately.
42 */
43
44%token ARG STRING
45
46%left `||` `|`
47%left `&&` `&`
48%left `=` `!=` `in`
49%left `<` `<=` `>` `>=`
50%left `!`
51
52%{
53#include "jam.h"
54
55#include "lists.h"
56#include "parse.h"
57#include "scan.h"
58#include "compile.h"
59#include "object.h"
60#include "rules.h"
61
62# define YYINITDEPTH 5000 /* for C++ parsing */
63# define YYMAXDEPTH 10000	/* for OSF and other less endowed yaccs */
64
65# define F0 -1
66# define P0 (PARSE *)0
67# define S0 (OBJECT *)0
68
69# define pappend( l,r )    	parse_make( PARSE_APPEND,l,r,P0,S0,S0,0 )
70# define peval( c,l,r )	parse_make( PARSE_EVAL,l,r,P0,S0,S0,c )
71# define pfor( s,l,r,x )    	parse_make( PARSE_FOREACH,l,r,P0,s,S0,x )
72# define pif( l,r,t )	  	parse_make( PARSE_IF,l,r,t,S0,S0,0 )
73# define pincl( l )       	parse_make( PARSE_INCLUDE,l,P0,P0,S0,S0,0 )
74# define plist( s )	  	parse_make( PARSE_LIST,P0,P0,P0,s,S0,0 )
75# define plocal( l,r,t )  	parse_make( PARSE_LOCAL,l,r,t,S0,S0,0 )
76# define pmodule( l,r )	  	parse_make( PARSE_MODULE,l,r,P0,S0,S0,0 )
77# define pclass( l,r )	  	parse_make( PARSE_CLASS,l,r,P0,S0,S0,0 )
78# define pnull()	  	parse_make( PARSE_NULL,P0,P0,P0,S0,S0,0 )
79# define pon( l,r )	  	parse_make( PARSE_ON,l,r,P0,S0,S0,0 )
80# define prule( s,p )     	parse_make( PARSE_RULE,p,P0,P0,s,S0,0 )
81# define prules( l,r )	  	parse_make( PARSE_RULES,l,r,P0,S0,S0,0 )
82# define pset( l,r,a )          parse_make( PARSE_SET,l,r,P0,S0,S0,a )
83# define pset1( l,r,t,a )	parse_make( PARSE_SETTINGS,l,r,t,S0,S0,a )
84# define psetc( s,p,a,l )     	parse_make( PARSE_SETCOMP,p,a,P0,s,S0,l )
85# define psete( s,l,s1,f ) 	parse_make( PARSE_SETEXEC,l,P0,P0,s,s1,f )
86# define pswitch( l,r )   	parse_make( PARSE_SWITCH,l,r,P0,S0,S0,0 )
87# define pwhile( l,r )   	parse_make( PARSE_WHILE,l,r,P0,S0,S0,0 )
88# define preturn( l )       parse_make( PARSE_RETURN,l,P0,P0,S0,S0,0 )
89# define pbreak()           parse_make( PARSE_BREAK,P0,P0,P0,S0,S0,0 )
90# define pcontinue()        parse_make( PARSE_CONTINUE,P0,P0,P0,S0,S0,0 )
91
92# define pnode( l,r )    	parse_make( F0,l,r,P0,S0,S0,0 )
93# define psnode( s,l )     	parse_make( F0,l,P0,P0,s,S0,0 )
94
95%}
96
97%%
98
99run	: /* empty */
100		/* do nothing */
101	| rules
102		{ parse_save( $1.parse ); }
103	;
104
105/*
106 * block - zero or more rules
107 * rules - one or more rules
108 * rule - any one of jam's rules
109 * right-recursive so rules execute in order.
110 */
111
112block	: null
113                { $$.parse = $1.parse; }
114	| rules
115		{ $$.parse = $1.parse; }
116	;
117
118rules	: rule
119		{ $$.parse = $1.parse; }
120	| rule rules
121		{ $$.parse = prules( $1.parse, $2.parse ); }
122	| `local` { yymode( SCAN_ASSIGN ); } list assign_list_opt `;` { yymode( SCAN_NORMAL ); } block
123		{ $$.parse = plocal( $3.parse, $4.parse, $7.parse ); }
124	;
125
126null    : /* empty */
127        { $$.parse = pnull(); }
128        ;
129
130assign_list_opt : `=` { yymode( SCAN_PUNCT ); } list
131                { $$.parse = $3.parse; $$.number = ASSIGN_SET; }
132        | null
133		{ $$.parse = $1.parse; $$.number = ASSIGN_APPEND; }
134        ;
135
136arglist_opt : `(` lol `)`
137                { $$.parse = $2.parse; }
138        |
139                { $$.parse = P0; }
140        ;
141
142local_opt : `local`
143                { $$.number = 1; }
144          | /* empty */
145                { $$.number = 0; }
146          ;
147
148else_opt : `else` rule
149                { $$.parse = $2.parse; }
150          | /* empty */
151                { $$.parse = pnull(); }
152
153rule	: `{` block `}`
154		{ $$.parse = $2.parse; }
155	| `include` { yymode( SCAN_PUNCT ); } list `;`
156		{ $$.parse = pincl( $3.parse ); yymode( SCAN_NORMAL ); }
157	| ARG { yymode( SCAN_PUNCT ); } lol `;`
158		{ $$.parse = prule( $1.string, $3.parse ); yymode( SCAN_NORMAL ); }
159	| arg assign { yymode( SCAN_PUNCT ); } list `;`
160		{ $$.parse = pset( $1.parse, $4.parse, $2.number ); yymode( SCAN_NORMAL ); }
161	| arg `on` { yymode( SCAN_ASSIGN ); } list assign { yymode( SCAN_PUNCT ); } list `;`
162		{ $$.parse = pset1( $1.parse, $4.parse, $7.parse, $5.number ); yymode( SCAN_NORMAL ); }
163	| `return` { yymode( SCAN_PUNCT ); } list `;`
164		{ $$.parse = preturn( $3.parse ); yymode( SCAN_NORMAL ); }
165    | `break` `;`
166        { $$.parse = pbreak(); }
167    | `continue` `;`
168        { $$.parse = pcontinue(); }
169	| `for` local_opt ARG `in` { yymode( SCAN_PUNCT ); } list `{` { yymode( SCAN_NORMAL ); } block `}`
170		{ $$.parse = pfor( $3.string, $6.parse, $9.parse, $2.number ); }
171	| `switch` { yymode( SCAN_PUNCT ); } list `{` { yymode( SCAN_NORMAL ); } cases `}`
172		{ $$.parse = pswitch( $3.parse, $6.parse ); }
173	| `if` { yymode( SCAN_CONDB ); } expr `{` { yymode( SCAN_NORMAL ); } block `}` else_opt
174		{ $$.parse = pif( $3.parse, $6.parse, $8.parse ); }
175	| `module` { yymode( SCAN_PUNCT ); } list `{` { yymode( SCAN_NORMAL ); } block `}`
176		{ $$.parse = pmodule( $3.parse, $6.parse ); }
177	| `class` { yymode( SCAN_PUNCT ); } lol `{` { yymode( SCAN_NORMAL ); } block `}`
178		{ $$.parse = pclass( $3.parse, $6.parse ); }
179	| `while` { yymode( SCAN_CONDB ); } expr { yymode( SCAN_NORMAL ); } `{` block `}`
180		{ $$.parse = pwhile( $3.parse, $6.parse ); }
181     | local_opt `rule` { yymode( SCAN_PUNCT ); } ARG { yymode( SCAN_PARAMS ); } arglist_opt { yymode( SCAN_NORMAL ); } rule
182		{ $$.parse = psetc( $4.string, $8.parse, $6.parse, $1.number ); }
183	| `on` arg rule
184		{ $$.parse = pon( $2.parse, $3.parse ); }
185	| `actions` eflags ARG bindlist `{`
186		{ yymode( SCAN_STRING ); }
187	  STRING
188		{ yymode( SCAN_NORMAL ); }
189	  `}`
190		{ $$.parse = psete( $3.string,$4.parse,$7.string,$2.number ); }
191	;
192
193/*
194 * assign - = or +=
195 */
196
197assign	: `=`
198		{ $$.number = ASSIGN_SET; }
199	| `+=`
200		{ $$.number = ASSIGN_APPEND; }
201	| `?=`
202		{ $$.number = ASSIGN_DEFAULT; }
203	| `default` `=`
204		{ $$.number = ASSIGN_DEFAULT; }
205	;
206
207/*
208 * expr - an expression for if
209 */
210expr	: arg
211		{ $$.parse = peval( EXPR_EXISTS, $1.parse, pnull() ); yymode( SCAN_COND ); }
212	| expr `=` { yymode( SCAN_CONDB ); } expr
213		{ $$.parse = peval( EXPR_EQUALS, $1.parse, $4.parse ); }
214	| expr `!=` { yymode( SCAN_CONDB ); } expr
215		{ $$.parse = peval( EXPR_NOTEQ, $1.parse, $4.parse ); }
216	| expr `<` { yymode( SCAN_CONDB ); } expr
217		{ $$.parse = peval( EXPR_LESS, $1.parse, $4.parse ); }
218	| expr `<=` { yymode( SCAN_CONDB ); } expr
219		{ $$.parse = peval( EXPR_LESSEQ, $1.parse, $4.parse ); }
220	| expr `>` { yymode( SCAN_CONDB ); } expr
221		{ $$.parse = peval( EXPR_MORE, $1.parse, $4.parse ); }
222	| expr `>=` { yymode( SCAN_CONDB ); } expr
223		{ $$.parse = peval( EXPR_MOREEQ, $1.parse, $4.parse ); }
224	| expr `&` { yymode( SCAN_CONDB ); } expr
225		{ $$.parse = peval( EXPR_AND, $1.parse, $4.parse ); }
226	| expr `&&` { yymode( SCAN_CONDB ); } expr
227		{ $$.parse = peval( EXPR_AND, $1.parse, $4.parse ); }
228	| expr `|` { yymode( SCAN_CONDB ); } expr
229		{ $$.parse = peval( EXPR_OR, $1.parse, $4.parse ); }
230	| expr `||` { yymode( SCAN_CONDB ); } expr
231		{ $$.parse = peval( EXPR_OR, $1.parse, $4.parse ); }
232	| arg `in` { yymode( SCAN_PUNCT ); } list
233		{ $$.parse = peval( EXPR_IN, $1.parse, $4.parse ); yymode( SCAN_COND ); }
234	| `!` { yymode( SCAN_CONDB ); } expr
235		{ $$.parse = peval( EXPR_NOT, $3.parse, pnull() ); }
236	| `(` { yymode( SCAN_CONDB ); } expr `)`
237		{ $$.parse = $3.parse; }
238	;
239
240
241/*
242 * cases - action elements inside a 'switch'
243 * case - a single action element inside a 'switch'
244 * right-recursive rule so cases can be examined in order.
245 */
246
247cases	: /* empty */
248		{ $$.parse = P0; }
249	| case cases
250		{ $$.parse = pnode( $1.parse, $2.parse ); }
251	;
252
253case	: `case` { yymode( SCAN_CASE ); } ARG `:` { yymode( SCAN_NORMAL ); } block
254		{ $$.parse = psnode( $3.string, $6.parse ); }
255	;
256
257/*
258 * lol - list of lists
259 * right-recursive rule so that lists can be added in order.
260 */
261
262lol	: list
263		{ $$.parse = pnode( P0, $1.parse ); }
264	| list `:` lol
265		{ $$.parse = pnode( $3.parse, $1.parse ); }
266	;
267
268/*
269 * list - zero or more args in a LIST
270 * listp - list (in puncutation only mode)
271 * arg - one ARG or function call
272 */
273
274list	: listp
275		{ $$.parse = $1.parse; }
276	;
277
278listp	: /* empty */
279		{ $$.parse = pnull(); }
280	| listp arg
281        	{ $$.parse = pappend( $1.parse, $2.parse ); }
282	;
283
284arg	: ARG
285		{ $$.parse = plist( $1.string ); }
286	| `[` { $$.number = yymode( SCAN_CALL ); } func `]`
287		{ $$.parse = $3.parse; yymode( $2.number ); }
288	;
289
290/*
291 * func - a function call (inside [])
292 * This needs to be split cleanly out of 'rule'
293 */
294
295func	: ARG { yymode( SCAN_PUNCT ); } lol
296		{ $$.parse = prule( $1.string, $3.parse ); }
297	| `on` arg ARG { yymode( SCAN_PUNCT ); } lol
298		{ $$.parse = pon( $2.parse, prule( $3.string, $5.parse ) ); }
299	| `on` arg `return` { yymode( SCAN_PUNCT ); } list
300		{ $$.parse = pon( $2.parse, $5.parse ); }
301	;
302
303
304/*
305 * eflags - zero or more modifiers to 'executes'
306 * eflag - a single modifier to 'executes'
307 */
308
309eflags	: /* empty */
310		{ $$.number = 0; }
311	| eflags eflag
312		{ $$.number = $1.number | $2.number; }
313	;
314
315eflag	: `updated`
316		{ $$.number = EXEC_UPDATED; }
317	| `together`
318		{ $$.number = EXEC_TOGETHER; }
319	| `ignore`
320		{ $$.number = EXEC_IGNORE; }
321	| `quietly`
322		{ $$.number = EXEC_QUIETLY; }
323	| `piecemeal`
324		{ $$.number = EXEC_PIECEMEAL; }
325	| `existing`
326		{ $$.number = EXEC_EXISTING; }
327	;
328
329
330/*
331 * bindlist - list of variable to bind for an action
332 */
333
334bindlist : /* empty */
335		{ $$.parse = pnull(); }
336	| `bind` { yymode( SCAN_PUNCT ); } list
337		{ $$.parse = $3.parse; }
338	;
339
340
341