Subversion Repositories tendra.SVN

Rev

Rev 2 | Go to most recent revision | Details | Compare with Previous | Last modification | View Log | RSS feed

Rev Author Line No. Line
2 7u83 1
/*
2
    		 Crown Copyright (c) 1997
3
 
4
    This TenDRA(r) Computer Program is subject to Copyright
5
    owned by the United Kingdom Secretary of State for Defence
6
    acting through the Defence Evaluation and Research Agency
7
    (DERA).  It is made available to Recipients with a
8
    royalty-free licence for its use, reproduction, transfer
9
    to other parties and amendment for any purpose not excluding
10
    product development provided that any such use et cetera
11
    shall be deemed to be acceptance of the following conditions:-
12
 
13
        (1) Its Recipients shall ensure that this Notice is
14
        reproduced upon any copies or amended versions of it;
15
 
16
        (2) Any amended version of it shall be clearly marked to
17
        show both the nature of and the organisation responsible
18
        for the relevant amendment or amendments;
19
 
20
        (3) Its onward transfer from a recipient to another
21
        party shall be deemed to be that party's acceptance of
22
        these conditions;
23
 
24
        (4) DERA gives no warranty or assurance as to its
25
        quality or suitability for any purpose and DERA accepts
26
        no liability whatsoever in relation to any use to which
27
        it may be put.
28
*/
29
 
30
 
31
#include "config.h"
32
#include "char.h"
33
#include "error.h"
34
#include "xalloc.h"
35
 
36
 
37
/*
38
    WHITE SPACE CHARACTERS
39
 
40
    This variable holds all the white space characters.
41
*/
42
 
43
letter *white_space = NULL ;
44
 
45
 
46
/*
47
    LEXICAL PASS REPRESENTATIONS
48
 
49
    These variables describe the various lexical passes.
50
*/
51
 
52
static character passes [2] = {
53
    { LAST_LETTER, NULL, NULL, NULL },
54
    { LAST_LETTER, NULL, NULL, NULL }
55
} ;
56
 
57
character *pre_pass = passes ;
58
character *main_pass = passes + 1 ;
59
 
60
 
61
/*
62
    ALLOCATE A NEW CHARACTER
63
 
64
    This routine allocates a new character with value c.
65
*/
66
 
67
static character *new_char
68
    PROTO_N ( ( c ) )
69
    PROTO_T ( letter c )
70
{
71
    character *p ;
72
    static int chars_left = 0 ;
73
    static character *chars_free = NULL ;
74
    if ( chars_left == 0 ) {
75
	chars_left = 100 ;
76
	chars_free = xmalloc_nof ( character, chars_left ) ;
77
    }
78
    p = chars_free + ( --chars_left ) ;
79
    p->ch = c ;
80
    p->defn = NULL ;
81
    p->cond = NULL ;
82
    p->opt = NULL ;
83
    p->next = NULL ;
84
    return ( p ) ;
85
}
86
 
87
 
88
/*
89
    ADD A CHARACTER
90
 
91
    This routine adds the string s (defined using data) to the lexical
92
    pass p.
93
*/
94
 
95
void add_char
96
    PROTO_N ( ( p, s, data ) )
97
    PROTO_T ( character *p X letter *s X char **data )
98
{
99
    character *q ;
100
    letter c = *s ;
101
    if ( p->next == NULL ) {
102
	q = new_char ( c ) ;
103
	p->next = q ;
104
    } else {
105
	character *r = NULL ;
106
	for ( q = p->next ; q && ( q->ch < c ) ; q = q->opt ) r = q ;
107
	if ( q && q->ch == c ) {
108
	    /* already exists */
109
	} else {
110
	    q = new_char ( c ) ;
111
	    if ( r == NULL ) {
112
		q->opt = p->next ;
113
		p->next = q ;
114
	    } else {
115
		q->opt = r->opt ;
116
		r->opt = q ;
117
	    }
118
	}
119
    }
120
    if ( c == LAST_LETTER ) {
121
	if ( q->defn ) {
122
	    error ( ERROR_SERIOUS,
123
		    "String for '%s' has already been defined to give '%s'",
124
		    data [0], q->defn ) ;
125
	}
126
	q->defn = data [0] ;
127
	q->args = data [1] ;
128
	q->cond = data [2] ;
129
    } else {
130
	add_char ( q, s + 1, data ) ;
131
    }
132
    return ;
133
}
134
 
135
 
136
/*
137
    ARRAY OF ALL GROUPS
138
 
139
    This array gives all the character groups.
140
*/
141
 
142
char_group groups [ MAX_GROUPS ] ;
143
int no_groups = 0 ;
144
 
145
 
146
/*
147
    CREATE A NEW GROUP
148
 
149
    This routine creates a new character group with name nm and
150
    definition s.
151
*/
152
 
153
void make_group
154
    PROTO_N ( ( nm, s ) )
155
    PROTO_T ( char *nm X letter *s )
156
{
157
    int i, n = no_groups ;
158
    for ( i = 0 ; i < n ; i++ ) {
159
	if ( streq ( nm, groups [i].name ) ) {
160
	    error ( ERROR_SERIOUS, "Group '%s' already defined", nm ) ;
161
	    return ;
162
	}
163
    }
164
    if ( n >= MAX_GROUPS ) {
165
	error ( ERROR_SERIOUS, "Too many groups defined (%d)", n ) ;
166
	return ;
167
    }
168
    groups [n].name = nm ;
169
    groups [n].defn = s ;
170
    no_groups = n + 1 ;
171
    return ;
172
}
173
 
174
 
175
/*
176
    IS A LETTER IN A GROUP?
177
 
178
    This routine checks whether the letter c is in the list p.
179
*/
180
 
181
int in_group
182
    PROTO_N ( ( p, c ) )
183
    PROTO_T ( letter *p X letter c )
184
{
185
    letter a ;
186
    if ( p == NULL ) return ( 0 ) ;
187
    while ( a = *( p++ ), a != LAST_LETTER ) {
188
	if ( a == c ) {
189
	    return ( 1 ) ;
190
	} else if ( a == WHITE_LETTER ) {
191
	    if ( in_group ( white_space, c ) ) return ( 1 ) ;
192
	} else if ( a >= GROUP_LETTER ) {
193
	    int n = ( int ) ( a - GROUP_LETTER ) ;
194
	    if ( in_group ( groups [n].defn, c ) ) return ( 1 ) ;
195
	}
196
    }
197
    return ( 0 ) ;
198
}
199
 
200
 
201
/*
202
    FIND AN ESCAPE SEQUENCE
203
 
204
    This routine finds the character corresponding to the escape sequence c.
205
*/
206
 
207
letter find_escape
208
    PROTO_N ( ( c ) )
209
    PROTO_T ( int c )
210
{
211
    letter a ;
212
    switch ( c ) {
213
	case 'n' : a = '\n' ; break ;
214
	case 't' : a = '\t' ; break ;
215
	case 'v' : a = '\v' ; break ;
216
	case 'f' : a = '\f' ; break ;
217
	case 'r' : a = '\r' ; break ;
218
	case '?' : a = '?' ; break ;
219
	case '"' : a = '"' ; break ;
220
	case '[' : a = '[' ; break ;
221
	case '\\' : a = '\\' ; break ;
222
	case '\'' : a = '\'' ; break ;
223
	case 'e' : a = EOF_LETTER ; break ;
224
	default : {
225
	    error ( ERROR_SERIOUS, "Unknown escape sequence, '\\%c'",
226
		    ( unsigned char ) c ) ;
227
	    a = ( letter ) ( c & 0xff ) ;
228
	    break ;
229
	}
230
    }
231
    return ( a ) ;
232
}
233
 
234
 
235
/*
236
    TRANSLATE A STRING INTO A CHARACTER STRING
237
 
238
    This routine translates the string s into an array of letters.
239
*/
240
 
241
letter *make_string
242
    PROTO_N ( ( s ) )
243
    PROTO_T ( char *s )
244
{
245
    int i = 0, n = ( int ) strlen ( s )  ;
246
    letter *p = xmalloc_nof ( letter, n + 1 ) ;
247
    while ( *s ) {
248
	letter a ;
249
	char c = *( s++ ) ;
250
	if ( c == '\\' ) {
251
	    c = *( s++ ) ;
252
	    a = find_escape ( c ) ;
253
	} else if ( c == '[' ) {
254
	    int j ;
255
	    size_t glen ;
256
	    char *gnm = s ;
257
	    while ( *s && *s != ']' ) s++ ;
258
	    glen = ( size_t ) ( s - gnm ) ;
259
	    if ( *s ) {
260
		s++ ;
261
	    } else {
262
		error ( ERROR_SERIOUS,
263
			"Unterminated character group name, '%s'", gnm ) ;
264
	    }
265
	    for ( j = 0 ; j < no_groups ; j++ ) {
266
		if ( strncmp ( gnm, groups [j].name, glen ) == 0 ) {
267
		    a = GROUP_LETTER + j ;
268
		    break ;
269
		}
270
	    }
271
	    if ( j == no_groups ) {
272
		if ( strncmp ( gnm, "white", glen ) == 0 ) {
273
		    a = WHITE_LETTER ;
274
		} else {
275
		    error ( ERROR_SERIOUS, "Unknown character group, '%.*s'",
276
			    ( int ) glen, gnm ) ;
277
		    a = '?' ;
278
		}
279
	    }
280
	    SET ( a ) ;
281
	} else {
282
	    a = ( letter ) ( c & 0xff ) ;
283
	}
284
	p [i] = a ;
285
	i++ ;
286
    }
287
    p [i] = LAST_LETTER ;
288
    return ( p ) ;
289
}
290
 
291
 
292
/*
293
    LIST OF ALL KEYWORDS
294
 
295
    This variable gives a list of all the keywords.
296
*/
297
 
298
keyword *keywords = NULL ;
299
 
300
 
301
/*
302
    ADD A KEYWORD
303
 
304
    This routine adds the keyword nm with its associated data to the list
305
    of all keywords.
306
*/
307
 
308
void add_keyword
309
    PROTO_N ( ( nm, data ) )
310
    PROTO_T ( char *nm X char **data )
311
{
312
    static int keywords_left = 0 ;
313
    static keyword *keywords_free = NULL ;
314
    keyword *p = keywords, *q = NULL ;
315
    while ( p ) {
316
	int c = strcmp ( nm, p->name ) ;
317
	if ( c == 0 ) {
318
	    error ( ERROR_SERIOUS, "Keyword '%s' already defined", nm ) ;
319
	    return ;
320
	}
321
	if ( c < 0 ) break ;
322
	q = p ;
323
	p = p->next ;
324
    }
325
    if ( keywords_left == 0 ) {
326
	keywords_left = 100 ;
327
	keywords_free = xmalloc_nof ( keyword, keywords_left ) ;
328
    }
329
    p = keywords_free + ( --keywords_left ) ;
330
    p->name = nm ;
331
    p->defn = data [0] ;
332
    p->args = data [1] ;
333
    p->cond = data [2] ;
334
    p->done = 0 ;
335
    if ( q == NULL ) {
336
	p->next = keywords ;
337
	keywords = p ;
338
    } else {
339
	p->next = q->next ;
340
	q->next = p ;
341
    }
342
    return ;
343
}