Synopsis - Cross-Reference

File: src/Synopsis/PTree/generation.cc
  1/*
  2  Copyright (C) 1997-2000 Shigeru Chiba, University of Tsukuba.
  3
  4  Permission to use, copy, distribute and modify this software and   
  5  its documentation for any purpose is hereby granted without fee,        
  6  provided that the above copyright notice appear in all copies and that 
  7  both that copyright notice and this permission notice appear in 
  8  supporting documentation.
  9
 10  Shigeru Chiba makes no representations about the suitability of this 
 11  software for any purpose.  It is provided "as is" without express or
 12  implied warranty.
 13*/
 14/*
 15  Copyright (c) 1995, 1996 Xerox Corporation.
 16  All Rights Reserved.
 17
 18  Use and copying of this software and preparation of derivative works
 19  based upon this software are permitted. Any copy of this software or
 20  of any derivative work must include the above copyright notice of
 21  Xerox Corporation, this paragraph and the one after it.  Any
 22  distribution of this software or derivative works must comply with all
 23  applicable United States export control laws.
 24
 25  This software is made available AS IS, and XEROX CORPORATION DISCLAIMS
 26  ALL WARRANTIES, EXPRESS OR IMPLIED, INCLUDING WITHOUT LIMITATION THE
 27  IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
 28  PURPOSE, AND NOTWITHSTANDING ANY OTHER PROVISION CONTAINED HEREIN, ANY
 29  LIABILITY FOR DAMAGES RESULTING FROM THE SOFTWARE OR ITS USE IS
 30  EXPRESSLY DISCLAIMED, WHETHER ARISING IN CONTRACT, TORT (INCLUDING
 31  NEGLIGENCE) OR STRICT LIABILITY, EVEN IF XEROX CORPORATION IS ADVISED
 32  OF THE POSSIBILITY OF SUCH DAMAGES.
 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->