Mercurial > hg > index.cgi
comparison lwasm/strings.c @ 519:724bcc4508bc
Add SETSTR/INCLUDESTR for some basic code building
It seemed useful to have the ability to build up a variable containing
arbitrary text and then to be able to include that in the assembly process
like an include file. So add, undocumented for now, the following:
SETTSTR varname="string"
INCLUDESTSR "string"
"string" must be enclosed in double quotes and may contain most of the usual
escape sequences (\t, \r, etc.) as well as %(varname) to interpolate a
variable value.
To use it to create assembleable source code, you need to make sure it
creates lines (ended by either \r or \n) with appropriate whitespace in
appropriate places.
author | William Astle <lost@l-w.ca> |
---|---|
date | Sun, 19 Dec 2021 17:01:42 -0700 |
parents | |
children |
comparison
equal
deleted
inserted
replaced
518:b530ff19f7c0 | 519:724bcc4508bc |
---|---|
1 /* | |
2 strings.c | |
3 Copyright © 2021 William Astle | |
4 | |
5 This file is part of LWASM. | |
6 | |
7 LWASM is free software: you can redistribute it and/or modify it under the | |
8 terms of the GNU General Public License as published by the Free Software | |
9 Foundation, either version 3 of the License, or (at your option) any later | |
10 version. | |
11 | |
12 This program is distributed in the hope that it will be useful, but WITHOUT | |
13 ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or | |
14 FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for | |
15 more details. | |
16 | |
17 You should have received a copy of the GNU General Public License along with | |
18 this program. If not, see <http://www.gnu.org/licenses/>. | |
19 | |
20 Contains stuff associated with generalized string parsing including | |
21 interpolation. | |
22 | |
23 A general string is enclosed in double quotes. Within the string, the | |
24 following is supported: | |
25 | |
26 %(VAR): a string variable defined with SETSTR | |
27 %[SYM]: the value of SYM; must be constant on pass 1 or will resolve to "" | |
28 \": a literal " | |
29 \%: a literal % | |
30 \n: a newline | |
31 \r: a carriage return | |
32 \t: a tab | |
33 \f: a form feed | |
34 \e: ESC (0x1b) | |
35 \\: a backslash | |
36 \xXX: an 8 bit value where XX are hex digits | |
37 | |
38 */ | |
39 | |
40 #include <ctype.h> | |
41 #include <string.h> | |
42 | |
43 #include <lw_alloc.h> | |
44 #include <lw_dict.h> | |
45 #include <lw_string.h> | |
46 #include <lw_strbuf.h> | |
47 | |
48 #include "lwasm.h" | |
49 #include "instab.h" | |
50 | |
51 void lwasm_stringvar_unset(asmstate_t *as, char *strname) | |
52 { | |
53 if (!(as -> stringvars)) | |
54 return; | |
55 lw_dict_unset(as -> stringvars, strname); | |
56 } | |
57 | |
58 void lwasm_stringvar_set(asmstate_t *as, char *strname, char *strval) | |
59 { | |
60 if (!(as -> stringvars)) | |
61 as -> stringvars = lw_dict_create(); | |
62 lw_dict_set(as -> stringvars, strname, strval); | |
63 } | |
64 | |
65 char *lwasm_stringvar_get(asmstate_t *as, char *strname) | |
66 { | |
67 if (!(as -> stringvars)) | |
68 return ""; | |
69 return lw_dict_get(as -> stringvars, strname); | |
70 } | |
71 | |
72 PARSEFUNC(pseudo_parse_setstr) | |
73 { | |
74 char *t1; | |
75 char *strname; | |
76 char *strval; | |
77 | |
78 l -> len = 0; | |
79 if (!**p) | |
80 { | |
81 lwasm_register_error(as, l, E_OPERAND_BAD); | |
82 return; | |
83 } | |
84 | |
85 for (t1 = *p; *t1 && *t1 != '='; t1++) | |
86 /* do nothing */; | |
87 strname = lw_alloc(t1 - *p + 1); | |
88 strncpy(strname, *p, t1 - *p); | |
89 strname[t1 - *p] = '\0'; | |
90 *p = t1; | |
91 if (**p == '\0') | |
92 { | |
93 lwasm_stringvar_unset(l -> as, strname); | |
94 lw_free(strname); | |
95 return; | |
96 } | |
97 (*p)++; | |
98 strval = lwasm_parse_general_string(l, p); | |
99 if (!strval) | |
100 { | |
101 lwasm_stringvar_unset(l -> as, strname); | |
102 lw_free(strname); | |
103 return; | |
104 } | |
105 lwasm_stringvar_set(l -> as, strname, strval); | |
106 lw_free(strval); | |
107 } | |
108 | |
109 char *lwasm_parse_general_string(line_t *l, char **p) | |
110 { | |
111 struct lw_strbuf *sb; | |
112 | |
113 if (!**p || isspace(**p)) | |
114 return lw_strdup(""); | |
115 if (**p != '"') | |
116 { | |
117 lwasm_register_error(l -> as, l, E_OPERAND_BAD); | |
118 return NULL; | |
119 } | |
120 | |
121 (*p)++; | |
122 sb = lw_strbuf_new(); | |
123 while (**p && **p != '"') | |
124 { | |
125 switch (**p) | |
126 { | |
127 case '\\': | |
128 if ((*p)[1]) | |
129 { | |
130 (*p)++; | |
131 switch (**p) | |
132 { | |
133 case 'n': | |
134 lw_strbuf_add(sb, 10); | |
135 break; | |
136 | |
137 case 'r': | |
138 lw_strbuf_add(sb, 13); | |
139 break; | |
140 | |
141 case 't': | |
142 lw_strbuf_add(sb, 9); | |
143 break; | |
144 | |
145 case 'f': | |
146 lw_strbuf_add(sb, 12); | |
147 break; | |
148 | |
149 case 'e': | |
150 lw_strbuf_add(sb, 27); | |
151 break; | |
152 | |
153 case 'x': | |
154 if ((*p)[1] && (*p)[2]) | |
155 { | |
156 int d1 = (*p)[1]; | |
157 int d2 = (*p)[2]; | |
158 if (d1 < '0' || (d1 > '9' && d1 < 'A') || (d1 > 'F' && d1 < 'a') || d1 > 'f' || | |
159 d2 < '0' || (d2 > '9' && d2 < 'A') || (d2 > 'F' && d2 < 'a') || d2 > 'f') | |
160 { | |
161 lw_strbuf_add(sb, 'x'); | |
162 } | |
163 else | |
164 { | |
165 (*p) += 2; | |
166 d1 -= '0'; | |
167 d2 -= '0'; | |
168 if (d1 > 9) | |
169 d1 -= 7; | |
170 if (d1 > 15) | |
171 d1 -= 32; | |
172 if (d2 > 9) | |
173 d2 -= 7; | |
174 if (d2 > 15) | |
175 d2 -= 32; | |
176 lw_strbuf_add(sb, (d1 << 4) | d2); | |
177 } | |
178 } | |
179 else | |
180 { | |
181 lw_strbuf_add(sb, 'x'); | |
182 } | |
183 break; | |
184 | |
185 default: | |
186 lw_strbuf_add(sb, **p); | |
187 break; | |
188 } | |
189 } | |
190 break; | |
191 | |
192 case '%': | |
193 (*p)++; | |
194 if (**p == '(') | |
195 { | |
196 char *t1; | |
197 // string var | |
198 for (t1 = *p + 1; *t1 && *t1 != ')' && *t1 != '"'; t1++) | |
199 /* do nothing */ ; | |
200 if (*t1 != ')') | |
201 { | |
202 lw_strbuf_add(sb, '%'); | |
203 (*p)--; | |
204 } | |
205 else | |
206 { | |
207 char *strname; | |
208 strname = lw_alloc(t1 - *p); | |
209 strncpy(strname, *p + 1, t1 - *p); | |
210 strname[t1 - *p - 1] = '\0'; | |
211 *p = t1; | |
212 t1 = lwasm_stringvar_get(l -> as, strname); | |
213 lw_free(strname); | |
214 for (strname = t1; *strname; strname++) | |
215 lw_strbuf_add(sb, *strname); | |
216 } | |
217 } | |
218 else | |
219 { | |
220 // unknown % sequence; back up and output the % | |
221 (*p)--; | |
222 lw_strbuf_add(sb, '%'); | |
223 } | |
224 break; | |
225 | |
226 default: | |
227 lw_strbuf_add(sb, **p); | |
228 } | |
229 (*p)++; | |
230 } | |
231 if (**p == '"') | |
232 (*p)++; | |
233 return lw_strbuf_end(sb); | |
234 } | |
235 |