ugBASIC 1.18
An isomorphic BASIC language compiler for retrocomputers
Loading...
Searching...
No Matches
_optimizer.c
Go to the documentation of this file.
1/*****************************************************************************
2 * ugBASIC - an isomorphic BASIC language compiler for retrocomputers *
3 *****************************************************************************
4 * Copyright 2021-2026 Marco Spedaletti (asimov@mclink.it)
5 *
6 * Licensed under the Apache License, Version 2.0 (the "License");
7 * you may not use this file except in compliance with the License.
8 * You may obtain a copy of the License at
9 *
10 * http://www.apache.org/licenses/LICENSE-2.0
11 *
12 * Unless required by applicable law or agreed to in writing, software
13 * distributed under the License is distributed on an "AS IS" BASIS,
14 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15 * See the License for the specific language governing permissions and
16 * limitations under the License.
17 *----------------------------------------------------------------------------
18 * Concesso in licenza secondo i termini della Licenza Apache, versione 2.0
19 * (la "Licenza"); è proibito usare questo file se non in conformità alla
20 * Licenza. Una copia della Licenza è disponibile all'indirizzo:
21 *
22 * http://www.apache.org/licenses/LICENSE-2.0
23 *
24 * Se non richiesto dalla legislazione vigente o concordato per iscritto,
25 * il software distribuito nei termini della Licenza è distribuito
26 * "COSÌ COM'È", SENZA GARANZIE O CONDIZIONI DI ALCUN TIPO, esplicite o
27 * implicite. Consultare la Licenza per il testo specifico che regola le
28 * autorizzazioni e le limitazioni previste dalla medesima.
29 ****************************************************************************/
30
31 /* Common optimizations routines for
32 - MOS 6502/6510
33 - Motorola 6809
34 - Zilog Z80
35 */
36
37/****************************************************************************
38 * INCLUDE SECTION
39 ****************************************************************************/
40
41#include "../../ugbc.h"
42#include <stdarg.h>
43
44/****************************************************************************
45 * CODE SECTION
46 ****************************************************************************/
47
48/* deallocate a buffer */
50 if(buf != NULL) {
51 free(buf->str);
52 buf->str = NULL;
53 buf->cap = 0;
54 buf->len = 0;
55 free(buf);
56 }
57
58 return NULL;
59}
60
61/* allocate a buffer */
63 POBuffer buf = malloc(sizeof(*buf));
64 if(buf != NULL) {
65 buf->len = 0;
66 buf->cap = size+1;
67 buf->str = malloc(buf->cap);
68 buf->str[0] = '\0';
69 }
70 return buf;
71}
72
73/* ensure the buffer can hold len data */
74static POBuffer _buf_cap(POBuffer buf, int len) {
75 if(len+1 >= buf->cap) {
76 buf->cap = len + 1 + 2*MAX_TEMPORARY_STORAGE;
77 buf->str = realloc(buf->str, buf->cap);
78 }
79 return buf;
80}
81
82/* append a string to a buffer */
83POBuffer po_buf_cat(POBuffer buf, char *string) {
84 if(buf != NULL) {
85 int len = strlen(string);
86 _buf_cap(buf, buf->len + len);
87 strcopy(&buf->str[buf->len], string);
88 buf->len += len;
89 }
90 return buf;
91}
92
93/* copy a string into a buffer */
94POBuffer po_buf_cpy(POBuffer buf, char *string) {
95 if(buf != NULL) buf->len = 0;
96 return po_buf_cat(buf, string);
97}
98
99/* append a char at the end of the buffer */
101 if(buf) {
102 _buf_cap(buf, buf->len + 1);
103 buf->str[buf->len] = c;
104 ++buf->len;
105 buf->str[buf->len] = '\0';
106 }
107 return buf;
108}
109
110/* vprintf like function */
111POBuffer po_buf_vprintf(POBuffer buf, const char *fmt, va_list ap) {
112 if(buf != NULL) {
113 int len = 0, avl;
114 do {
115 _buf_cap(buf, buf->len + len);
116 avl = buf->cap - buf->len;
117 len = vsnprintf(&buf->str[buf->len], avl, fmt, ap);
118 } while(len >= avl);
119 buf->len += len;
120 }
121 return buf;
122}
123
124/* sprintf like function */
125#ifdef __GNUC__
126POBuffer po_buf_printf(POBuffer buf, const char *fmt, ...)
127 __attribute__ ((format (printf, 2, 3)));
128#endif
129POBuffer po_buf_printf(POBuffer buf, const char *fmt, ...) {
130 va_list ap;
131 va_start(ap, fmt);
132 po_buf_vprintf(buf, fmt, ap);
133 va_end(ap);
134 return buf;
135}
136
137/* fgets-like */
139 int c;
140
141 po_buf_cpy(buf, "");
142
143 while( (c = fgetc(f)) != EOF) {
144 po_buf_add(buf, (char)c);
145 if(c=='\n') break;
146 }
147
148 return buf;
149}
150
151/* strcmp */
153 if(a) return b ? strcmp(a->str, b->str) : 1;
154 else return -1;
155}
156
158
159 if ( buf->len <= 1 ) {
160 return 0;
161 }
162
163 char * p = buf->str;
164 char * q = buf->str + buf->len - 1;
165 while((p-buf->str) < buf->len) {
166 if ( ! ( (*p == ' ') || (*p == '\n') || (*p == '\r') || (*p == 13) || (*p == 10) || (*p == '\t') ) ) {
167 break;
168 };
169 ++p;
170 }
171 while(q > p) {
172 if ( ! ( (*q == ' ') || (*q == 10) || (*q == 13) || (*q == '\t') ) ) {
173 break;
174 };
175 --q;
176 }
177 *(q+1) = 0;
178 unsigned long realLen = ( q - p ) + 1;
179 if ( p != buf->str ) {
180 memmove( buf->str, p, realLen );
181 }
182 buf->len = realLen;
183 *(buf->str + realLen) = 0;
184 return p - buf->str;
185}
186
187/* returns an UPPER-cased char */
188static inline char _toUpper(char a) {
189 return (a>='a' && a<='z') ? a-'a'+'A' : a;
190}
191
192/* returns true if char is end of line ? */
193static inline int _eol(char c) {
194 return c=='\0' || c=='\n';
195}
196
197/* returns true if both char matches */
198static inline int _eq(char pat, char txt) {
199 return (pat<=' ') ? (txt<=' ') : (_toUpper(pat)==_toUpper(txt));
200}
201
202#define TMP_BUF_POOL 128
203static struct tmp_buf_pool {
204 POBuffer buf;
205 void *key1;
206 int key2;
207} tmp_buf_pool[TMP_BUF_POOL];
208
209/* an integer hash
210 https://gist.github.com/badboy/6267743
211*/
212static unsigned int tmp_buf_hash(unsigned int key) {
213 key ^= (key<<17) | (key>>16);
214 return key;
215}
216
217/* a static one-time buffer */
218POBuffer tmp_buf(void *key1, unsigned int key2) {
219 int hash = tmp_buf_hash(((intptr_t)key1)*31 + key2) % TMP_BUF_POOL;
220 struct tmp_buf_pool *tmp = &tmp_buf_pool[hash];
221 int count = 0;
222
223 while(tmp->buf!=NULL && (tmp->key1!=key1 || tmp->key2!=key2)) {
224 ++count;
225 if(++tmp == &tmp_buf_pool[TMP_BUF_POOL]) {
226 tmp = tmp_buf_pool;
227 }
228 }
229
230 if(tmp->buf == NULL) {
231 if(count == TMP_BUF_POOL) {
232 fprintf(stderr, "TMP_BUF_POOL to short\n");
233 exit(-1);
234 }
235 tmp->buf = po_buf_new(0);
236 tmp->key1 = key1;
237 tmp->key2 = key2;
238 }
239
240 return tmp->buf;
241}
242
243void tmp_buf_clr(void *key1) {
244 struct tmp_buf_pool *tmp = &tmp_buf_pool[0];
245 for(;tmp!=&tmp_buf_pool[TMP_BUF_POOL];++tmp) {
246 if(tmp->key1 == key1) tmp->buf = po_buf_del(tmp->buf);
247 }
248}
249
250/* a version of strcmp that ends at EOL and deal our special equality. */
252 char *s = _s->str, *t = _t->str;
253
254 while(!_eol(*s) && !_eol(*t) && _eq(*s,*t)) {
255 ++s;
256 ++t;
257 }
258 return _eol(*s) && _eol(*t) ? 0 : _eol(*s) ? 1 : -1;
259}
260
261/* Matches a string:
262 - ' ' maches anthing <= ' ' (eg 'r', \n', '\t' or ' ' )
263 - '*' matches up to the next one in the pattern.
264 Matched content is copied into buffers passed as varargs. If
265 a passed variable is NULL the matched content corresponding
266 to it is not copied.
267
268 Returns the last matched '*' or the buffer if pattern is fully
269 matched, or NULL otherwise meaning "no match".
270*/
271POBuffer po_buf_match(POBuffer _buf, const char *_pattern, ...) {
272 POBuffer ret = _buf;
273 const char *s = _buf->str, *p = _pattern;
274 va_list ap;
275
276 va_start(ap, _pattern);
277
278 while(!_eol(*s) && *p) {
279 if(*p==' ') {while(*p==' ') ++p;
280 if(!_eq(' ', *s)) {
281 ret = NULL;
282 break;
283 }
284 while(!_eol(*s) && _eq(' ', *s)) ++s;
285 } else if(*p=='^') {
286 ++p;
287 while(!_eol(*s) && !_eq(*p, *s)) ++s;
288 if(!_eq(*p,*s)) {
289 ret = NULL;
290 break;
291 }
292 } else if( *p=='*' ) {
293 if ( *(p+1) == '*' ) {
294 if(*s != '*') {
295 ret = NULL;
296 break;
297 }
298 ++p;++p;
299 ++s;
300 continue;
301 }
302 POBuffer m = va_arg(ap, POBuffer); ++p;
303 if(m != NULL) {
304 ret = po_buf_cpy(m, "");
305 }
306 while(!_eol(*s) && !_eq(*p, *s)) po_buf_add(m, *s++);
307 if(!_eq(*p,*s)) {
308 ret = NULL;
309 break;
310 }
311 } else if(_toUpper(*s++) != _toUpper(*p++)) {
312 ret = NULL;
313 break;
314 }
315 }
316
317 va_end(ap);
318
319 return *p=='\0' ? ret : NULL;
320}
321
322/* Check if buffer is a (hexadecimal) number */
324 char *s = _s->str;
325
326 while(!_eol(*s)) {
327 if ( ( (*s) < '0' || (*s) > '9' ) && ( (*s) < 'a' || (*s) > 'f' ) && ( (*s) < 'A' || (*s) > 'Z' ) )
328 return 0;
329 ++s;
330 }
331 return 1;
332}
333
335
336void po_var_init( ) {
337 variables = NULL;
338}
339
340POVariable * po_var_register( char * _name ) {
341 POVariable * variable = malloc( sizeof( POVariable ) );
342 memset( variable, 0, sizeof( POVariable ) );
343 variable->name = strdup( _name );
344 variable->next = variables;
345 variables = variable;
346 return variable;
347}
348
349POVariable * po_var_find( char * _name ) {
350 POVariable * variable = variables;
351 while( variable ) {
352 if ( strcmp( _name, variable->name ) == 0 ) {
353 return variable;
354 }
355 variable = variable->next;
356 }
357 return NULL;
358}
359
360POVariable * po_var_lookup( char * _name ) {
361 POVariable * variable = po_var_find( _name );
362 if ( variable ) {
363 return variable;
364 } else {
365 return po_var_register( _name );
366 }
367}
int size
Definition _optimizer.c:678
#define TMP_BUF_POOL
Definition _optimizer.c:202
POBuffer po_buf_match(POBuffer _buf, const char *_pattern,...)
Definition _optimizer.c:271
POVariable * variables
Definition _optimizer.c:334
POVariable * po_var_register(char *_name)
Definition _optimizer.c:340
POBuffer po_buf_new(int size)
Definition _optimizer.c:62
POBuffer po_buf_printf(POBuffer buf, const char *fmt,...)
Definition _optimizer.c:129
int po_buf_strcmp(POBuffer _s, POBuffer _t)
Definition _optimizer.c:251
POBuffer po_buf_cpy(POBuffer buf, char *string)
Definition _optimizer.c:94
POBuffer tmp_buf(void *key1, unsigned int key2)
Definition _optimizer.c:218
POBuffer po_buf_del(POBuffer buf)
Definition _optimizer.c:49
void tmp_buf_clr(void *key1)
Definition _optimizer.c:243
POBuffer po_buf_add(POBuffer buf, char c)
Definition _optimizer.c:100
POVariable * po_var_lookup(char *_name)
Definition _optimizer.c:360
int po_buf_is_hex(POBuffer _s)
Definition _optimizer.c:323
int po_buf_trim(POBuffer buf)
Definition _optimizer.c:157
void po_var_init()
Definition _optimizer.c:336
POBuffer po_buf_vprintf(POBuffer buf, const char *fmt, va_list ap)
Definition _optimizer.c:111
POBuffer po_buf_cat(POBuffer buf, char *string)
Definition _optimizer.c:83
int po_buf_cmp(POBuffer a, POBuffer b)
Definition _optimizer.c:152
POVariable * po_var_find(char *_name)
Definition _optimizer.c:349
POBuffer po_buf_fgets(POBuffer buf, FILE *f)
Definition _optimizer.c:138
char * str
Definition ugbc.h:293
int cap
Definition ugbc.h:295
int len
Definition ugbc.h:294
char * name
Definition ugbc.h:301
struct _POVariable * next
Definition ugbc.h:304
void * malloc(YYSIZE_T)
void free(void *)
#define MAX_TEMPORARY_STORAGE
Definition ugbc.h:563
struct _POVariable POVariable
Definition ugbc.h:307
struct _POBuffer * POBuffer
Definition ugbc.h:298
char * strcopy(char *_dest, char *_source)