1 /* -*- c -*- */
2
3 /*
4 * commands.c
5 *
6 * chpp
7 *
8 * Copyright (C) 1997-1999 Heinz Deinhart
9 *
10 * This program is free software; you can redistribute it and/or
11 * modify it under the terms of the GNU General Public License
12 * as published by the Free Software Foundation; either version 2
13 * of the License, or (at your option) any later version.
14 *
15 * This program is distributed in the hope that it will be useful,
16 * but WITHOUT ANY WARRANTY; without even the implied warranty of
17 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18 * GNU General Public License for more details.
19 *
20 * You should have received a copy of the GNU General Public License
21 * along with this program; if not, write to the Free Software
22 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
23 */
24
25 #include "commands.h"
26 #include "filler.h"
27
28 #include <stdio.h>
29 #include <stdarg.h>
30 #include <stdlib.h>
31 #include <string.h>
32
33 #include "memory.h"
34 #include "dynstring.h"
35 /*#include "macros.h"*/
36 /*#include "symtab.h"*/
37 #include "arith.h"
38 #include "error.h"
39 #include "parser.h"
40 #include "input.h"
41
42 extern int bufPosAtCommandBegin;
43
44 extern char filler_cmdChar;
45 extern int flowsExtern;
46 extern dynstring externFlow;
47 extern FlowStack *flowStack;
48 extern int flowDepth;
49 extern int zeilenNummer;
50 extern int incFiles;
51 extern dynstring currentFileName;
52 extern InputFileStack *ifStack;
53
54 /* static flowLevel = 1; */
55
evalDS(dynstring * ds)56 static dynstring evalDS( dynstring *ds ) {
57 dynstring eds = dsNew();
58 inputReader ir = irNewDynstring(ds, 0);
59 outputWriter ow = owNewDynstring(&eds);
60
61 parParseUntil(&ir, 0, bcwNewOutput(globalEnvironment, &ow), 1, globalEnvironment, 0);
62 return eds;
63 }
64
eatDSUntil(dynstring * body,int * pos,const char * set)65 static dynstring eatDSUntil( dynstring *body, int *pos, const char *set ) {
66 int origPos = *pos;
67 while( (*pos) < body->length ) {
68 const char *setElement = set;
69
70 while( (*setElement) != 0 ) {
71 if( (*setElement) == body->data[(*pos)] ) {
72 return dsNewFromBytes( &(body->data[origPos]), (*pos) - origPos );
73 }
74 setElement++;
75 }
76 (*pos)++;
77 }
78 return dsCopy( body );
79 }
80
81 void
emmitLocation(const char * muh)82 emmitLocation( const char *muh ) {
83 dynstring fHira;
84 InputFileStack *ifs = ifStack;
85 static char kurdenBuffer[100];
86
87 fHira = dsNew();
88 if( incFiles > 1 ) {
89 dsAppendString( &fHira, " (", 2 );
90 while( ifs ) {
91 dsAppendString( &fHira, ifs->name.data, ifs->name.length );
92 dsAppendChar( &fHira, ':' );
93 sprintf( kurdenBuffer, "%i", ifs->zeilenNummer );
94 dsAppendString( &fHira, kurdenBuffer, strlen( kurdenBuffer ));
95 ifs = ifs->next;
96 if( ifs ) dsAppendString( &fHira, ", ", 2 );
97 }
98 dsAppendChar( &fHira, ')' );
99 }
100 fprintf( stderr, "%s: file %s:%i%s\n",
101 muh, currentFileName.data, zeilenNummer, fHira.data );
102 }
103
104 /*
105 void
106 commandFatalError( const char *cmd, const char *format, ... ) {
107 va_list ap;
108
109 emmitLocation( "ERROR" );
110
111 fprintf( stderr, " %c%s: ", filler_cmdChar, cmd );
112 va_start( ap, format );
113 vfprintf( stderr, format, ap );
114 va_end( ap );
115 fprintf( stderr, "\n" );
116 exit( 1 );
117 }
118
119 void
120 commandWarning( const char *cmd, const char *format, ... ) {
121 va_list ap;
122
123 emmitLocation( "WARNING" );
124
125 fprintf( stderr, " %c%s: ", filler_cmdChar, cmd );
126 va_start( ap, format );
127 vfprintf( stderr, format, ap );
128 va_end( ap );
129 fprintf( stderr, "\n" );
130 }
131 */
132
133 void
cmd_error(const char * what)134 cmd_error( const char *what ) {
135 issueError( ERRCMD_USER_ERROR, what, 0, 0 );
136 }
137
138 void
cmd_rem(const char * what)139 cmd_rem( const char *what ) {
140 // 1 + 1 = 3
141 }
142
143 void
cmd_elseif(const char * what)144 cmd_elseif( const char *what ) {
145 if( !what ) {
146 issueWarning( ERRCMD_ONE_ARG, "ifdef", 0, 0 );
147 return;
148 }
149 cmd_endif( 0 );
150 cmd_if( what );
151 }
152
153 void
cmd_if(const char * what)154 cmd_if( const char *what ) {
155 FlowStack *tmpFS = (FlowStack *)memXAlloc( sizeof( FlowStack ));
156 dynstring eds, ds;
157
158 if( !what ) {
159 issueWarning( ERRCMD_ONE_ARG, "if", 0, 0);
160 return;
161 }
162 ds = dsNewFrom( what );
163
164 if( flowStack->flowLevel ) {
165 dynstring tmpDS;
166 dsRemoveOuterWS( &ds );
167 eds = evalDS( &ds );
168
169 tmpDS = arithEvalDS( &eds, globalEnvironment );
170 if( atoi( tmpDS.data )) tmpFS->flowLevel = 1;
171 else tmpFS->flowLevel = 0; /* discard all */
172 } else {
173 tmpFS->flowLevel = 0;
174 }
175 tmpFS->openCmd = CMD_IF;
176
177 tmpFS->next = flowStack;
178 flowStack = tmpFS;
179 flowDepth++;
180 }
181
182 void
cmd_ifdef(const char * what)183 cmd_ifdef( const char *what ) {
184 FlowStack *tmpFS = (FlowStack *)memXAlloc( sizeof( FlowStack ));
185 dynstring eds, ds;
186
187 if( !what ) {
188 issueWarning( ERRCMD_ONE_ARG, "ifdef", 0, 0);
189 return;
190 }
191 ds = dsNewFrom( what );
192
193 if( flowStack->flowLevel ) {
194 dsRemoveOuterWS( &ds );
195 eds = evalDS( &ds );
196
197 if( envGetBinding(globalEnvironment, &eds ) != 0 ) tmpFS->flowLevel = 1;
198 else tmpFS->flowLevel = 0; /* discard all */
199 } else {
200 tmpFS->flowLevel = 0;
201 }
202 tmpFS->openCmd = CMD_IFDEF;
203
204 tmpFS->next = flowStack;
205 flowStack = tmpFS;
206 flowDepth++;
207 }
208
209 void
cmd_ifndef(const char * what)210 cmd_ifndef( const char *what ) {
211 FlowStack *tmpFS = (FlowStack *)memXAlloc( sizeof( FlowStack ));
212 dynstring eds, ds;
213
214 if( !what ) {
215 issueWarning( ERRCMD_ONE_ARG, "ifdef", 0, 0);
216 return;
217 }
218 ds = dsNewFrom( what );
219
220 if( flowStack->flowLevel ) {
221 dsRemoveOuterWS( &ds );
222 eds = evalDS( &ds );
223
224 if( envGetBinding(globalEnvironment, &eds ) == 0) tmpFS->flowLevel = 1;
225 else tmpFS->flowLevel = 0; /* discard all */
226 } else {
227 tmpFS->flowLevel = 0;
228 }
229 tmpFS->openCmd = CMD_IFNDEF;
230
231 tmpFS->next = flowStack;
232 flowStack = tmpFS;
233 flowDepth++;
234 }
235
236 void
cmd_else(const char * arg)237 cmd_else( const char *arg ) {
238 if( arg ) issueWarning( WARNCMD_UNUSED_ARGS, "else", 0, 0);
239
240 switch( flowStack->openCmd ) {
241 case CMD_IFDEF:
242 case CMD_IFNDEF:
243 case CMD_IF:
244 flowStack->openCmd++; /* IFXX_ELSE is always IFXX + 1 !! */
245 flowStack->flowLevel = (flowStack->flowLevel + 1) % 2;
246
247 /* wenn ma schon im discard war, hilfts nix */
248 if( flowStack->next && !flowStack->next->flowLevel )
249 flowStack->flowLevel = 0;
250 break;
251 default:
252 issueError(ERRCMD_UNMATCHED_COMMAND, "else", 0, 0);
253 }
254 }
255
256 void
cmd_endif(const char * arg)257 cmd_endif( const char *arg ) {
258 FlowStack *tmpFS = flowStack;
259
260 if( arg ) issueWarning( WARNCMD_UNUSED_ARGS, "endif", 0, 0);
261
262 switch( flowStack->openCmd ) {
263 case CMD_IFDEF:
264 case CMD_IFDEF_ELSE:
265 case CMD_IFNDEF:
266 case CMD_IFNDEF_ELSE:
267 case CMD_IF:
268 case CMD_IF_ELSE:
269 flowDepthCeck();
270 flowDepth--;
271 flowStack = tmpFS->next;
272 memFree( tmpFS );
273 break;
274 default:
275 issueError( ERRCMD_UNMATCHED_COMMAND, "endif", 0, 0 );
276 }
277 }
278
279 void
cmd_discard(const char * arg)280 cmd_discard( const char *arg ) {
281 FlowStack *tmpFS = (FlowStack *)memXAlloc( sizeof( FlowStack ));
282
283 if( arg ) issueWarning( WARNCMD_UNUSED_ARGS, "discard", 0, 0);
284
285 tmpFS->flowLevel = 0; /* discard all */
286 tmpFS->openCmd = CMD_DISCARD;
287
288 tmpFS->next = flowStack;
289 flowStack = tmpFS;
290 flowDepth++;
291 }
292
293 void
cmd_endd(const char * arg)294 cmd_endd( const char *arg ) {
295 FlowStack *tmpFS = flowStack;
296
297 if( arg ) issueWarning( WARNCMD_UNUSED_ARGS, "endd", 0, 0);
298 if( flowStack->openCmd != CMD_DISCARD )
299 issueError( ERRCMD_UNMATCHED_COMMAND, "endd", 0, 0);
300
301 flowDepthCeck();
302 flowDepth--;
303 flowStack = tmpFS->next;
304 memFree( tmpFS );
305 }
306
307 void
cmd_include(const char * fileName)308 cmd_include( const char *fileName ) {
309 dynstring evald, fn;
310 /* FILE *ifi;*/
311
312 if( !fileName ) {
313 issueWarning( ERRCMD_ONE_ARG, "include", 0, 0);
314 return;
315 }
316 fn = dsNewFrom( fileName );
317 if( !flowStack->flowLevel ) return;
318
319 evald = evalDS( &fn );
320 dsRemoveOuterWS( &evald );
321 /* // obsolete:
322
323 ifi = fopen( evald.data, "r" );
324 if( !ifi )
325 issueError(ERRCMD_NO_INCLUDE, evald.data, 0, 0);
326 includeFile( ifi, fileName );
327 */
328
329 if( !includeFile( evald.data ))
330 issueError( ERRCMD_NO_INCLUDE, evald.data, 0, 0 );
331 }
332
333 static dynstring *edef_dynAr;
334 static int edef_dynNr;
335 static dynstring edef_evaldName;
336 static int edef_itIsSimple;
337
338 void
cmd_edefine(const char * args)339 cmd_edefine( const char *args ) {
340 dynstring name, body = dsNewFrom( args );
341 int pos = 0;
342 FlowStack *tmpFS = (FlowStack *)memXAlloc( sizeof( FlowStack ));
343
344 if( flowStack->flowLevel ) {
345 tmpFS->flowLevel = 1; /* discard all */
346 } else {
347 tmpFS->flowLevel = 0;
348 }
349 tmpFS->openCmd = CMD_EDEF;
350
351 tmpFS->next = flowStack;
352 flowStack = tmpFS;
353 flowDepth++;
354
355 if( !flowStack->flowLevel ) return;
356
357 dsRemoveOuterWS( &body ); /* only 1 arg, so we can remove the spaces */
358
359 name = eatDSUntil( &body, &pos, " \t(" );
360 if( body.data[pos] == '(' ) { /* macro with arguments */
361 dynstring parms = eatDSUntil( &body, &pos, ")" );
362
363 if( pos == body.length )
364 issueError(ERRCMD_CLOSE_PAREN_EXPECTED, 0, 0, 0);
365 if( pos != body.length - 1 ) {
366 issueError(ERRCMD_ONE_ARG, "edefine", 0, 0);
367 }
368 /* dsShrinkFront( &body, pos+1 ); */
369 dsRemoveOuterWS( &body );
370 if( parms.length ) { /* parse arguments outya ! */
371 dynstring first = dsNew();
372 dynstring second = dsNew();
373 int pos = 1;
374 int dynSize = 8;
375
376 edef_dynAr = (dynstring *)memXAlloc( sizeof( dynstring ) * 8 );
377 edef_dynNr = 0;
378 second = eatDSUntil( &parms, &pos, "," );
379 dsRemoveOuterWS( &second );
380 evalDS( &second );
381 edef_dynAr[edef_dynNr++] = dsCopy( &second );
382 pos++;
383 while( parms.length > pos ) {
384 first = eatDSUntil( &parms, &pos, "," );
385 dsRemoveOuterWS( &first );
386 evalDS( &first );
387 pos++;
388 if( edef_dynNr == dynSize ) {
389 dynSize += 8;
390 edef_dynAr = (dynstring *)memXRealloc( edef_dynAr, sizeof( dynstring ) *
391 dynSize );
392 }
393 edef_dynAr[edef_dynNr++] = dsCopy( &first );
394 }
395
396 edef_itIsSimple = 0;
397 edef_evaldName = evalDS( &name );
398 flowsExtern = 1;
399 externFlow = dsNew();
400 return;
401 /* defineGlobalUserDefined( &evaldName, edef_dynNr, dynAr, &body ); */
402 }
403 /* else no */
404 } /* macro with arguments */
405
406 if( pos != body.length )
407 issueError(ERRCMD_ONE_ARG, "edefine", 0, 0);
408
409 edef_itIsSimple = 1;
410 edef_evaldName = evalDS( &name );
411 /*
412 // dsShrinkFront( &body, pos+1 );
413 // dsRemoveOuterWS( &body );
414 // edef_body = dsCopy( &body );
415 // defineGlobalVariable( &evaldName, &body );
416 */
417 flowsExtern = 1;
418 externFlow = dsNew();
419 }
420
421 void
cmd_ende(const char * args)422 cmd_ende( const char * args ) {
423 FlowStack *tmpFS = flowStack;
424 dynstring ef2;
425
426 if( args ) issueWarning( WARNCMD_UNUSED_ARGS, "endd", 0, 0);
427 if( flowStack->openCmd != CMD_EDEF )
428 issueError(ERRCMD_UNMATCHED_COMMAND, "ende", 0, 0);
429
430 flowDepthCeck();
431 flowDepth--;
432 flowStack = tmpFS->next;
433 memFree( tmpFS );
434
435 flowsExtern = 0;
436
437 dsShrinkRear( &externFlow, 1 );
438 ef2 = evalDS( &externFlow );
439
440 /* now define the macro */
441 if( edef_itIsSimple ) {
442 envModifyOrAddBinding(globalEnvironment, &edef_evaldName,
443 valueNewScalar(&ef2), globalEnvironment);
444 } else {
445 inputReader ir = irNewDynstring(&ef2, 0);
446
447 envModifyOrAddBinding(globalEnvironment, &edef_evaldName,
448 valueNewLambda(edef_dynNr, 0, 0, edef_dynAr, '%',
449 parParseIntoBCUntil(&ir, 0, 1,
450 globalEnvironment, 0),
451 globalEnvironment, 1),
452 globalEnvironment);
453
454 }
455 }
456
457 void
cmd_end(const char * args)458 cmd_end( const char * args ) {
459 if( args ) issueWarning( WARNCMD_UNUSED_ARGS, "endd", 0, 0 );
460 switch( flowStack->openCmd ) {
461 case CMD_EDEF: return cmd_ende( 0 );
462 case CMD_IFDEF:
463 case CMD_IFDEF_ELSE:
464 case CMD_IFNDEF:
465 case CMD_IFNDEF_ELSE:
466 case CMD_IF:
467 case CMD_IF_ELSE: return cmd_endif( 0 );
468 case CMD_DISCARD: return cmd_endd( 0 );
469 default:
470 issueError(ERRCMD_UNMATCHED_COMMAND, "end", 0, 0);
471 }
472 }
473
474 void
cmd_define(const char * args)475 cmd_define( const char *args ) {
476 dynstring evaldName, name, body = dsNewFrom( args );
477 int pos = 0;
478
479 if( !flowStack->flowLevel ) return;
480
481 name = eatDSUntil( &body, &pos, " \t(" );
482 if( body.data[pos] == '(' ) { /* macro with arguments */
483 dynstring parms = eatDSUntil( &body, &pos, ")" );
484
485 if( pos == body.length )
486 issueError(ERRCMD_CLOSE_PAREN_EXPECTED, 0, 0, 0);
487 dsShrinkFront( &body, pos+1 );
488 dsRemoveOuterWS( &body );
489 if( parms.length ) { /* parse arguments outya ! */
490 dynstring first = dsNew();
491 dynstring second = dsNew();
492 int pos = 1;
493 dynstring *dynAr = (dynstring *)memXAlloc( sizeof( dynstring ) * 8 );
494 int dynNr = 0;
495 int dynSize = 8;
496
497 second = eatDSUntil( &parms, &pos, "," );
498 dsRemoveOuterWS( &second );
499 evalDS( &second );
500 dynAr[dynNr++] = dsCopy( &second );
501 pos++;
502 while( parms.length > pos ) {
503 first = eatDSUntil( &parms, &pos, "," );
504 dsRemoveOuterWS( &first );
505 evalDS( &first );
506 pos++;
507 if( dynNr == dynSize ) {
508 dynSize += 8;
509 dynAr = (dynstring *)memXRealloc( dynAr, sizeof( dynstring ) * dynSize );
510 }
511 dynAr[dynNr++] = dsCopy( &first );
512 }
513
514 evaldName = evalDS( &name );
515 {
516 inputReader ir = irNewDynstring(&evaldName, 0);
517
518 envModifyOrAddBinding(globalEnvironment, &evaldName,
519 valueNewLambda(dynNr, 0, 0, dynAr, '%',
520 parParseIntoBCUntil(&ir, 0, 1,
521 globalEnvironment, 0),
522 globalEnvironment, 1),
523 globalEnvironment);
524 }
525 return;
526 }
527 /* else no */
528 } /* macro with arguments */
529
530 evaldName = evalDS( &name );
531 dsShrinkFront( &body, pos+1 );
532 dsRemoveOuterWS( &body );
533 envModifyOrAddBinding(globalEnvironment, &evaldName,
534 valueNewScalar(&body), globalEnvironment);
535 }
536