1 %{
2 /* Parser for linker scripts
3    Copyright (C) 2001, 2002, 2003, 2004, 2005
4    Craig Franklin
5 
6 This file is part of gputils.
7 
8 gputils is free software; you can redistribute it and/or modify
9 it under the terms of the GNU General Public License as published by
10 the Free Software Foundation; either version 2, or (at your option)
11 any later version.
12 
13 gputils is distributed in the hope that it will be useful,
14 but WITHOUT ANY WARRANTY; without even the implied warranty of
15 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
16 GNU General Public License for more details.
17 
18 You should have received a copy of the GNU General Public License
19 along with gputils; see the file COPYING.  If not, write to
20 the Free Software Foundation, 59 Temple Place - Suite 330,
21 Boston, MA 02111-1307, USA.  */
22 
23 #include "stdhdr.h"
24 
25 #include "libgputils.h"
26 #include "gplink.h"
27 #include "scan.h"
28 #include "script.h"
29 
yyerror(const char * Message)30 void yyerror(const char *Message)
31 {
32   script_error(Message, NULL);
33 }
34 
35 int yylex(void);
36 
37 /************************************************************************/
38 
39 /* Some simple functions for building parse trees */
40 
41 static pnode_t *
_mk_pnode(enum pnode_tag Tag)42 _mk_pnode(enum pnode_tag Tag)
43 {
44   pnode_t *new = GP_Malloc(sizeof(*new));
45 
46   new->tag = Tag;
47   return new;
48 }
49 
50 static pnode_t *
_mk_constant(long Value)51 _mk_constant(long Value)
52 {
53   pnode_t *new = _mk_pnode(PTAG_CONSTANT);
54 
55   PnConstant(new) = Value;
56   return new;
57 }
58 
59 static pnode_t *
_mk_symbol(const char * String)60 _mk_symbol(const char *String)
61 {
62   pnode_t *new = _mk_pnode(PTAG_SYMBOL);
63 
64   PnSymbol(new) = String;
65   return new;
66 }
67 
68 /*
69 static pnode_t *
70 _mk_string(const char *String)
71 {
72   pnode_t *new = _mk_pnode(PTAG_STRING);
73 
74   PnString(new) = String;
75   return new;
76 }
77 
78 */
79 
80 static pnode_t *
_mk_list(pnode_t * Head,pnode_t * Tail)81 _mk_list(pnode_t *Head, pnode_t *Tail)
82 {
83   pnode_t *new = _mk_pnode(PTAG_LIST);
84 
85   PnListHead(new) = Head;
86   PnListTail(new) = Tail;
87   return new;
88 }
89 
90 static pnode_t *
_mk_2op(int Op,pnode_t * Pnode0,pnode_t * Pnode1)91 _mk_2op(int Op, pnode_t *Pnode0, pnode_t *Pnode1)
92 {
93   pnode_t *new = _mk_pnode(PTAG_BINOP);
94 
95   PnBinOpOp(new) = Op;
96   PnBinOpP0(new) = Pnode0;
97   PnBinOpP1(new) = Pnode1;
98   return new;
99 }
100 
101 /*
102 static pnode_t *
103 _mk_1op(int Op, pnode_t *Pnode)
104 {
105   pnode_t *new = _mk_pnode(PTAG_UNOP);
106 
107   PnUnOpOp(new) = Op;
108   PnUnOpP0(new) = Pnode;
109   return new;
110 }
111 
112 */
113 
114 %}
115 
116 /* Bison declarations */
117 
118 %union {
119   int           i;
120   long          l;
121   char         *s;
122   struct pnode *p;
123 }
124 
125 %token <s> SYMBOL
126 %token <s> LIBPATH
127 %token <s> LKRPATH
128 %token <s> STRING
129 %token <s> LEXEOF 0 "end of file"
130 %token <s> ERROR
131 %token <l> NUMBER
132 %token DEFINE
133 %token IFDEF
134 %token ELSE
135 %token FI
136 %type <i> '='
137 %type <i> '+'
138 %type <i> '-'
139 %type <i> '/'
140 %type <i> '*'
141 %type <i> e1op
142 %type <l> macroval
143 %type <i> aop
144 
145 %type <p> e0
146 %type <p> e1
147 %type <p> parameter_list
148 %type <p> path_list
149 
150 %%
151 /* Grammar rules */
152 
153 program:
154         line
155         | error
156         | program '\n' {
157           ++state.src->line_number;
158         } line
159         ;
160 
161 line:
162         /* empty */
163         |
164         LIBPATH path_list
165         {
166           if ((state.ifdef == NULL) || (state.ifdef->is_true)) {
167             script_add_path($2);
168           }
169         }
170         |
171         LKRPATH path_list
172         {
173           if ((state.ifdef == NULL) || (state.ifdef->is_true)) {
174             script_add_path($2);
175           }
176         }
177         |
178         SYMBOL parameter_list
179         {
180           if ((state.ifdef == NULL) || (state.ifdef->is_true)) {
181             script_execute_command($1, $2);
182           }
183         }
184         |
185         STRING parameter_list
186         {
187           if ((state.ifdef == NULL) || (state.ifdef->is_true)) {
188             script_execute_command($1, $2);
189           }
190         }
191         |
192         ERROR
193         {
194           if ((state.ifdef == NULL) || (state.ifdef->is_true)) {
195             yyerror($1);
196           }
197         }
198         |
199         DEFINE SYMBOL macroval aop macroval
200         {
201           /* Contrary to documentation, the mplink 4.38 does not seem
202              to care if the macro has already been defined or if the
203              parameters to the operation are undefined. */
204           if ((state.ifdef == NULL) || (state.ifdef->is_true)) {
205             long newval;
206             long lh;
207             long rh;
208 
209             newval = 0;
210             lh     = $3;
211             rh     = $5;
212             switch ($4) {
213               case '+': newval = lh + rh; break;
214               case '-': newval = lh - rh; break;
215               case '*': newval = lh * rh; break;
216               case '/': {
217                 if (rh == 0) {
218                   yyerror("Division by zero.");
219                 }
220                 else {
221                   newval = lh / rh;
222                 }
223                 break;
224               }
225             }
226             script_add_symbol_value($2, newval);
227           }
228         }
229         |
230         IFDEF SYMBOL
231         {
232           ifdef_t *ifdef = GP_Malloc(sizeof(*ifdef));
233 
234           ifdef->is_true = (((state.ifdef == NULL) || state.ifdef->is_true) &&
235                             gp_sym_get_symbol(state.script_symbols, $2));
236           ifdef->in_else = false;
237           ifdef->prev    = state.ifdef;
238           state.ifdef = ifdef;
239         }
240         |
241         ELSE
242         {
243           if ((state.ifdef == NULL) || (state.ifdef->in_else)) {
244             yyerror("#ELSE without #IFDEF in linker script.");
245           }
246           else {
247             state.ifdef->is_true = ((!state.ifdef->is_true) &&
248                                     (state.ifdef->prev == NULL || state.ifdef->prev->is_true));
249             state.ifdef->in_else = true;
250           }
251         }
252         |
253         FI
254         {
255           if (state.ifdef == NULL)
256             yyerror("#FI without #IFDEF in linker script.");
257           else {
258             ifdef_t *ifdef = state.ifdef;
259 
260             state.ifdef = state.ifdef->prev;
261             free(ifdef);
262           }
263         }
264         ;
265 
266 path_list:
267         SYMBOL
268         {
269           $$ = _mk_list(_mk_symbol($1), NULL);
270         }
271         |
272         SYMBOL ';' path_list
273         {
274           $$ = _mk_list(_mk_symbol($1), $3);
275         }
276         |
277         STRING
278         {
279           $$ = _mk_list(_mk_symbol($1), NULL);
280         }
281         |
282         STRING ';' path_list
283         {
284           $$ = _mk_list(_mk_symbol($1), $3);
285         }
286         ;
287 
288 parameter_list:
289         e1
290         {
291           $$ = _mk_list($1, NULL);
292         }
293         |
294         e1  parameter_list
295         {
296           $$ = _mk_list($1, $2);
297         }
298         ;
299 
300 e1:
301         e0
302         |
303         e1 e1op e0
304         {
305           $$ = _mk_2op($2, $1, $3);
306         }
307         ;
308 
309 e1op:   '=' ;
310 
311 e0:
312         SYMBOL
313         {
314           $$ = _mk_symbol($1);
315         }
316         |
317         STRING
318         {
319           $$ = _mk_symbol($1);
320         }
321         |
322         NUMBER
323         {
324           $$ = _mk_constant($1);
325         }
326         ;
327 
328 macroval:
329         SYMBOL
330         {
331           $$ = script_get_symbol_value($1);
332         }
333         |
334         NUMBER
335         ;
336 
337 aop:    '+' | '-' | '/' | '*' ;
338 
339 %%
340