1/*
2 * Copyright 1993-2002 Christopher Seiwald and Perforce Software, Inc.
3 *
4 * This file is part of Jam - see jam.c for Copyright information.
5 */
6
7/*
8 * jamgram.yy - jam grammar
9 *
10 * 04/13/94 (seiwald) - added shorthand L0 for null list pointer
11 * 06/01/94 (seiwald) - new 'actions existing' does existing sources
12 * 08/23/94 (seiwald) - Support for '+=' (append to variable)
13 * 08/31/94 (seiwald) - Allow ?= as alias for "default =".
14 * 09/15/94 (seiwald) - if conditionals take only single arguments, so
15 *			that 'if foo == bar' gives syntax error (use =).
16 * 02/11/95 (seiwald) - when scanning arguments to rules, only treat
17 *			punctuation keywords as keywords.  All arg lists
18 *			are terminated with punctuation keywords.
19 * 09/11/00 (seiwald) - Support for function calls; rules return LIST *.
20 * 01/22/01 (seiwald) - replace evaluate_if() with compile_eval()
21 * 01/24/01 (seiwald) - 'while' statement
22 * 03/23/01 (seiwald) - "[ on target rule ]" support
23 * 02/27/02 (seiwald) - un-break "expr : arg in list" syntax
24 * 03/02/02 (seiwald) - rules can be invoked via variable names
25 * 03/12/02 (seiwald) - set YYMAXDEPTH for big, right-recursive rules
26 * 02/28/02 (seiwald) - merge EXEC_xxx flags in with RULE_xxx
27 * 06/21/02 (seiwald) - support for named parameters
28 * 10/22/02 (seiwald) - working return/break/continue statements
29 */
30
31%token ARG STRING
32
33%left `||` `|`
34%left `&&` `&`
35%left `=` `!=` `in`
36%left `<` `<=` `>` `>=`
37%left `!`
38
39%{
40#include "jam.h"
41
42#include "lists.h"
43#include "variable.h"
44#include "parse.h"
45#include "scan.h"
46#include "compile.h"
47#include "newstr.h"
48#include "rules.h"
49
50# define YYMAXDEPTH 10000	/* for OSF and other less endowed yaccs */
51
52# define F0 (LIST *(*)(PARSE *, LOL *, int *))0
53# define P0 (PARSE *)0
54# define S0 (char *)0
55
56# define pappend( l,r )    	parse_make( compile_append,l,r,P0,S0,S0,0 )
57# define pbreak( l,f )     	parse_make( compile_break,l,P0,P0,S0,S0,f )
58# define peval( c,l,r )		parse_make( compile_eval,l,r,P0,S0,S0,c )
59# define pfor( s,l,r )    	parse_make( compile_foreach,l,r,P0,s,S0,0 )
60# define pif( l,r,t )	  	parse_make( compile_if,l,r,t,S0,S0,0 )
61# define pincl( l )       	parse_make( compile_include,l,P0,P0,S0,S0,0 )
62# define plist( s )	  	parse_make( compile_list,P0,P0,P0,s,S0,0 )
63# define plocal( l,r,t )  	parse_make( compile_local,l,r,t,S0,S0,0 )
64# define pnull()	  	parse_make( compile_null,P0,P0,P0,S0,S0,0 )
65# define pon( l,r )	  	parse_make( compile_on,l,r,P0,S0,S0,0 )
66# define prule( a,p )     	parse_make( compile_rule,a,p,P0,S0,S0,0 )
67# define prules( l,r )	  	parse_make( compile_rules,l,r,P0,S0,S0,0 )
68# define pset( l,r,a ) 	  	parse_make( compile_set,l,r,P0,S0,S0,a )
69# define pset1( l,r,t,a )	parse_make( compile_settings,l,r,t,S0,S0,a )
70# define psetc( s,l,r )     	parse_make( compile_setcomp,l,r,P0,s,S0,0 )
71# define psete( s,l,s1,f ) 	parse_make( compile_setexec,l,P0,P0,s,s1,f )
72# define pswitch( l,r )   	parse_make( compile_switch,l,r,P0,S0,S0,0 )
73# define pwhile( l,r )   	parse_make( compile_while,l,r,P0,S0,S0,0 )
74
75# define pnode( l,r )    	parse_make( F0,l,r,P0,S0,S0,0 )
76# define psnode( s,l )     	parse_make( F0,l,P0,P0,s,S0,0 )
77
78%}
79
80%%
81
82run	: /* empty */
83		/* do nothing */
84	| rules
85		{ parse_save( $1.parse ); }
86	;
87
88/*
89 * block - zero or more rules
90 * rules - one or more rules
91 * rule - any one of jam's rules
92 * right-recursive so rules execute in order.
93 */
94
95block	: /* empty */
96		{ $$.parse = pnull(); }
97	| rules
98		{ $$.parse = $1.parse; }
99	;
100
101rules	: rule
102		{ $$.parse = $1.parse; }
103	| rule rules
104		{ $$.parse = prules( $1.parse, $2.parse ); }
105	| `local` list `;` block
106		{ $$.parse = plocal( $2.parse, pnull(), $4.parse ); }
107	| `local` list `=` list `;` block
108		{ $$.parse = plocal( $2.parse, $4.parse, $6.parse ); }
109	;
110
111rule	: `{` block `}`
112		{ $$.parse = $2.parse; }
113	| `include` list `;`
114		{ $$.parse = pincl( $2.parse ); }
115	| `jumptoeof` list `;`
116		{ $$.parse = pbreak( $2.parse, JMP_EOF ); }
117	| arg lol `;`
118		{ $$.parse = prule( $1.parse, $2.parse ); }
119	| arg assign list `;`
120		{ $$.parse = pset( $1.parse, $3.parse, $2.number ); }
121	| arg `on` list assign list `;`
122		{ $$.parse = pset1( $1.parse, $3.parse, $5.parse, $4.number ); }
123	| `break` list `;`
124		{ $$.parse = pbreak( $2.parse, JMP_BREAK ); }
125	| `continue` list `;`
126		{ $$.parse = pbreak( $2.parse, JMP_CONTINUE ); }
127	| `return` list `;`
128		{ $$.parse = pbreak( $2.parse, JMP_RETURN ); }
129	| `for` ARG `in` list `{` block `}`
130		{ $$.parse = pfor( $2.string, $4.parse, $6.parse ); }
131	| `switch` list `{` cases `}`
132		{ $$.parse = pswitch( $2.parse, $4.parse ); }
133	| `if` expr `{` block `}`
134		{ $$.parse = pif( $2.parse, $4.parse, pnull() ); }
135	| `if` expr `{` block `}` `else` rule
136		{ $$.parse = pif( $2.parse, $4.parse, $7.parse ); }
137	| `while` expr `{` block `}`
138		{ $$.parse = pwhile( $2.parse, $4.parse ); }
139	| `rule` ARG params `{` block `}`
140		{ $$.parse = psetc( $2.string, $3.parse, $5.parse ); }
141	| `on` arg rule
142		{ $$.parse = pon( $2.parse, $3.parse ); }
143	| `actions` eflags ARG bindlist `{`
144		{ yymode( SCAN_STRING ); }
145	  STRING
146		{ yymode( SCAN_NORMAL ); }
147	  `}`
148		{ $$.parse = psete( $3.string,$4.parse,$7.string,$2.number ); }
149	;
150
151/*
152 * assign - = or +=
153 */
154
155assign	: `=`
156		{ $$.number = VAR_SET; }
157	| `+=`
158		{ $$.number = VAR_APPEND; }
159	| `?=`
160		{ $$.number = VAR_DEFAULT; }
161	| `default` `=`
162		{ $$.number = VAR_DEFAULT; }
163	;
164
165/*
166 * expr - an expression for if
167 */
168
169expr	: arg
170		{ $$.parse = peval( EXPR_EXISTS, $1.parse, pnull() ); }
171	| expr `=` expr
172		{ $$.parse = peval( EXPR_EQUALS, $1.parse, $3.parse ); }
173	| expr `!=` expr
174		{ $$.parse = peval( EXPR_NOTEQ, $1.parse, $3.parse ); }
175	| expr `<` expr
176		{ $$.parse = peval( EXPR_LESS, $1.parse, $3.parse ); }
177	| expr `<=` expr
178		{ $$.parse = peval( EXPR_LESSEQ, $1.parse, $3.parse ); }
179	| expr `>` expr
180		{ $$.parse = peval( EXPR_MORE, $1.parse, $3.parse ); }
181	| expr `>=` expr
182		{ $$.parse = peval( EXPR_MOREEQ, $1.parse, $3.parse ); }
183	| expr `&` expr
184		{ $$.parse = peval( EXPR_AND, $1.parse, $3.parse ); }
185	| expr `&&` expr
186		{ $$.parse = peval( EXPR_AND, $1.parse, $3.parse ); }
187	| expr `|` expr
188		{ $$.parse = peval( EXPR_OR, $1.parse, $3.parse ); }
189	| expr `||` expr
190		{ $$.parse = peval( EXPR_OR, $1.parse, $3.parse ); }
191	| arg `in` list
192		{ $$.parse = peval( EXPR_IN, $1.parse, $3.parse ); }
193	| `!` expr
194		{ $$.parse = peval( EXPR_NOT, $2.parse, pnull() ); }
195	| `(` expr `)`
196		{ $$.parse = $2.parse; }
197	;
198
199/*
200 * cases - action elements inside a 'switch'
201 * case - a single action element inside a 'switch'
202 * right-recursive rule so cases can be examined in order.
203 */
204
205cases	: /* empty */
206		{ $$.parse = P0; }
207	| case cases
208		{ $$.parse = pnode( $1.parse, $2.parse ); }
209	;
210
211case	: `case` ARG `:` block
212		{ $$.parse = psnode( $2.string, $4.parse ); }
213	;
214
215/*
216 * params - optional parameter names to rule definition
217 * right-recursive rule so that params can be added in order.
218 */
219
220params	: /* empty */
221		{ $$.parse = P0; }
222	| ARG `:` params
223		{ $$.parse = psnode( $1.string, $3.parse ); }
224	| ARG
225		{ $$.parse = psnode( $1.string, P0 ); }
226	;
227
228/*
229 * lol - list of lists
230 * right-recursive rule so that lists can be added in order.
231 */
232
233lol	: list
234		{ $$.parse = pnode( P0, $1.parse ); }
235	| list `:` lol
236		{ $$.parse = pnode( $3.parse, $1.parse ); }
237	;
238
239/*
240 * list - zero or more args in a LIST
241 * listp - list (in puncutation only mode)
242 * arg - one ARG or function call
243 */
244
245list	: listp
246		{ $$.parse = $1.parse; yymode( SCAN_NORMAL ); }
247	;
248
249listp	: /* empty */
250		{ $$.parse = pnull(); yymode( SCAN_PUNCT ); }
251	| listp arg
252		{ $$.parse = pappend( $1.parse, $2.parse ); }
253	;
254
255arg	: ARG
256		{ $$.parse = plist( $1.string ); }
257	| `[` { yymode( SCAN_NORMAL ); } func `]`
258		{ $$.parse = $3.parse; }
259	;
260
261/*
262 * func - a function call (inside [])
263 * This needs to be split cleanly out of 'rule'
264 */
265
266func	: arg lol
267		{ $$.parse = prule( $1.parse, $2.parse ); }
268	| `on` arg arg lol
269		{ $$.parse = pon( $2.parse, prule( $3.parse, $4.parse ) ); }
270	| `on` arg `return` list
271		{ $$.parse = pon( $2.parse, $4.parse ); }
272	;
273
274/*
275 * eflags - zero or more modifiers to 'executes'
276 * eflag - a single modifier to 'executes'
277 */
278
279eflags	: /* empty */
280		{ $$.number = 0; }
281	| eflags eflag
282		{ $$.number = $1.number | $2.number; }
283	;
284
285eflag	: `updated`
286		{ $$.number = RULE_UPDATED; }
287	| `together`
288		{ $$.number = RULE_TOGETHER; }
289	| `ignore`
290		{ $$.number = RULE_IGNORE; }
291	| `quietly`
292		{ $$.number = RULE_QUIETLY; }
293	| `piecemeal`
294		{ $$.number = RULE_PIECEMEAL; }
295	| `existing`
296		{ $$.number = RULE_EXISTING; }
297	| `maxline` ARG
298		{ $$.number = atoi( $2.string ) * RULE_MAXLINE; }
299	;
300
301
302/*
303 * bindlist - list of variable to bind for an action
304 */
305
306bindlist : /* empty */
307		{ $$.parse = pnull(); }
308	| `bind` list
309		{ $$.parse = $2.parse; }
310	;
311
312
313