File: simple-parser.c

package info (click to toggle)
saml 970418-9
  • links: PTS
  • area: main
  • in suites: woody
  • size: 1,188 kB
  • ctags: 1,703
  • sloc: ansic: 17,186; sh: 2,573; yacc: 497; perl: 264; makefile: 242; python: 242
file content (235 lines) | stat: -rw-r--r-- 5,164 bytes parent folder | download | duplicates (3)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
/*
 * Copyright 1996 Thierry Bousch
 * Licensed under the Gnu Public License, Version 2
 *
 * $Id: simple-parser.c,v 1.6 1996/12/28 16:27:53 bousch Exp $
 *
 * A simple recursive descent parser for algebraic expressions
 */

#include <ctype.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "saml.h"
#include "saml-errno.h"
#include "saml-parse.h"

/*
 * Here is the grammar:
 *
 * expr -> term
 *       | `+' term
 *       | `-' term
 *       | expr `+' term
 *       | expr `-' term
 *
 * term -> factor
 *       | term `*' factor
 *       | term `/' factor
 *
 * factor -> atom
 *         | atom `^' signed_int
 *
 * atom -> `(' expr `)'
 *       | INTEGER
 *       | IDENTIFIER
 *       | IDENTIFIER `!' signed_int
 *
 * signed_int -> INTEGER
 *             | `+' INTEGER
 *             | `-' INTEGER
 */

static mref_t model;
static int last_token;

static int parse_expr (mref_t result);
static int parse_factor (mref_t result);
static int parse_term (mref_t result);
static int parse_atom (mref_t result);

int saml_parse (mref_t result, mref_t _model)
{
	int ret;

	/* Beware of aliasing, result and _model might be the same mref */
	model = mref_new();
	mref_copy(model, _model);
	last_token = (*saml_lexer)();
	ret = parse_expr(result);
	mref_free(model);

	/* Have we reached the end of the input? */
	if (last_token != STOK_EOF)
		ret = -1;
	if (ret < 0)
		mref_error(result, SE_STRING, "saml_parse");
	return ret;
}

static int parse_expr (mref_t result)
{
	mref_t tmp0 = mref_new(), tmp1 = mref_new(), tmp2 = mref_new();
	int ret, op;
	unsigned int terms = 0;

	while(1) {
		if (last_token == '+' || last_token == '-') {
			op = last_token;
			last_token = (*saml_lexer)();
		}
		else if (terms == 0) {
			/* The first term doesn't need a sign */
			op = '+';
		}
		else break;

		ret = parse_term(tmp0);
		if (ret < 0) goto end_parse;

		if (terms == 0) {
			/*
			 * In the case of tensors, there are different kinds
			 * of zeros, so we must initialize tmp1,tmp2,result
			 * from the first term, not from the model.
			 */
			mref_zero(tmp1,   tmp0);
			mref_zero(tmp2,   tmp0);
			mref_zero(result, tmp0);
		}

		if (op == '+')
		  mref_add(tmp1, tmp1, tmp0);
		else
		  mref_sub(tmp1, tmp1, tmp0);

		/* After having read 32 terms, move them to tmp2 */
		terms++;
		if (terms % 32 == 0) {
			mref_add(tmp2, tmp2, tmp1);
			mref_zero(tmp1, tmp1);
			/* After 1024 terms, move them to result */
			if (terms % 1024 == 0) {
				mref_add(result, result, tmp2);
				mref_zero(tmp2, tmp2);
			}
		}
	}
	mref_add(tmp2, tmp2, tmp1);
	mref_add(result, result, tmp2);
	ret = 0;  /* to make GCC happy */
end_parse:
	mref_free(tmp0); mref_free(tmp1); mref_free(tmp2);
	return ret;
}

static int parse_term (mref_t result)
{
	mref_t tmp = mref_new();
	int ret, op;

	ret = parse_factor(result);
	if (ret < 0) goto end_parse;

	while (last_token == '*' || last_token == '/') {
		op = last_token;
		last_token = (*saml_lexer)();

		ret = parse_factor(tmp);
		if (ret < 0) goto end_parse;

		if (op == '*')	mref_mul(result, result, tmp);
		else		mref_div(result, result, tmp);
	}
end_parse:
	mref_free(tmp);
	return ret;
}

int parse_factor (mref_t result)
{
	int ret, sign, expo;

	ret = parse_atom(result);
	if (ret < 0)
		return ret;

	/* If there isn't a caret after the atom, exit now */
	if (last_token != '^')
		return ret;
		
	last_token = (*saml_lexer)();
	sign = '+';
	if (last_token == '+' || last_token == '-') {
		sign = last_token;
		last_token = (*saml_lexer)();
	}
	if (last_token != STOK_INTEGER) {
		/* Syntax error, no exponent found */
		return -1;
	}
	expo = atoi(saml_token); /* FIXME */
	last_token = (*saml_lexer)();
	if (sign == '-')
		expo = -expo;
	mref_power(result, result, expo);
	return 0;
}
	
int parse_atom (mref_t result)
{
	int ret, sign;
	char *litname;

	switch (last_token) {
	    case '(':
		last_token = (*saml_lexer)();
		ret = parse_expr(result);
		if (last_token != ')')
			ret = -1;  /* no matching parenthesis */
		last_token = (*saml_lexer)();
		return ret;

	    case STOK_INTEGER:
		mref_build(result, ST_INTEGER, saml_token);
		mref_promote(result, model);
		last_token = (*saml_lexer)();
		return 0;

	    case STOK_LITERAL:
	    	litname = alloca(strlen(saml_token) + 32);
	    	strcpy(litname, saml_token);
	    	last_token = (*saml_lexer)();
	    	if (last_token != '!') {
	    		/* Simply a literal */
	    		mref_build(result, ST_LITERAL, litname);
	    		mref_promote(result, model);
	    		return 0;
	    	}
	    	/* This is tensorid!number */
	    	last_token = (*saml_lexer)();
	    	sign = '+';
	    	if (last_token == '+' || last_token == '-') {
	    		sign = last_token;
	    		last_token = (*saml_lexer)();
	    	}
	    	if (last_token != STOK_INTEGER)
	    		return -1;	/* missing vector number */

	    	strcat(litname, "!");
	    	if (sign == '-')
	    		strcat(litname, "-");
	    	/* FIXME -- possible stack overflow */
	    	strcat(litname, saml_token);
	    	last_token = (*saml_lexer)();
	    	
	    	mref_build(result, ST_TENSOR, litname);
	    	mref_promote(result, model);
	    	return 0;

	    default:
	    	/* Syntax error, not an atom */
	    	return -1;
	}
}