7b4ac7e1 |
1 | /* Print in infix form a struct expression. |
2 | Copyright (C) 1986 Free Software Foundation, Inc. |
3 | |
4 | GDB is distributed in the hope that it will be useful, but WITHOUT ANY |
5 | WARRANTY. No author or distributor accepts responsibility to anyone |
6 | for the consequences of using it or for whether it serves any |
7 | particular purpose or works at all, unless he says so in writing. |
8 | Refer to the GDB General Public License for full details. |
9 | |
10 | Everyone is granted permission to copy, modify and redistribute GDB, |
11 | but only under the conditions described in the GDB General Public |
12 | License. A copy of this license is supposed to have been given to you |
13 | along with GDB so you can know your rights and responsibilities. It |
14 | should be in a file named COPYING. Among other things, the copyright |
15 | notice and this notice must be preserved on all copies. |
16 | |
17 | In other words, go ahead and share GDB, but don't try to stop |
18 | anyone else from sharing it farther. Help stamp out software hoarding! |
19 | */ |
20 | |
21 | #include "defs.h" |
22 | #include "symtab.h" |
e91b87a3 |
23 | #include "param.h" |
7b4ac7e1 |
24 | #include "expression.h" |
25 | |
26 | #include <stdio.h> |
27 | \f |
28 | /* These codes indicate operator precedences, least tightly binding first. */ |
29 | /* Adding 1 to a precedence value is done for binary operators, |
30 | on the operand which is more tightly bound, so that operators |
31 | of equal precedence within that operand will get parentheses. */ |
32 | /* PREC_HYPER and PREC_ABOVE_COMMA are not the precedence of any operator; |
33 | they are used as the "surrounding precedence" to force |
34 | various kinds of things to be parenthesized. */ |
35 | enum precedence |
36 | { PREC_NULL, PREC_COMMA, PREC_ABOVE_COMMA, PREC_ASSIGN, PREC_OR, PREC_AND, |
37 | PREC_LOGIOR, PREC_LOGAND, PREC_LOGXOR, PREC_EQUAL, PREC_ORDER, |
38 | PREC_SHIFT, PREC_ADD, PREC_MUL, PREC_REPEAT, |
39 | PREC_HYPER, PREC_PREFIX, PREC_SUFFIX }; |
40 | |
41 | /* Table mapping opcodes into strings for printing operators |
42 | and precedences of the operators. */ |
43 | |
44 | struct op_print |
45 | { |
46 | char *string; |
47 | enum exp_opcode opcode; |
48 | /* Precedence of operator. These values are used only by comparisons. */ |
49 | enum precedence precedence; |
50 | int right_assoc; |
51 | }; |
52 | |
53 | static struct op_print op_print_tab[] = |
54 | { |
55 | {",", BINOP_COMMA, PREC_COMMA, 0}, |
56 | {"=", BINOP_ASSIGN, PREC_ASSIGN, 1}, |
57 | {"||", BINOP_OR, PREC_OR, 0}, |
58 | {"&&", BINOP_AND, PREC_AND, 0}, |
59 | {"|", BINOP_LOGIOR, PREC_LOGIOR, 0}, |
60 | {"&", BINOP_LOGAND, PREC_LOGAND, 0}, |
61 | {"^", BINOP_LOGXOR, PREC_LOGXOR, 0}, |
62 | {"==", BINOP_EQUAL, PREC_EQUAL, 0}, |
63 | {"!=", BINOP_NOTEQUAL, PREC_EQUAL, 0}, |
64 | {"<=", BINOP_LEQ, PREC_ORDER, 0}, |
65 | {">=", BINOP_GEQ, PREC_ORDER, 0}, |
66 | {">", BINOP_GTR, PREC_ORDER, 0}, |
67 | {"<", BINOP_LESS, PREC_ORDER, 0}, |
68 | {">>", BINOP_RSH, PREC_SHIFT, 0}, |
69 | {"<<", BINOP_LSH, PREC_SHIFT, 0}, |
70 | {"+", BINOP_ADD, PREC_ADD, 0}, |
71 | {"-", BINOP_SUB, PREC_ADD, 0}, |
72 | {"*", BINOP_MUL, PREC_MUL, 0}, |
73 | {"/", BINOP_DIV, PREC_MUL, 0}, |
74 | {"%", BINOP_REM, PREC_MUL, 0}, |
75 | {"@", BINOP_REPEAT, PREC_REPEAT, 0}, |
76 | {"-", UNOP_NEG, PREC_PREFIX, 0}, |
77 | {"!", UNOP_ZEROP, PREC_PREFIX, 0}, |
78 | {"~", UNOP_LOGNOT, PREC_PREFIX, 0}, |
79 | {"*", UNOP_IND, PREC_PREFIX, 0}, |
80 | {"&", UNOP_ADDR, PREC_PREFIX, 0}, |
81 | {"sizeof ", UNOP_SIZEOF, PREC_PREFIX, 0}, |
82 | {"++", UNOP_PREINCREMENT, PREC_PREFIX, 0}, |
e91b87a3 |
83 | {"--", UNOP_PREDECREMENT, PREC_PREFIX, 0}, |
84 | /* C++ */ |
85 | {"::", BINOP_SCOPE, PREC_PREFIX, 0}, |
7b4ac7e1 |
86 | }; |
87 | \f |
88 | static void print_subexp (); |
89 | |
90 | void |
91 | print_expression (exp, stream) |
92 | struct expression *exp; |
93 | FILE *stream; |
94 | { |
95 | int pc = 0; |
96 | print_subexp (exp, &pc, stream, PREC_NULL); |
97 | } |
98 | |
99 | /* Print the subexpression of EXP that starts in position POS, on STREAM. |
100 | PREC is the precedence of the surrounding operator; |
101 | if the precedence of the main operator of this subexpression is less, |
102 | parentheses are needed here. */ |
103 | |
104 | static void |
105 | print_subexp (exp, pos, stream, prec) |
106 | register struct expression *exp; |
107 | register int *pos; |
108 | FILE *stream; |
109 | enum precedence prec; |
110 | { |
111 | register int tem; |
112 | register int pc; |
113 | int nargs; |
114 | register char *op_str; |
115 | int assign_modify = 0; |
116 | enum exp_opcode opcode; |
117 | enum precedence myprec; |
118 | /* Set to 1 for a right-associative operator. */ |
119 | int assoc; |
120 | |
121 | pc = (*pos)++; |
122 | opcode = exp->elts[pc].opcode; |
123 | switch (opcode) |
124 | { |
e91b87a3 |
125 | case OP_SCOPE: |
126 | myprec = PREC_PREFIX; |
127 | assoc = 0; |
128 | (*pos) += 2; |
129 | print_subexp (exp, pos, stream, (int) myprec + assoc); |
130 | fprintf (stream, " :: "); |
131 | nargs = strlen (&exp->elts[pc + 2].string); |
132 | (*pos) += 1 + (nargs + sizeof (union exp_element)) / sizeof (union exp_element); |
133 | |
134 | fprintf (stream, &exp->elts[pc + 2].string); |
135 | return; |
136 | |
7b4ac7e1 |
137 | case OP_LONG: |
138 | (*pos) += 3; |
139 | value_print (value_from_long (exp->elts[pc + 1].type, |
140 | exp->elts[pc + 2].longconst), |
3bf57d21 |
141 | stream, 0); |
7b4ac7e1 |
142 | return; |
143 | |
144 | case OP_DOUBLE: |
145 | (*pos) += 3; |
146 | value_print (value_from_double (exp->elts[pc + 1].type, |
147 | exp->elts[pc + 2].doubleconst), |
3bf57d21 |
148 | stream, 0); |
7b4ac7e1 |
149 | return; |
150 | |
151 | case OP_VAR_VALUE: |
152 | (*pos) += 2; |
153 | fprintf (stream, "%s", SYMBOL_NAME (exp->elts[pc + 1].symbol)); |
154 | return; |
155 | |
156 | case OP_LAST: |
157 | (*pos) += 2; |
158 | fprintf (stream, "$%d", exp->elts[pc + 1].longconst); |
159 | return; |
160 | |
161 | case OP_REGISTER: |
162 | (*pos) += 2; |
163 | fprintf (stream, "$%s", reg_names[exp->elts[pc + 1].longconst]); |
164 | return; |
165 | |
166 | case OP_INTERNALVAR: |
167 | (*pos) += 2; |
168 | fprintf (stream, "$%s", |
169 | internalvar_name (exp->elts[pc + 1].internalvar)); |
170 | return; |
171 | |
172 | case OP_FUNCALL: |
173 | (*pos) += 2; |
174 | nargs = exp->elts[pc + 1].longconst; |
175 | print_subexp (exp, pos, stream, PREC_SUFFIX); |
176 | fprintf (stream, " ("); |
177 | for (tem = 0; tem < nargs; tem++) |
178 | { |
179 | if (tem > 0) |
180 | fprintf (stream, ", "); |
181 | print_subexp (exp, pos, stream, PREC_ABOVE_COMMA); |
182 | } |
183 | fprintf (stream, ")"); |
184 | return; |
185 | |
186 | case OP_STRING: |
187 | nargs = strlen (&exp->elts[pc + 1].string); |
188 | (*pos) += 2 + (nargs + sizeof (union exp_element)) / sizeof (union exp_element); |
189 | fprintf (stream, "\""); |
190 | for (tem = 0; tem < nargs; tem++) |
3bf57d21 |
191 | printchar ((&exp->elts[pc + 1].string)[tem], stream, '"'); |
7b4ac7e1 |
192 | fprintf (stream, "\""); |
193 | return; |
194 | |
195 | case TERNOP_COND: |
196 | if ((int) prec > (int) PREC_COMMA) |
197 | fprintf (stream, "("); |
198 | /* Print the subexpressions, forcing parentheses |
199 | around any binary operations within them. |
200 | This is more parentheses than are strictly necessary, |
201 | but it looks clearer. */ |
202 | print_subexp (exp, pos, stream, PREC_HYPER); |
203 | fprintf (stream, " ? "); |
204 | print_subexp (exp, pos, stream, PREC_HYPER); |
205 | fprintf (stream, " : "); |
206 | print_subexp (exp, pos, stream, PREC_HYPER); |
207 | if ((int) prec > (int) PREC_COMMA) |
208 | fprintf (stream, ")"); |
209 | return; |
210 | |
211 | case STRUCTOP_STRUCT: |
212 | tem = strlen (&exp->elts[pc + 1].string); |
213 | (*pos) += 2 + (tem + sizeof (union exp_element)) / sizeof (union exp_element); |
214 | print_subexp (exp, pos, stream, PREC_SUFFIX); |
215 | fprintf (stream, ".%s", &exp->elts[pc + 1].string); |
216 | return; |
217 | |
218 | case STRUCTOP_PTR: |
219 | tem = strlen (&exp->elts[pc + 1].string); |
220 | (*pos) += 2 + (tem + sizeof (union exp_element)) / sizeof (union exp_element); |
221 | print_subexp (exp, pos, stream, PREC_SUFFIX); |
222 | fprintf (stream, "->%s", &exp->elts[pc + 1].string); |
223 | return; |
224 | |
225 | case BINOP_SUBSCRIPT: |
226 | print_subexp (exp, pos, stream, PREC_SUFFIX); |
227 | fprintf (stream, "["); |
228 | print_subexp (exp, pos, stream, PREC_ABOVE_COMMA); |
229 | fprintf (stream, "]"); |
230 | return; |
231 | |
232 | case UNOP_POSTINCREMENT: |
233 | print_subexp (exp, pos, stream, PREC_SUFFIX); |
234 | fprintf (stream, "++"); |
235 | return; |
236 | |
237 | case UNOP_POSTDECREMENT: |
238 | print_subexp (exp, pos, stream, PREC_SUFFIX); |
239 | fprintf (stream, "--"); |
240 | return; |
241 | |
242 | case UNOP_CAST: |
243 | (*pos) += 2; |
244 | if ((int) prec > (int) PREC_PREFIX) |
245 | fprintf (stream, "("); |
246 | fprintf (stream, "("); |
247 | type_print (exp->elts[pc + 1].type, "", stream, 0); |
248 | fprintf (stream, ") "); |
249 | print_subexp (exp, pos, stream, PREC_PREFIX); |
250 | if ((int) prec > (int) PREC_PREFIX) |
251 | fprintf (stream, ")"); |
252 | return; |
253 | |
254 | case UNOP_MEMVAL: |
255 | (*pos) += 2; |
256 | if ((int) prec > (int) PREC_PREFIX) |
257 | fprintf (stream, "("); |
258 | fprintf (stream, "{"); |
259 | type_print (exp->elts[pc + 1].type, "", stream, 0); |
260 | fprintf (stream, "} "); |
261 | print_subexp (exp, pos, stream, PREC_PREFIX); |
262 | if ((int) prec > (int) PREC_PREFIX) |
263 | fprintf (stream, ")"); |
264 | return; |
265 | |
266 | case BINOP_ASSIGN_MODIFY: |
267 | opcode = exp->elts[pc + 1].opcode; |
268 | (*pos) += 2; |
269 | myprec = PREC_ASSIGN; |
270 | assoc = 1; |
271 | assign_modify = 1; |
272 | for (tem = 0; tem < sizeof op_print_tab / sizeof op_print_tab[0]; tem++) |
273 | if (op_print_tab[tem].opcode == opcode) |
274 | { |
275 | op_str = op_print_tab[tem].string; |
276 | break; |
277 | } |
278 | |
279 | default: |
280 | for (tem = 0; tem < sizeof op_print_tab / sizeof op_print_tab[0]; tem++) |
281 | if (op_print_tab[tem].opcode == opcode) |
282 | { |
283 | op_str = op_print_tab[tem].string; |
284 | myprec = op_print_tab[tem].precedence; |
285 | assoc = op_print_tab[tem].right_assoc; |
286 | break; |
287 | } |
288 | } |
289 | |
290 | if ((int) myprec < (int) prec) |
291 | fprintf (stream, "("); |
292 | if ((int) opcode > (int) BINOP_END) |
293 | { |
294 | /* Unary prefix operator. */ |
295 | fprintf (stream, "%s", op_str); |
296 | print_subexp (exp, pos, stream, PREC_PREFIX); |
297 | } |
298 | else |
299 | { |
300 | /* Binary operator. */ |
301 | /* Print left operand. |
302 | If operator is right-associative, |
303 | increment precedence for this operand. */ |
304 | print_subexp (exp, pos, stream, (int) myprec + assoc); |
305 | /* Print the operator itself. */ |
306 | if (assign_modify) |
307 | fprintf (stream, " %s= ", op_str); |
308 | else if (op_str[0] == ',') |
309 | fprintf (stream, "%s ", op_str); |
310 | else |
311 | fprintf (stream, " %s ", op_str); |
312 | /* Print right operand. |
313 | If operator is left-associative, |
314 | increment precedence for this operand. */ |
315 | print_subexp (exp, pos, stream, (int) myprec + !assoc); |
316 | } |
317 | if ((int) myprec < (int) prec) |
318 | fprintf (stream, ")"); |
319 | } |