]> git.sur5r.net Git - cc65/blob - src/da65/data.c
Allow conditional directives within .STRUCT7:UNION and .ENUM
[cc65] / src / da65 / data.c
1 /*****************************************************************************/
2 /*                                                                           */
3 /*                                  data.c                                   */
4 /*                                                                           */
5 /*                           Data output routines                            */
6 /*                                                                           */
7 /*                                                                           */
8 /*                                                                           */
9 /* (C) 2000-2003 Ullrich von Bassewitz                                       */
10 /*               Römerstrasse 52                                             */
11 /*               D-70794 Filderstadt                                         */
12 /* EMail:        uz@cc65.org                                                 */
13 /*                                                                           */
14 /*                                                                           */
15 /* This software is provided 'as-is', without any expressed or implied       */
16 /* warranty.  In no event will the authors be held liable for any damages    */
17 /* arising from the use of this software.                                    */
18 /*                                                                           */
19 /* Permission is granted to anyone to use this software for any purpose,     */
20 /* including commercial applications, and to alter it and redistribute it    */
21 /* freely, subject to the following restrictions:                            */
22 /*                                                                           */
23 /* 1. The origin of this software must not be misrepresented; you must not   */
24 /*    claim that you wrote the original software. If you use this software   */
25 /*    in a product, an acknowledgment in the product documentation would be  */
26 /*    appreciated but is not required.                                       */
27 /* 2. Altered source versions must be plainly marked as such, and must not   */
28 /*    be misrepresented as being the original software.                      */
29 /* 3. This notice may not be removed or altered from any source              */
30 /*    distribution.                                                          */
31 /*                                                                           */
32 /*****************************************************************************/
33
34
35
36 /* da65 */
37 #include "attrtab.h"
38 #include "code.h"
39 #include "error.h"
40 #include "global.h"
41 #include "output.h"
42 #include "data.h"
43
44
45
46 /*****************************************************************************/
47 /*                                   Code                                    */
48 /*****************************************************************************/
49
50
51
52 static unsigned GetSpan (attr_t Style)
53 /* Get the number of bytes for a given style */
54 {
55     /* Get the number of bytes still available */
56     unsigned RemainingBytes = GetRemainingBytes ();
57
58     /* Count how many bytes are available. This number is limited by the
59      * number of remaining bytes, a label, or the end of the given Style
60      * attribute.
61      */
62     unsigned Count = 1;
63     while (Count < RemainingBytes) {
64         if (MustDefLabel(PC+Count) || GetStyleAttr (PC+Count) != Style) {
65             break;
66         }
67         ++Count;
68     }
69
70     /* Return the number of bytes */
71     return Count;
72 }
73
74
75
76 static unsigned DoTable (attr_t Style, unsigned MemberSize, void (*TableFunc) (unsigned))
77 /* Output a table of bytes */
78 {
79     unsigned BytesLeft;
80
81     /* Count how many bytes may be output. */
82     unsigned Count = GetSpan (Style);
83
84     /* If the count is less than the member size, print a row of Count data
85      * bytes. We assume here that there is no member with a size that is less
86      * than BytesPerLine.
87      */
88     if (Count < MemberSize) {
89         DataByteLine (Count);
90         return Count;
91     }
92
93     /* Make Count an even number of multiples of MemberSize */
94     Count &= ~(MemberSize-1);
95
96     /* Output as many data bytes lines as needed */
97     BytesLeft = Count;
98     while (BytesLeft > 0) {
99
100         /* Calculate the number of bytes for the next line */
101         unsigned Chunk = (BytesLeft > BytesPerLine)? BytesPerLine : BytesLeft;
102
103         /* Output a line with these bytes */
104         TableFunc (Chunk);
105
106         /* Next line */
107         BytesLeft -= Chunk;
108         PC        += Chunk;
109     }
110
111     /* If the next line is not the same style, add a separator */
112     if (CodeLeft() && GetStyleAttr (PC) != Style) {
113         SeparatorLine ();
114     }
115
116     /* Return the number of bytes output */
117     return Count;
118 }
119
120
121
122 unsigned ByteTable (void)
123 /* Output a table of bytes */
124 {
125     /* Call the low level function */
126     return DoTable (atByteTab, 1, DataByteLine);
127 }
128
129
130
131 unsigned DByteTable (void)
132 /* Output a table of dbytes */
133 {
134     /* Call the low level function */
135     return DoTable (atDByteTab, 2, DataDByteLine);
136 }
137
138
139
140 unsigned WordTable (void)
141 /* Output a table of words */
142 {
143     /* Call the low level function */
144     return DoTable (atWordTab, 2, DataWordLine);
145 }
146
147
148
149 unsigned DWordTable (void)
150 /* Output a table of double words */
151 {
152     /* Call the low level function */
153     return DoTable (atDWordTab, 4, DataDWordLine);
154 }
155
156
157
158 unsigned AddrTable (void)
159 /* Output a table of addresses */
160 {
161     unsigned BytesLeft;
162
163     /* Count how many bytes may be output. */
164     unsigned Count = GetSpan (atAddrTab);
165
166     /* Handle Count == 1 */
167     if (Count == 1) {
168         ByteTable ();
169     }
170
171     /* Make the given number even */
172     Count &= ~1U;
173
174     /* Output as many data bytes lines as needed. For addresses, each line
175      * will hold just one address.
176      */
177     BytesLeft = Count;
178     while (BytesLeft > 0) {
179
180         /* Get the address */
181         unsigned Addr = GetCodeWord (PC);
182
183         /* In pass 1, define a label, in pass 2 output the line */
184         if (Pass == 1) {
185             if (!HaveLabel (Addr)) {
186                 AddLabel (Addr, atIntLabel, MakeLabelName (Addr));
187             }
188         } else {
189             const char* Label = GetLabel (Addr);
190             if (Label == 0) {
191                 /* OOPS! Should not happen */
192                 Internal ("OOPS - Label for address %04X disappeard!", Addr);
193             }
194             Indent (MIndent);
195             Output (".word");
196             Indent (AIndent);
197             Output ("%s", Label);
198             LineComment (PC, 2);
199             LineFeed ();
200         }
201
202         /* Next line */
203         PC        += 2;
204         BytesLeft -= 2;
205     }
206
207     /* If the next line is not a byte table line, add a separator */
208     if (CodeLeft() && GetStyleAttr (PC) != atAddrTab) {
209         SeparatorLine ();
210     }
211
212     /* Return the number of bytes output */
213     return Count;
214 }
215
216
217
218 unsigned RtsTable (void)
219 /* Output a table of RTS addresses (address - 1) */
220 {
221     unsigned BytesLeft;
222
223     /* Count how many bytes may be output. */
224     unsigned Count = GetSpan (atRtsTab);
225
226     /* Handle Count == 1 */
227     if (Count == 1) {
228         ByteTable ();
229     }
230
231     /* Make the given number even */
232     Count &= ~1U;
233
234     /* Output as many data bytes lines as needed. For addresses, each line
235      * will hold just one address.
236      */
237     BytesLeft = Count;
238     while (BytesLeft > 0) {
239
240         /* Get the address */
241         unsigned Addr = (GetCodeWord (PC) + 1) & 0xFFFF;
242
243         /* In pass 1, define a label, in pass 2 output the line */
244         if (Pass == 1) {
245             if (!HaveLabel (Addr)) {
246                 AddLabel (Addr, atIntLabel, MakeLabelName (Addr));
247             }
248         } else {
249             const char* Label = GetLabel (Addr);
250             if (Label == 0) {
251                 /* OOPS! Should not happen */
252                 Internal ("OOPS - Label for address %04X disappeard!", Addr);
253             }
254             Indent (MIndent);
255             Output (".word");
256             Indent (AIndent);
257             Output ("%s-1", Label);
258             LineComment (PC, 2);
259             LineFeed ();
260         }
261
262         /* Next line */
263         PC        += 2;
264         BytesLeft -= 2;
265     }
266
267     /* If the next line is not a byte table line, add a separator */
268     if (CodeLeft() && GetStyleAttr (PC) != atRtsTab) {
269         SeparatorLine ();
270     }
271
272     /* Return the number of bytes output */
273     return Count;
274 }
275
276
277
278 unsigned TextTable (void)
279 /* Output a table of text messages */
280 {
281     /* Count how many bytes may be output. */
282     unsigned ByteCount = GetSpan (atTextTab);
283
284     /* Output as many data bytes lines as needed. */
285     unsigned BytesLeft = ByteCount;
286     while (BytesLeft > 0) {
287
288         unsigned I;
289
290         /* Count the number of characters that can be output as such */
291         unsigned Count = 0;
292         while (Count < BytesLeft && Count < BytesPerLine*4-1) {
293             unsigned char C = GetCodeByte (PC + Count);
294             if (C >= 0x20 && C <= 0x7E && C != '\"') {
295                 ++Count;
296             } else {
297                 break;
298             }
299         }
300
301         /* If we have text, output it */
302         if (Count > 0) {
303             unsigned CBytes;
304             Indent (MIndent);
305             Output (".text");
306             Indent (AIndent);
307             Output ("\"");
308             for (I = 0; I < Count; ++I) {
309                 Output ("%c", GetCodeByte (PC+I));
310             }
311             Output ("\"");
312             CBytes = Count;
313             while (CBytes > 0) {
314                 unsigned Chunk = CBytes;
315                 if (Chunk > BytesPerLine) {
316                     Chunk = BytesPerLine;
317                 }
318                 LineComment (PC, Chunk);
319                 LineFeed ();
320                 CBytes -= Chunk;
321                 PC += Chunk;
322             }
323             BytesLeft -= Count;
324         }
325
326         /* Count the number of bytes that must be output as bytes */
327         Count = 0;
328         while (Count < BytesLeft && Count < BytesPerLine) {
329             unsigned char C = GetCodeByte (PC + Count);
330             if (C < 0x20 || C > 0x7E || C == '\"') {
331                 ++Count;
332             } else {
333                 break;
334             }
335         }
336
337         /* If we have raw output bytes, print them */
338         if (Count > 0) {
339             DataByteLine (Count);
340             PC += Count;
341             BytesLeft -= Count;
342         }
343
344     }
345
346     /* If the next line is not a byte table line, add a separator */
347     if (CodeLeft() && GetStyleAttr (PC) != atTextTab) {
348         SeparatorLine ();
349     }
350
351     /* Return the number of bytes output */
352     return ByteCount;
353 }
354
355
356