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