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