struct / union in initializer, RFE #901.
[sdcc.git] / sdcc / src / SDCCgen.c
blob839400511d7419c9681f77e35eb4db777c4e091a
1 /*-------------------------------------------------------------------------
2 SDCCgen.c - source files for target code generation common functions
4 Copyright (C) 2012, Borut Razem
5 Copyright (C) 2022, Sebastian 'basxto' Riedel <sdcc@basxto.de>
7 This program is free software; you can redistribute it and/or modify it
8 under the terms of the GNU General Public License as published by the
9 Free Software Foundation; either version 2, or (at your option) any
10 later version.
12 This program is distributed in the hope that it will be useful,
13 but WITHOUT ANY WARRANTY; without even the implied warranty of
14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 GNU General Public License for more details.
17 You should have received a copy of the GNU General Public License
18 along with this program; if not, write to the Free Software
19 Foundation, 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
20 -------------------------------------------------------------------------*/
22 #include "common.h"
23 #include "dbuf_string.h"
25 /* Use the D macro for basic (unobtrusive) debugging messages */
26 #define D(x) do if (options.verboseAsm) {x;} while(0)
28 genLine_t genLine;
30 /*-----------------------------------------------------------------*/
31 /* newLineNode - creates a new peep line */
32 /*-----------------------------------------------------------------*/
33 lineNode *
34 newLineNode (const char *line)
36 lineNode *pl;
38 pl = Safe_alloc (sizeof (lineNode));
39 pl->line = Safe_strdup (line);
40 pl->ic = NULL;
41 return pl;
44 /*-----------------------------------------------------------------*/
45 /* connectLine - connects two lines */
46 /*-----------------------------------------------------------------*/
47 lineNode *
48 connectLine (lineNode * pl1, lineNode * pl2)
50 if (!pl1 || !pl2)
52 fprintf (stderr, "trying to connect null line\n");
53 return NULL;
56 pl2->prev = pl1;
57 pl1->next = pl2;
59 return pl2;
62 void
63 destroy_line_list (void)
65 lineNode *pl;
67 pl = genLine.lineCurr;
69 while (pl)
71 lineNode *p;
73 if (pl->line)
74 Safe_free (pl->line);
76 if (pl->aln)
77 Safe_free (pl->aln);
79 p = pl;
80 pl = pl->prev;
81 Safe_free (p);
83 genLine.lineHead = genLine.lineCurr = NULL;
86 /*-----------------------------------------------------------------*/
87 /* emit_raw - emit raw unformatted line */
88 /*-----------------------------------------------------------------*/
89 static void
90 add_line_node (const char *line)
92 lineNode *pl;
94 pl = Safe_alloc (sizeof (lineNode));
96 memcpy (pl, (lineElem_t *) & genLine.lineElement, sizeof (lineElem_t));
98 pl->line = Safe_strdup (line);
100 if (genLine.lineCurr)
102 pl->next = NULL;
103 genLine.lineCurr->next = pl;
104 pl->prev = genLine.lineCurr;
105 genLine.lineCurr = pl;
107 else
109 pl->prev = pl->next = NULL;
110 genLine.lineCurr = genLine.lineHead = pl;
114 void
115 emit_raw (const char *line)
117 const char *p = line;
119 while (isspace ((unsigned char) *p))
120 p++;
122 if (*p)
124 if (!port->rtrackUpdate || !port->rtrackUpdate(line))
126 genLine.lineElement.isComment = (*p == ';');
127 add_line_node (line);
132 /*-----------------------------------------------------------------*/
133 /* format_opcode - format the opcode and arguments for emitting */
134 /*-----------------------------------------------------------------*/
135 const char *
136 format_opcode (const char *inst, const char *fmt, va_list ap)
138 struct dbuf_s dbuf;
140 dbuf_init (&dbuf, INITIAL_INLINEASM);
142 if (inst && *inst)
144 dbuf_append_str (&dbuf, inst);
146 if (fmt && *fmt)
148 dbuf_append_char (&dbuf, '\t');
149 dbuf_tvprintf (&dbuf, fmt, ap);
152 else
154 if (fmt && *fmt)
156 dbuf_tvprintf (&dbuf, fmt, ap);
160 return dbuf_detach_c_str (&dbuf);
163 void
164 va_emitcode (const char *inst, const char *fmt, va_list ap)
166 const char *line = format_opcode (inst, fmt, ap);
167 emit_raw (line);
168 dbuf_free (line);
171 /*-----------------------------------------------------------------*/
172 /* emitcode - writes the code into a file : for now it is simple */
173 /*-----------------------------------------------------------------*/
174 void
175 emitcode (const char *inst, const char *fmt, ...)
177 va_list ap;
179 va_start (ap, fmt);
180 va_emitcode (inst, fmt, ap);
181 va_end (ap);
184 void
185 emitLabel (const symbol *tlbl)
187 if (!tlbl)
188 return;
189 emitcode ("", "!tlabeldef", labelKey2num (tlbl->key));
190 genLine.lineCurr->isLabel = 1;
193 /*-----------------------------------------------------------------*/
194 /* genInline - write the inline code out */
195 /*-----------------------------------------------------------------*/
196 void
197 genInline (iCode * ic)
199 char *buf, *bp, *begin;
200 bool inComment = FALSE;
201 bool inLiteral = FALSE;
202 bool inLiteralString = FALSE;
204 D (emitcode (";", "genInline"));
206 genLine.lineElement.isInline += (!options.asmpeep);
208 buf = bp = begin = Safe_strdup (IC_INLINE (ic));
210 /* Emit each line as a code */
211 while (*bp)
213 switch (*bp)
215 case '\'':
216 inLiteral = !inLiteral;
217 ++bp;
218 break;
220 case '"':
221 inLiteralString = !inLiteralString;
222 ++bp;
223 break;
225 case ';':
226 if (!inLiteral && !inLiteralString)
228 inComment = TRUE;
230 ++bp;
231 break;
233 case ':':
234 /* Add \n for labels, not dirs such as c:\mydir, not local direct assignment =: */
235 if (!inComment && !inLiteral && !inLiteralString && (isspace ((unsigned char) bp[1])) && (*(bp-1) != '='))
237 ++bp;
238 *bp = '\0';
239 ++bp;
240 /* Don't emit leading whitespaces */
241 while (isspace (*begin))
242 ++begin;
243 emitcode (begin, NULL);
244 genLine.lineCurr->isLabel = 1;
245 begin = bp;
247 else
249 ++bp;
251 break;
253 case '\x87':
254 case '\n':
255 inLiteral = FALSE;
256 inLiteralString = FALSE;
257 inComment = FALSE;
258 *bp++ = '\0';
260 /* Don't emit leading whitespaces */
261 while (isspace (*begin))
262 ++begin;
264 if (*begin)
265 emitcode (begin, NULL);
267 begin = bp;
268 break;
270 default:
271 ++bp;
272 break;
275 if (begin != bp)
277 /* Don't emit leading whitespaces */
278 while (isspace (*begin))
279 ++begin;
281 if (*begin)
282 emitcode (begin, NULL);
285 Safe_free (buf);
287 /* consumed; we can free it here */
288 dbuf_free (IC_INLINE (ic));
290 genLine.lineElement.isInline -= (!options.asmpeep);
293 /*-----------------------------------------------------------------*/
294 /* printLine - prints a line chain into a given file */
295 /*-----------------------------------------------------------------*/
296 void
297 printLine (lineNode * head, struct dbuf_s *oBuf)
299 iCode *last_ic = NULL;
300 bool debug_iCode_tracking = (getenv ("DEBUG_ICODE_TRACKING") != NULL);
302 while (head)
304 if (head->ic != last_ic)
306 last_ic = head->ic;
307 if (debug_iCode_tracking)
309 if (head->ic)
310 dbuf_printf (oBuf, "; block = %d, seq = %d\n", head->ic->block, head->ic->seq);
311 else
312 dbuf_append_str (oBuf, "; iCode lost\n");
316 /* don't indent comments & labels */
317 if (head->line && (head->isComment || head->isLabel))
319 dbuf_printf (oBuf, "%s\n", head->line);
321 else
323 if (head->isInline && *head->line == '#')
325 /* comment out preprocessor directives in inline asm */
326 dbuf_append_char (oBuf, ';');
328 dbuf_printf (oBuf, "\t%s\n", head->line);
330 head = head->next;
334 /*-----------------------------------------------------------------*/
335 /* ifxForOp - returns the icode containing the ifx for operand */
336 /*-----------------------------------------------------------------*/
337 iCode *
338 ifxForOp (const operand *op, const iCode *ic)
340 iCode *ifxIc;
342 /* if true symbol then needs to be assigned */
343 if (!IS_TRUE_SYMOP (op))
345 /* if this has register type condition and
346 while skipping ipop's (see bug 1509084),
347 the next instruction is ifx with the same operand
348 and live to of the operand is upto the ifx only then */
349 for (ifxIc = ic->next; ifxIc && ifxIc->op == IPOP; ifxIc = ifxIc->next)
352 if (ifxIc && ifxIc->op == IFX &&
353 IC_COND (ifxIc)->key == op->key &&
354 OP_SYMBOL_CONST (op)->liveFrom >= ic->seq &&
355 OP_SYMBOL_CONST (op)->liveTo <= ifxIc->seq)
356 return ifxIc;
359 return NULL;