1 | /*****************************************************************************/ |
2 | /* */ |
3 | /* asminc.c */ |
4 | /* */ |
5 | /* Read an assembler include file containing symbols */ |
6 | /* */ |
7 | /* */ |
8 | /* */ |
9 | /* (C) 2005-2008 Ullrich von Bassewitz */ |
10 | /* Roemerstrasse 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 | #include <stdio.h> |
37 | #include <errno.h> |
38 | |
39 | /* common */ |
40 | #include "chartype.h" |
41 | #include "strbuf.h" |
42 | |
43 | /* da65 */ |
44 | #include "asminc.h" |
45 | #include "comments.h" |
46 | #include "error.h" |
47 | #include "labels.h" |
48 | |
49 | |
50 | |
51 | /*****************************************************************************/ |
52 | /* Code */ |
53 | /*****************************************************************************/ |
54 | |
55 | |
56 | |
57 | static char* SkipWhitespace (char* L) |
58 | /* Ignore white space in L */ |
59 | { |
60 | while (IsBlank (*L)) { |
61 | ++L; |
62 | } |
63 | return L; |
64 | } |
65 | |
66 | |
67 | |
68 | unsigned DigitVal (unsigned char C) |
69 | /* Return the value of the given digit */ |
70 | { |
71 | if (IsDigit (C)) { |
72 | return C - '0'; |
73 | } else { |
74 | return tolower (C) - 'a' + 10; |
75 | } |
76 | } |
77 | |
78 | |
79 | |
80 | void AsmInc (const char* Filename, char , int IgnoreUnknown) |
81 | /* Read an assembler include file */ |
82 | { |
83 | char Buf[1024]; |
84 | char* L; |
85 | const char* ; |
86 | unsigned Line; |
87 | unsigned Len; |
88 | long Val; |
89 | unsigned DVal; |
90 | int Sign; |
91 | unsigned Base; |
92 | unsigned Digits; |
93 | StrBuf Ident = STATIC_STRBUF_INITIALIZER; |
94 | |
95 | /* Try to open the file for reading */ |
96 | FILE* F = fopen (Filename, "r" ); |
97 | if (F == 0) { |
98 | Error ("Cannot open asm include file \"%s\": %s" , |
99 | Filename, strerror (errno)); |
100 | } |
101 | |
102 | /* Read line by line, check for NAME = VALUE lines */ |
103 | Line = 0; |
104 | while ((L = fgets (Buf, sizeof (Buf), F)) != 0) { |
105 | |
106 | /* One more line read */ |
107 | ++Line; |
108 | |
109 | /* Ignore leading white space */ |
110 | while (IsBlank (*L)) { |
111 | ++L; |
112 | } |
113 | |
114 | /* Remove trailing whitespace */ |
115 | Len = strlen (L); |
116 | while (Len > 0 && IsSpace (L[Len-1])) { |
117 | --Len; |
118 | } |
119 | L[Len] = '\0'; |
120 | |
121 | /* If the line is empty or starts with a comment char, ignore it */ |
122 | if (*L == '\0' || *L == CommentStart) { |
123 | continue; |
124 | } |
125 | |
126 | /* Read an identifier */ |
127 | SB_Clear (&Ident); |
128 | if (IsAlpha (*L) || *L == '_') { |
129 | SB_AppendChar (&Ident, *L++); |
130 | while (IsAlNum (*L) || *L == '_') { |
131 | SB_AppendChar (&Ident, *L++); |
132 | } |
133 | SB_Terminate (&Ident); |
134 | } else { |
135 | if (!IgnoreUnknown) { |
136 | Error ("%s(%u): Syntax error" , Filename, Line); |
137 | } |
138 | continue; |
139 | } |
140 | |
141 | /* Ignore white space */ |
142 | L = SkipWhitespace (L); |
143 | |
144 | /* Check for := or = */ |
145 | if (*L == '=') { |
146 | ++L; |
147 | } else if (*L == ':' && *++L == '=') { |
148 | ++L; |
149 | } else { |
150 | if (!IgnoreUnknown) { |
151 | Error ("%s(%u): Missing '='" , Filename, Line); |
152 | } |
153 | continue; |
154 | } |
155 | |
156 | /* Allow white space once again */ |
157 | L = SkipWhitespace (L); |
158 | |
159 | /* A number follows. Read the sign. */ |
160 | if (*L == '-') { |
161 | Sign = -1; |
162 | ++L; |
163 | } else { |
164 | Sign = 1; |
165 | if (*L == '+') { |
166 | ++L; |
167 | } |
168 | } |
169 | |
170 | /* Determine the base of the number. Allow $ and % as prefixes for |
171 | ** hex and binary numbers respectively. |
172 | */ |
173 | if (*L == '$') { |
174 | Base = 16; |
175 | ++L; |
176 | } else if (*L == '%') { |
177 | Base = 2; |
178 | ++L; |
179 | } else { |
180 | Base = 10; |
181 | } |
182 | |
183 | /* Decode the number */ |
184 | Digits = 0; |
185 | Val = 0; |
186 | while (IsXDigit (*L) && (DVal = DigitVal (*L)) < Base) { |
187 | Val = (Val * Base) + DVal; |
188 | ++Digits; |
189 | ++L; |
190 | } |
191 | |
192 | /* Must have at least one digit */ |
193 | if (Digits == 0) { |
194 | if (!IgnoreUnknown) { |
195 | Error ("%s(%u): Error in number format" , Filename, Line); |
196 | } |
197 | continue; |
198 | } |
199 | |
200 | /* Skip whitespace again */ |
201 | L = SkipWhitespace (L); |
202 | |
203 | /* Check for a comment */ |
204 | if (*L == CommentStart) { |
205 | Comment = SkipWhitespace (L+1); |
206 | if (*Comment == '\0') { |
207 | Comment = 0; |
208 | } |
209 | } else { |
210 | Comment = 0; |
211 | } |
212 | |
213 | /* Check for a comment character or end of line */ |
214 | if (*L != CommentStart && *L != '\0') { |
215 | if (!IgnoreUnknown) { |
216 | Error ("%s(%u): Trailing garbage" , Filename, Line); |
217 | } |
218 | continue; |
219 | } |
220 | |
221 | /* Apply the sign */ |
222 | Val *= Sign; |
223 | |
224 | /* Define the symbol and the comment */ |
225 | AddExtLabel (Val, SB_GetConstBuf (&Ident)); |
226 | SetComment (Val, Comment); |
227 | |
228 | } |
229 | |
230 | /* Delete the string buffer contents */ |
231 | SB_Done (&Ident); |
232 | |
233 | /* Close the include file ignoring errors (we were just reading). */ |
234 | (void) fclose (F); |
235 | } |
236 | |