parser.c 6.25 KB
Newer Older
dcw's avatar
dcw committed
1 2 3 4 5 6 7 8 9 10 11 12
/*
 *                           PARSER FOR THE
 *                           ====== === ===
 *
 *                      DATA DECLARATION BUILDER
 *                      ==== =========== =======
 *
 *      This module is the parser used to interprete the high
 *      level data declarations.
 *
 ******* Grammar for Declarations
 *
dcw's avatar
dcw committed
13 14
 *	data   = [ tEXPORT chunk ]
 *		 [ tGLOBAL chunk ]
dcw's avatar
dcw committed
15
 *		 [ tBEGIN chunk ]
dcw's avatar
dcw committed
16 17 18
 *		 tTYPE tOPENCURLY declns tCLOSECURLY
 *	chunk  = tOPENCURLY list_of_lines tCLOSECURLY
 *	declns = list*( decln ) tEOF
dcw's avatar
dcw committed
19 20
 *	decln  = tID tEQ shapes tSEMI
 *	shapes = sep-list+( shape, tOR )
dcw's avatar
dcw committed
21
 *	shape  = tID [ tOPENBR params tCLOSEBR ] printlist
dcw's avatar
dcw committed
22
 *	params = sep-list+( param, tCOMMA )
23
 *	param  = [tMINUS] tID tID
dcw's avatar
dcw committed
24
 *	printlist = list( tSTR | tNUM )
dcw's avatar
dcw committed
25 26 27
 */


28 29
#include <stdio.h>
#include <string.h>
30
#include <stdlib.h>
31
#include <stdbool.h>
dcw's avatar
dcw committed
32 33 34 35 36
#include "struct.h"
#include "lexer.h"
#include "parser.h"


37 38 39
#define COPYOF(new,old) {new=malloc(1+strlen(old));if(new)strcpy(new,old);}


40 41
static bool parse_chunk( char * s );
static bool parse_declns( declnlist * dp );
Duncan White's avatar
Duncan White committed
42
static void error( char * s );
43 44 45 46 47 48 49 50
static bool parse_decln( char ** name, shapelist * shapes );
static bool parse_shapes( shapelist * sp );
static bool parse_shape( char ** tagname, paramlist * pl, printlist * print );
static bool parse_params( paramlist * pp );
static bool parse_printlist( printlist * pp );
static bool parse_printitem( printitem * item );
static bool neverfreetype( char * typename );
static bool parse_param( bool * dontfree, char ** type, char ** name );
dcw's avatar
dcw committed
51 52


53
#define MUSTBE(t,mesg)	if( nexttok() != (t) ) {error(mesg); return false;}
dcw's avatar
dcw committed
54 55


dcw's avatar
dcw committed
56 57 58
/*
 *	data   = [ tEXPORT tOPENCURLY crap_to_} ]
 *		 [ tGLOBAL tOPENCURLY crap_to_} ]
dcw's avatar
dcw committed
59
 *		 [ tBEGIN tOPENCURLY crap_to_} ]
dcw's avatar
dcw committed
60 61 62
 *		 tTYPE tOPENCURLY declns tCLOSECURLY
 */

63
bool parse_data( char *exports, char *globals, char *begin, declnlist *dp )
dcw's avatar
dcw committed
64 65 66
{
	if( nexttok() == tEXPORT )
	{
67
		if( ! parse_chunk( exports ) ) return false;
dcw's avatar
dcw committed
68 69 70 71 72 73 74 75
	} else
	{
		*exports = '\0';
		ungettok();
	}

	if( nexttok() == tGLOBAL )
	{
76
		if( ! parse_chunk( globals ) ) return false;
dcw's avatar
dcw committed
77 78 79 80 81
	} else
	{
		*globals = '\0';
		ungettok();
	}
dcw's avatar
dcw committed
82 83 84

	if( nexttok() == tBEGIN )
	{
85
		if( ! parse_chunk( begin ) ) return false;
dcw's avatar
dcw committed
86 87 88 89 90 91 92
	} else
	{
		*begin = '\0';
		ungettok();
	}

	MUSTBE( tTYPE, "TYPE/EXPORT/GLOBAL/BEGIN expected" );
dcw's avatar
dcw committed
93
	MUSTBE( tOPENCURLY, "{ expected" );
94
	if( ! parse_declns( dp ) ) return false;
95
	MUSTBE( tCLOSECURLY, "} expected" );
dcw's avatar
dcw committed
96 97
	MUSTBE( tEOF, "Spurious characters found beyond EOF" );

98
	return true;
dcw's avatar
dcw committed
99 100 101 102 103
}


/* chunk  = tOPENCURLY list_of_lines tCLOSECURLY */

104
static bool parse_chunk( char *s )
dcw's avatar
dcw committed
105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120
{
	char line[256];
	int  startlineno;

	*s = '\0';

	MUSTBE( tOPENCURLY, "'{' expected" );

	startlineno = lineno;
	for(;;)
	{
		if( ! readnextline( line ) )
		{
			fprintf( stderr,
				 "Premature EOF after { - started at line %d\n",
				 startlineno );
121
			return false;
dcw's avatar
dcw committed
122 123 124 125 126
		}
	if( streq( line, "}" ) ) break;
		strcat( s, line );
		strcat( s, "\n" );
	}
127
	return true;
dcw's avatar
dcw committed
128 129
}

dcw's avatar
dcw committed
130

dcw's avatar
dcw committed
131 132 133
/* declns = list*( decln )       */
/* NB: a decln starts with a tID */

134
static bool parse_declns( declnlist *dp )
dcw's avatar
dcw committed
135 136 137 138
{
	char		*name;
	shapelist	shapes;

dcw's avatar
dcw committed
139 140 141
	while( nexttok() == tID )
	{
		ungettok();
142
		if( ! parse_decln( &name, &shapes ) ) return false;
dcw's avatar
dcw committed
143
		*dp = build_declnlist( name, shapes, (declnlist) NULL );
dcw's avatar
dcw committed
144 145
		dp = &( (*dp)->next );
	}
dcw's avatar
dcw committed
146
	ungettok();
147
	return true;
dcw's avatar
dcw committed
148 149 150
}


Duncan White's avatar
Duncan White committed
151
static void error( char *s )
dcw's avatar
dcw committed
152
{
dcw's avatar
dcw committed
153
	fprintf( stderr, "%s at line %d\n", s, lineno );
dcw's avatar
dcw committed
154 155 156 157 158
}


/* decln  = tID tEQ shapes tSEMI */

159
static bool parse_decln( char **name, shapelist *shapes )
dcw's avatar
dcw committed
160
{
dcw's avatar
dcw committed
161 162
	MUSTBE( tID, "declaration expected" );
	COPYOF( *name, lexidval );
dcw's avatar
dcw committed
163

dcw's avatar
dcw committed
164
	MUSTBE( tEQ, "'=' expected" );
dcw's avatar
dcw committed
165

166
	if( ! parse_shapes( shapes ) ) return false;
dcw's avatar
dcw committed
167

dcw's avatar
dcw committed
168
	MUSTBE( tSEMI, "';' expected" );
dcw's avatar
dcw committed
169

170
	return true;
dcw's avatar
dcw committed
171 172 173
}


dcw's avatar
dcw committed
174
/* shapes = sep-list+( shape, tOR ) */
dcw's avatar
dcw committed
175

176
static bool parse_shapes( shapelist *sp )
dcw's avatar
dcw committed
177 178 179
{
	char		*tagname;
	paramlist	paras;
180
	printlist	print;
dcw's avatar
dcw committed
181

dcw's avatar
dcw committed
182
	for(;;) {
183
		if( ! parse_shape( &tagname, &paras, &print ) ) return false;
dcw's avatar
dcw committed
184 185
		*sp = build_shapelist( tagname, paras,
				       print, (shapelist) NULL );
dcw's avatar
dcw committed
186 187 188 189
	if( nexttok() != tOR ) break;
		sp = &( (*sp)->next );
	}
	ungettok();
190
	return true;
dcw's avatar
dcw committed
191 192 193
}


dcw's avatar
dcw committed
194
/* shape = tID [ tOPENBR params tCLOSEBR ] printlist */
dcw's avatar
dcw committed
195

196
static bool parse_shape( char **tagname, paramlist *pl, printlist *print )
dcw's avatar
dcw committed
197
{
dcw's avatar
dcw committed
198
	*pl    = (paramlist) NULL;
dcw's avatar
dcw committed
199
	*print = (printlist) NULL;
200

dcw's avatar
dcw committed
201 202
	MUSTBE( tID, "shape name expected" );
	COPYOF( *tagname, lexidval );
dcw's avatar
dcw committed
203

dcw's avatar
dcw committed
204
	if( nexttok() == tOPENBR )
dcw's avatar
dcw committed
205
	{
206
		if( ! parse_params( pl ) ) return false;
dcw's avatar
dcw committed
207

208
		MUSTBE( tCLOSEBR, "',' or ')' expected" );
dcw's avatar
dcw committed
209
	} else
dcw's avatar
dcw committed
210 211 212 213
	{
		ungettok();
	}

dcw's avatar
dcw committed
214
	return parse_printlist( print );
dcw's avatar
dcw committed
215 216 217
}


dcw's avatar
dcw committed
218
/* params = sep-list+( param, tCOMMA ) */
dcw's avatar
dcw committed
219

220
static bool parse_params( paramlist *pp )
dcw's avatar
dcw committed
221 222 223
{
	char *type;
	char *name;
224
	bool dontfree;
dcw's avatar
dcw committed
225

dcw's avatar
dcw committed
226
	for(;;) {
227
		if( !parse_param( &dontfree, &type, &name ) ) return false;
228
		*pp = build_paramlist( dontfree, type, name, (paramlist) NULL );
dcw's avatar
dcw committed
229
	if( nexttok() != tCOMMA ) break;
dcw's avatar
dcw committed
230 231 232
		pp = &( (*pp)->next );
	}
	ungettok();
233
	return true;
dcw's avatar
dcw committed
234 235 236
}


237 238 239
/* printlist = list( printitem ) */
/* NB: Never fails, cos items are one token long */

240
static bool parse_printlist( printlist *pp )
241 242 243
{
	printitem item;

dcw's avatar
dcw committed
244
	*pp = (printlist) NULL;
245 246 247

	while( parse_printitem( &item ) )
	{
dcw's avatar
dcw committed
248 249
		*pp = build_printlist( item, (printlist) NULL );
		pp = &( (*pp)->next );
250
	}
251
	return true;
252 253 254 255
}


/* printitem = tSTR | tNUM */
dcw's avatar
dcw committed
256

257
static bool parse_printitem( printitem *item )
258
{
dcw's avatar
dcw committed
259 260
	char *temp;

261 262
	switch( nexttok() ) {
	case tSTR:
dcw's avatar
dcw committed
263 264
		COPYOF( temp, lexidval );
		*item = build_printitem_str( temp );
265
		return true;
266 267
	case tNUM:
		*item = build_printitem_num( lexintval );
268
		return true;
269 270
	default:
		ungettok();
271
		return false;
272 273 274 275
	}
}


276 277 278
/* never free the following types - sorted list */
static char *neverfree[] = {
	"BOOL",
279
	"bool",
280 281 282
	"char",
	"int",
};
283

284 285 286
#define NEVERFREE_NEL (sizeof(neverfree)/sizeof(char *))


287
static bool neverfreetype( char *typename )
dcw's avatar
dcw committed
288
{
289 290 291 292 293
	int i;
	for( i=0; i<NEVERFREE_NEL; i++ )
	{
		if( strcmp( neverfree[i], typename ) == 0 )
		{
294
			return true;
295 296
		}
	}
297
	return false;
298 299 300 301 302
}


/* param     = [tMINUS] tID tID */

303
static bool parse_param( bool *dontfree, char **type, char **name )
304 305 306 307 308 309
{
	*dontfree = nexttok() == tMINUS;
	if( ! *dontfree )
	{
		ungettok();
	}
dcw's avatar
dcw committed
310
	MUSTBE( tID, "Field type expected" );
dcw's avatar
dcw committed
311 312
	COPYOF( *type, lexidval );

313 314 315 316 317 318
	/* apply standard "never free rules" */
	if( ! *dontfree )
	{
		*dontfree = neverfreetype( *type );
	}

dcw's avatar
dcw committed
319
	MUSTBE( tID, "Field name expected" );
dcw's avatar
dcw committed
320
	COPYOF( *name, lexidval );
321
	//printf( "debug: param(%s, %s): dontfree %d\n", *type, *name, *dontfree );
dcw's avatar
dcw committed
322

323
	return true;
dcw's avatar
dcw committed
324
}