Synopsis - Cross-Reference
File:
src/Synopsis/PTree/generation.cc 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#include <Synopsis/PTree.hh> // for MopWarningMessage only !
36#include <Synopsis/PTree/generation.hh>
37#include <cstdio>
38#include <cstring>
39#include <cstdarg>
40#include <stdexcept>
41#if !defined(_MSC_VER)
42#include <sys/time.h>
43#endif
44#include "Synopsis/Lexer.hh" // for is_xletter et al.
45// #include "Class.hh"
46
47#if (defined(sun) && defined(SUNOS4)) || defined(SUNOS5)
48extern "C"
49{
50 int gettimeofday(struct timeval*, void*);
51};
52#endif
53
54using namespace Synopsis;
55
56namespace
57{
58const int MAX = 32;
59PTree::Node **resultsArgs[MAX];
60int resultsIndex;
61
62const char *skip_spaces(const char *pat)
63{
64 while(*pat == ' ' || *pat == '\t') ++pat;
65 return pat;
66}
67
68const char *integer_to_string(int num, int& length)
69{
70 const int N = 16;
71 static char buf[N];
72 bool minus;
73
74 int i = N - 1;
75 if(num >= 0) minus = false;
76 else
77 {
78 minus = true;
79 num = -num;
80 }
81
82 buf[i--] = '\0';
83 if(num == 0)
84 {
85 buf[i] = '0';
86 length = 1;
87 return &buf[i];
88 }
89 else
90 {
91 while(num > 0)
92 {
93 buf[i--] = '0' + char(num % 10);
94 num /= 10;
95 }
96
97 if(minus) buf[i--] = '-';
98 length = N - 2 - i;
99 return &buf[i + 1];
100 }
101}
102
103const char *match_word(PTree::Node *list, const char *pat)
104{
105 const char* str = list->position();
106 size_t str_len = list->length();
107
108 for(int j = 0; ; ++pat)
109 {
110 char c = *pat;
111 switch(c)
112 {
113 case '\0' :
114 case ' ' :
115 case '\t' :
116 case '[' :
117 case ']' :
118 if(j == str_len) return pat;
119 else return 0;
120 case '%' :
121 c = *++pat;
122 switch(c)
123 {
124 case '[' :
125 case ']' :
126 case '%' :
127 if(j >= str_len || c != str[j++]) return 0;
128 break;
129 default :
130 if(j == str_len) return pat;
131 else return 0;
132 }
133 break;
134 default :
135 if(j >= str_len || c != str[j++]) return 0;
136 }
137 }
138}
139
140const char *match_pat(PTree::Node *list, const char *pat);
141
142const char *match_list(PTree::Node *list, const char *pat)
143{
144 char c, d;
145 pat = skip_spaces(pat);
146 while((c = *pat) != '\0')
147 {
148 if(c == ']')
149 if(list == 0)
150 return(pat + 1);
151 else
152 return 0;
153 else if(c == '%' && (d = pat[1], (d == 'r' || d == '_'))){
154 /* %r or %_ */
155 if(d == 'r')
156 *resultsArgs[resultsIndex++] = list;
157 list = 0;
158 pat = pat + 2;
159 }
160 else if(list == 0) return 0;
161 else
162 {
163 pat = match_pat(list->car(), pat);
164 if(pat == 0) return 0;
165 list = list->cdr();
166 }
167 pat = skip_spaces(pat);
168 }
169 throw std::runtime_error("PTree::match(): unmatched bracket");
170}
171
172const char *match_pat(PTree::Node *list, const char *pat)
173{
174 switch(*pat)
175 {
176 case '[' : /* [] means 0 */
177 if(list != 0 && list->is_atom())
178 return 0;
179 else
180 return match_list(list, pat + 1);
181 case '%' :
182 switch(pat[1])
183 {
184 case '?' :
185 *resultsArgs[resultsIndex++] = list;
186 return(pat + 2);
187 case '*' :
188 return(pat + 2);
189 case '_' :
190 case 'r' : /* %_ and %r must be appear in a list */
191 return 0;
192 default :
193 break;
194 }
195 }
196 if(list != 0 && list->is_atom())
197 return match_word(list, pat);
198 else return 0;
199}
200
201size_t count_args(const char *pat)
202{
203 size_t n = 0;
204 for(char c = *pat; c != '\0'; c = *++pat)
205 if(c == '%')
206 {
207 c = *++pat;
208 if(c == '?' || c == 'r') ++n;
209 }
210 return n;
211}
212}
213
214namespace Synopsis
215{
216namespace PTree
217{
218
219bool match(PTree::Node *list, char *pattern, ...)
220{
221 va_list args;
222 size_t n = count_args(pattern);
223 if(n >= MAX)
224 throw std::runtime_error("PTree::match(): too many arguments");
225
226 va_start(args, pattern);
227 for(size_t i = 0; i < n; ++i)
228 resultsArgs[i] = va_arg(args, PTree::Node **);
229
230 va_end(args);
231
232 resultsIndex = 0;
233 const char *pat = skip_spaces(pattern);
234 pat = match_pat(list, pat);
235 if(pat == 0) return false;
236 else
237 {
238 pat = skip_spaces(pat);
239 if(*pat == '\0') return true;
240 else
241 {
242 MopWarningMessage("PTree::Node::Match()", "[ ] are forgot?");
243 MopMoreWarningMessage(pattern);
244 return false;
245 }
246 }
247}
248
249Node *gen_sym()
250{
251 static char head[] = "_sym";
252 static int seed = 1;
253 int len1, len2;
254
255 integer_to_string(seed, len1);
256
257#if !defined(_MSC_VER) && !defined(__WIN32__)
258 struct timeval time;
259 gettimeofday(&time, 0);
260 size_t rnum = (time.tv_sec * 10 + time.tv_usec / 100) & 0xffff;
261#else
262 static size_t time = 0;
263 time++;
264 size_t rnum = time & 0xffff;
265#endif
266 const char *num = integer_to_string(rnum, len2);
267
268 int size = len1 + len2 + sizeof(head) - 1 + 1;
269 char *name = new (GC) char[size];
270 memmove(name, head, sizeof(head) - 1);
271 memmove(&name[sizeof(head) - 1], num, len2);
272 name[sizeof(head) - 1 + len2] = '_';
273 num = integer_to_string(seed++, len1);
274 memmove(&name[sizeof(head) - 1 + len2 + 1], num, len1);
275 return new PTree::Atom(name, size);
276}
277
278Node *make(const char *pat, ...)
279{
280 va_list args;
281 const int N = 4096;
282 static char buf[N];
283 char c;
284 int len;
285 const char* ptr;
286 PTree::Node *p;
287 PTree::Node *q;
288 int i = 0, j = 0;
289 PTree::Node *result = 0;
290
291 va_start(args, pat);
292 while((c = pat[i++]) != '\0')
293 if(c == '%')
294 {
295 c = pat[i++];
296 if(c == '%') buf[j++] = c;
297 else if(c == 'd')
298 {
299 ptr = integer_to_string(va_arg(args, int), len);
300 memmove(&buf[j], ptr, len);
301 j += len;
302 }
303 else if(c == 's')
304 {
305 ptr = va_arg(args, char*);
306 len = strlen(ptr);
307 memmove(&buf[j], ptr, len);
308 j += len;
309 }
310 else if(c == 'c')
311 buf[j++] = va_arg(args, int);
312 else if(c == 'p')
313 {
314 p = va_arg(args, PTree::Node *);
315 if(p == 0)
316 /* ignore */;
317 else if(p->is_atom())
318 {
319 memmove(&buf[j], p->position(), p->length());
320 j += p->length();
321 }
322 else
323 {
324 if(j > 0)
325 q = list(new PTree::DupAtom(buf, j), p);
326 else q = list(p);
327 j = 0;
328 result = nconc(result, q);
329 }
330 }
331 else throw std::runtime_error("PTree::make(): invalid format");
332 }
333 else buf[j++] = c;
334 va_end(args);
335
336 if(j > 0)
337 if(result == 0)
338 result = new PTree::DupAtom(buf, j);
339 else
340 result = snoc(result, new PTree::DupAtom(buf, j));
341
342 return result;
343}
344
345bool reify(Node *n, unsigned int& value)
346{
347 if(!n->is_atom()) return false;
348
349 const char *p = n->position();
350 int len = n->length();
351 value = 0;
352 if(len > 2 && *p == '0' && is_xletter(p[1]))
353 {
354 for(int i = 2; i < len; ++i)
355 {
356 char c = p[i];
357 if(is_digit(c)) value = value * 0x10 + (c - '0');
358 else if('A' <= c && c <= 'F') value = value * 0x10 + (c - 'A' + 10);
359 else if('a' <= c && c <= 'f') value = value * 0x10 + (c - 'a' + 10);
360 else if(is_int_suffix(c)) break;
361 else return false;
362 }
363 return true;
364 }
365 else if(len > 0 && is_digit(*p))
366 {
367 for(int i = 0; i < len; ++i)
368 {
369 char c = p[i];
370 if(is_digit(c)) value = value * 10 + c - '0';
371 else if(is_int_suffix(c)) break;
372 else return false;
373 }
374 return true;
375 }
376 else return false;
377}
378
379bool reify(Node *n, const char*& str)
380{
381 if(!n->is_atom()) return false;
382 const char *p = n->position();
383 size_t l = n->length();
384 if(*p != '"') return false;
385 else
386 {
387 char *tmp = new(GC) char[l];
388 char *sp = tmp;
389 for(size_t i = 1; i < l; ++i)
390 if(p[i] != '"')
391 {
392 *sp++ = p[i];
393 if(p[i] == '\\' && i + 1 < l) *sp++ = p[++i];
394 }
395 else while(++i < l && p[i] != '"');
396 *sp = '\0';
397 str = tmp;
398 return true;
399 }
400}
401
402Node *qmake(const char*)
403{
404 throw std::runtime_error("PTree::qmake(): the metaclass must be compiled by OpenC++.");
405}
406
407// class PtreeHead --- this is used to implement PTree::Node::qMake().
408
409PTree::Head &PTree::Head::operator + (PTree::Node *p)
410{
411 ptree = append(ptree, p);
412 return *this;
413}
414
415PTree::Head &PTree::Head::operator + (const char* str)
416{
417 if(*str != '\0') ptree = append(ptree, str, strlen(str));
418 return *this;
419}
420
421PTree::Head &PTree::Head::operator + (char c)
422{
423 ptree = append(ptree, &c, 1);
424 return *this;
425}
426
427PTree::Head &PTree::Head::operator + (int n)
428{
429 int len;
430 const char *str = integer_to_string(n, len);
431 ptree = append(ptree, str, len);
432 return *this;
433}
434
435PTree::Node *PTree::Head::append(PTree::Node *lst, PTree::Node *tail)
436{
437 PTree::Node *last;
438 PTree::Node *p;
439 PTree::Node *q;
440
441 if(tail == 0)
442 return lst;
443
444 if(!tail->is_atom() && PTree::length(tail) == 1){
445 tail = tail->car();
446 if(tail == 0)
447 return lst;
448 }
449
450 if(tail->is_atom() && lst != 0){
451 last = PTree::last(lst);
452 if(last != 0){
453 p = last->car();
454 if(p != 0 && p->is_atom()){
455 q = new PTree::DupAtom(p->position(), p->length(),
456 tail->position(), tail->length());
457 last->set_car(q);
458 return lst;
459 }
460 }
461 }
462
463 return PTree::snoc(lst, tail);
464}
465
466PTree::Node *PTree::Head::append(PTree::Node *lst, const char *str, size_t len)
467{
468 if(lst)
469 {
470 PTree::Node *last = PTree::last(lst);
471 if(last)
472 {
473 PTree::Node *p = last->car();
474 if(p && p->is_atom())
475 {
476 PTree::Node *q = new PTree::DupAtom(p->position(), p->length(), str, len);
477 last->