]> git.sur5r.net Git - cc65/blob - src/cc65/segments.c
Working on the backend
[cc65] / src / cc65 / segments.c
1 /*****************************************************************************/
2 /*                                                                           */
3 /*                                segments.c                                 */
4 /*                                                                           */
5 /*                   Lightweight segment management stuff                    */
6 /*                                                                           */
7 /*                                                                           */
8 /*                                                                           */
9 /* (C) 2001      Ullrich von Bassewitz                                       */
10 /*               Wacholderweg 14                                             */
11 /*               D-70597 Stuttgart                                           */
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 #include <stdarg.h>
37 #include <string.h>
38
39 /* common */
40 #include "chartype.h"
41 #include "check.h"
42 #include "coll.h"
43 #include "scanner.h"
44 #include "xmalloc.h"
45
46 /* cc65 */
47 #include "codeent.h"
48 #include "codeseg.h"
49 #include "dataseg.h"
50 #include "textseg.h"
51 #include "segments.h"
52
53
54
55 /*****************************************************************************/
56 /*                                   Data                                    */
57 /*****************************************************************************/
58
59
60
61 /* Pointer to the current segment list. Output goes here. */
62 Segments* CS = 0;
63
64 /* Actual names for the segments */
65 static char* SegmentNames[SEG_COUNT];
66
67 /* We're using a collection for the stack instead of a linked list. Since
68  * functions may not be nested (at least in the current implementation), the
69  * maximum stack depth is 2, so there is not really a need for a better
70  * implementation.
71  */
72 static Collection SegmentStack = STATIC_COLLECTION_INITIALIZER;
73
74
75
76 /*****************************************************************************/
77 /*                                   Code                                    */
78 /*****************************************************************************/
79
80
81
82 void InitSegNames (void)
83 /* Initialize the segment names */
84 {
85     SegmentNames [SEG_BSS]      = xstrdup ("BSS");
86     SegmentNames [SEG_CODE]     = xstrdup ("CODE");
87     SegmentNames [SEG_DATA]     = xstrdup ("DATA");
88     SegmentNames [SEG_RODATA]   = xstrdup ("RODATA");
89 }
90
91
92
93 void NewSegName (segment_t Seg, const char* Name)
94 /* Set a new name for a segment */
95 {
96     /* Free the old name and set a new one */
97     xfree (SegmentNames [Seg]);
98     SegmentNames [Seg] = xstrdup (Name);
99 }
100
101
102
103 int ValidSegName (const char* Name)
104 /* Return true if the given segment name is valid, return false otherwise */
105 {
106     /* Must start with '_' or a letter */
107     if ((*Name != '_' && !IsAlpha(*Name)) || strlen(Name) > 80) {
108         return 0;
109     }
110
111     /* Can have letters, digits or the underline */
112     while (*++Name) {
113         if (*Name != '_' && !IsAlNum(*Name)) {
114             return 0;
115         }
116     }
117
118     /* Name is ok */
119     return 1;
120 }
121
122
123
124 static Segments* NewSegments (SymEntry* Func)
125 /* Initialize a Segments structure (set all fields to NULL) */
126 {
127     /* Allocate memory */
128     Segments* S = xmalloc (sizeof (Segments));
129
130     /* Initialize the fields */
131     S->Text     = NewTextSeg (Func);
132     S->Code     = NewCodeSeg (SegmentNames[SEG_CODE], Func);
133     S->Data     = NewDataSeg (SegmentNames[SEG_DATA], Func);
134     S->ROData   = NewDataSeg (SegmentNames[SEG_RODATA], Func);
135     S->BSS      = NewDataSeg (SegmentNames[SEG_BSS], Func);
136     S->CurDSeg  = SEG_DATA;
137
138     /* Return the new struct */
139     return S;
140 }
141
142
143
144 Segments* PushSegments (SymEntry* Func)
145 /* Make the new segment list current but remember the old one */
146 {
147     /* Push the current pointer onto the stack */
148     CollAppend (&SegmentStack, CS);
149
150     /* Create a new Segments structure */
151     CS = NewSegments (Func);
152
153     /* Return the new struct */
154     return CS;
155 }
156
157
158
159 void PopSegments (void)
160 /* Pop the old segment list (make it current) */
161 {
162     /* Must have something on the stack */
163     PRECONDITION (CollCount (&SegmentStack) > 0);
164
165     /* Pop the last segment and set it as current */
166     CS = CollPop (&SegmentStack);
167 }
168
169
170
171 void UseDataSeg (segment_t DSeg)
172 /* For the current segment list, use the data segment DSeg */
173 {
174     /* Check the input */
175     PRECONDITION (CS && DSeg != SEG_CODE);
176
177     /* Set the new segment to use */
178     CS->CurDSeg = DSeg;
179 }
180
181
182
183 struct DataSeg* GetDataSeg (void)
184 /* Return the current data segment */
185 {
186     PRECONDITION (CS != 0);
187     switch (CS->CurDSeg) {
188         case SEG_BSS:     return CS->BSS;
189         case SEG_DATA:    return CS->Data;
190         case SEG_RODATA:  return CS->ROData;
191         default:
192             FAIL ("Invalid data segment");
193             return 0;
194     }
195 }
196
197
198
199 void AddTextLine (const char* Format, ...)
200 /* Add a line of code to the current text segment */
201 {
202     va_list ap;
203     va_start (ap, Format);
204     CHECK (CS != 0);
205     TS_AddLine (CS->Text, Format, ap);
206     va_end (ap);
207 }
208
209
210
211 void AddCodeLine (const char* Format, ...)
212 /* Add a line of code to the current code segment */
213 {
214     va_list ap;
215     va_start (ap, Format);
216     CHECK (CS != 0);
217     CS_AddLine (CS->Code, CurTok.LI, Format, ap);
218     va_end (ap);
219 }
220
221
222
223 void AddCode (opc_t OPC, am_t AM, const char* Arg, struct CodeLabel* JumpTo)
224 /* Add a code entry to the current code segment */
225 {
226     CHECK (CS != 0);
227     CS_AddEntry (CS->Code, NewCodeEntry (OPC, AM, Arg, JumpTo, CurTok.LI));
228 }
229
230
231
232 void AddDataLine (const char* Format, ...)
233 /* Add a line of data to the current data segment */
234 {
235     va_list ap;
236     va_start (ap, Format);
237     CHECK (CS != 0);
238     DS_AddLine (GetDataSeg(), Format, ap);
239     va_end (ap);
240 }
241
242
243
244 static void PrintFunctionHeader (const SymEntry* Entry, FILE* F)
245 {
246     /* Print a comment with the function signature */
247     fprintf (F,
248              "; ---------------------------------------------------------------\n"
249              "; ");
250     PrintFuncSig (F, Entry->Name, Entry->Type);
251     fprintf (F,
252              "\n"
253              "; ---------------------------------------------------------------\n"
254              "\n");
255 }
256
257
258
259 void OutputSegments (const Segments* S, FILE* F)
260 /* Output the given segments to the file */
261 {
262     /* If the code segment is associated with a function, print a function header */
263     if (S->Code->Func) {
264         PrintFunctionHeader (S->Code->Func, F);
265     }
266
267     /* Output the text segment */
268     TS_Output (S->Text, F);
269
270     /* Output the three data segments */
271     DS_Output (S->Data, F);
272     DS_Output (S->ROData, F);
273     DS_Output (S->BSS, F);
274
275     /* Output the code segment */
276     CS_Output (S->Code, F);
277 }
278
279
280