source: to-imperative/trunk/runtime/rf_expr.ih @ 1106

Last change on this file since 1106 was 1106, checked in by luba, 17 years ago
  • type_short_int is replaced by type_int32, class ShortInt? is renamed to Int32
  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 21.5 KB
Line 
1//-----------------------------------------------------------------------------
2/// @file rf_expr.ih
3///
4/// Refal+ expression inline method implementation
5//
6//  $Source$
7//  $Revision: 1106 $
8//  $Date: 2003-08-06 13:30:09 +0000 (Wed, 06 Aug 2003) $
9//-----------------------------------------------------------------------------
10
11#ifndef __rf_expr_ih__
12#define __rf_expr_ih__
13
14#include "rf_expr.hh"
15#include "rf_term.ih"
16#include "rf_object_ref.ih"
17#include "rf_short_int.ih"
18#include "pxx_heap_allocator.ih"
19#include "pxx_common.ih"
20
21#include <wchar.h>
22#include <wctype.h>
23
24namespace rfrt
25{
26
27using namespace rftype ;
28
29inline Expr::Expr (
30  Term* const _first, Term* const _last,
31  MemoryChunk* const _mem_chunk, uintptr_t const _flags
32) :
33  first (_first),
34  last (_last),
35  mem_chunk (_mem_chunk),
36  flags (_flags)
37{
38  //
39  // Increment a reference counter to memory block containing an expression
40  mem_chunk->inc_ref_count();
41  D(printf("+ %p(%p,%p,%p) by generic constructor",
42           this, first, last, mem_chunk);)
43}
44
45inline Expr::Expr (Expr const* _expr) :
46  first (_expr->first),
47  last (_expr->last),
48  mem_chunk (_expr->mem_chunk),
49  flags (_expr->flags)
50{
51  //
52  // This is a special kind of copy constructor used to get arguments and
53  // results from stack. Do not increment a reference counter to memory block!
54//    inc_ref_count();
55  D(printf("+ %p(%p,%p,%p) from *%p\n",
56           this, first, last, mem_chunk, _expr);)
57}
58
59inline Expr::Expr (size_t _len, int _align)
60{
61  //
62  // Initialize an expression with requested length
63  init(_len, _align);
64  D(printf("+ %p(%p,%p,%p) of size %d\n", this, first, last, mem_chunk, _len);)
65}
66
67inline Expr::Expr (Object* _obj)
68{
69  init(1, 0);
70  new(first) ObjectRef(_obj);
71}
72
73#if 0
74inline Expr::Expr (char const* _string /* = null */)
75{
76  //
77  // Initialize an expression with necessary length
78  init(_string != null ? strlen(_string) : 0, 0);
79  //
80  // In a loop...
81  for (Term* p = first; p < last; p++, _string++) {
82    //
83    // ...create a symbol in place
84    new(p) Term(*_string);
85  }
86  //
87  // Mark expression as flat
88  flags = FLAT_BIT;
89  D(printf("+ %p(%p,%p,%p) from %s\n", this, first, last, mem_chunk, _string);)
90}
91#endif
92
93inline Expr::Expr ()
94{
95  init(0, 0);
96}
97
98inline Expr::Expr (Term const* _cp)
99{
100  //
101  // If we really have a reference term...
102  if (_cp->is_ref()) {
103    //
104    // ...get a first term of referenced expression...
105    first = _cp->get_first();
106    //
107    // ...and its right margin
108    last = _cp->get_last();
109    //
110    // Obtain a pointer to a memory block containing an expression
111    mem_chunk = _cp->get_mem_chunk();
112    //
113    // Increment reference counter to this memory block
114    mem_chunk->inc_ref_count();
115    //
116    // Check whether reference expression is flat and set a flag appropriately
117    flags = _cp->data1 & FLAT_BIT;
118    D(printf("+ %p(%p,%p,%p) from %p()\n", this, first, last, mem_chunk, _cp);)
119  }
120  //
121  // Oh, no, we have a symbol...
122  else {
123    //
124    // ...and this is the error
125    FATAL("Attempt to dereference a symbol" );
126  }
127}
128
129inline Expr::Expr (Expr const& _expr, uintptr_t _index)
130{
131  new(this) Expr(_expr.first + _index);
132}
133
134inline Expr::Expr (Expr const& _expr, uintptr_t _index, uintptr_t _length)
135{
136  //
137  // Call a generic constructor
138  new(this) Expr(
139    _expr.first + _index, _expr.first + _index + _length,
140    _expr.mem_chunk, _expr.flags
141  );
142}
143
144inline Expr::Expr (Expr const& _expr) :
145  first (_expr.first),
146  last (_expr.last),
147  mem_chunk (_expr.mem_chunk),
148  flags (_expr.flags)
149{
150  //
151  // Increment a reference counter to memory block
152  mem_chunk->inc_ref_count();
153  D(printf("+ %p(%p,%p,%p) by copy from %p\n",
154           this, first, last, mem_chunk, &_expr);)
155}
156
157inline Expr::~Expr ()
158{
159  D(printf("- %p(%p,%p,%p)\n", this, first, last, mem_chunk);)
160  //
161  // Destructor only calls a drop() method
162  drop();
163}
164
165inline Expr& Expr::operator = (Expr const& _expr)
166{
167  D(printf("%p(%p,%p,%p) = %p(%p,%p,%p)\n",
168           this, first, last, mem_chunk,
169           &_expr, _expr.first, _expr.last, _expr.mem_chunk);)
170  //
171  // If we are not assigning to self
172  if( this != &_expr ) {
173    //
174    // Destroy old expression
175    drop();
176    //
177    // Build a copy in place
178    new(this) Expr(_expr);
179  }
180  //
181  // Return reference to self
182  return *this;
183}
184
185inline Expr Expr::operator () () const
186{
187//  return Expr(Term(self));
188  Expr res(1, 0);
189  new(res.first) Term(self);
190  res.flags = 0;
191  return res;
192}
193
194inline Expr Expr::operator * () const
195{
196  if (last - first == 1) {
197    return Expr(first);
198  } else {
199    FATAL("Expression length not equal to 1");
200  }
201}
202
203inline bool Expr::symbol_at (uintptr_t _index) const
204{
205  return (first + _index)->is_sym();
206}
207
208inline bool Expr::is_flat () const
209{
210  return flags & FLAT_BIT;
211}
212
213inline bool Expr::is_empty () const
214{
215  return first == last;
216}
217
218inline Term* Expr::get_first () const
219{
220  return first;
221}
222
223inline Term* Expr::get_last () const
224{
225  return last;
226}
227
228inline uintptr_t Expr::get_len () const
229{
230  return last - first;
231}
232
233inline uintptr_t Expr::get_flags () const
234{
235  return flags;
236}
237
238inline void Expr::dump () const
239{
240  Term* p;
241  printf("%p, %p, %"PRIuPTR": ", first, last, last - first);
242  for (p = first; p < last; p++) {
243    printf("[%08"PRIxPTR" %08"PRIxPTR"]", p->data1, p->uint_data2);
244  }
245  printf("\n");
246}
247
248inline void Expr::drop ()
249{
250  //
251  // Decrement reference counter and destroy an object if it is zero
252  if (mem_chunk != null && mem_chunk->dec_ref_count() == 0) {
253    //
254    // Walk through and decrement reference counters on childs
255//    deref_childs();
256    deref_childs(first, is_flat() ? last : first, mem_chunk);
257    //
258    // Deallocate expression holder in memory
259    MemoryChunk::destroy_instance(mem_chunk);
260    D(printf("-- %p\n", mem_chunk);)
261  }
262  mem_chunk = null;
263}
264
265#if 0
266inline void Expr::ref_childs () const
267{
268  for (Term* p = first; p < last; p++) {
269    if (p->is_ref()) p->get_mem_chunk()->inc_ref_count();
270  }
271}
272#endif
273
274inline bool Expr::writeln (FILE* _fp) const
275{
276  if (!write (_fp)) return false;
277  if (fputc('\n', _fp) == EOF) return false;
278  return true;
279}
280
281inline bool Expr::println (FILE* _fp) const
282{
283  if (!print (_fp)) return false;
284  if (fputc('\n', _fp) == EOF) return false;
285  return true;
286}
287
288//
289// We prefer to have inline functions instead of macros, but changing macros
290// below to inline functions gives worse execution times
291
292///
293/// Check whether a term pointer is not a right margin of used area in
294/// a memory block
295#define is_not_right_margin(_p, _last) \
296  (((_p) < (_last)) && ((_p)->data1 != SYM_BORDER))
297
298///
299/// Check whether a term pointer is not a left margin of used area in
300/// a memory block
301#define is_not_left_margin(_p, _first) \
302  (((_p) >= (_first)) && ((_p)->data1 != SYM_BORDER))
303
304inline bool Expr::rt_alloc (uintptr_t _len) const
305{
306  //
307  // Get a pointer beyond the term area in our memory block
308  Term *p = static_cast<Term*>(mem_chunk->get_last());
309  //
310  // If our expression is the only one referencing a memory block than we can
311  // go to the right and destroy all terms there, because they are not a part
312  // of any expression
313  if (mem_chunk->no_extern_refs()) {
314    for (Term* q = last; is_not_right_margin(q, p); q++ ) {
315      q->~Term();
316    }
317    //
318    // Set correct right margin of used area in a memory block
319    if (last < p) last->data1 = SYM_BORDER;
320  } else {
321    //
322    // If there are other references to our memory block than if last is not
323    // a right margin of used area, we cannot allocate some space.
324    if (is_not_right_margin(last, p)) return false;
325  }
326  //
327  // Ok, here last is a a right margin of used area. Check whether we have
328  // enough space.
329  if (last + _len > p) return false;
330  //
331  // Set right margin if needed.
332  if (last + _len < p) (last + _len)->data1 = SYM_BORDER;
333  return true;
334}
335
336inline bool Expr::lt_alloc (uintptr_t _len) const
337{
338  Term* p = static_cast<Term*>(mem_chunk->get_first());
339  Term* f = first - 1;
340  if (mem_chunk->no_extern_refs()) {
341    for (Term* q = f; is_not_left_margin(q, p); q--) {
342      q->~Term();
343    }
344    if (f >= p) f->data1 = SYM_BORDER;
345  } else {
346    if (is_not_left_margin(f, p)) return false;
347  }
348  --p;
349  if (f - _len < p) return false;
350  if (f - _len > p) (f - _len)->data1 = SYM_BORDER;
351  return true;
352}
353
354//
355// FIXME: should be a real hash computation
356inline uint32_t Expr::hash () const
357{
358  return 0;
359}
360
361inline bool Expr::term_eq (Expr const& _expr, uintptr_t _index) const
362{
363  return *first == *(_expr.first + _index);
364}
365
366inline bool Expr::eq (Expr const& _expr, uintptr_t _index) const
367{
368  Term *f = _expr.first + _index;
369  if (first == f) {
370    #if DEBUG
371    identical++;
372    #endif
373    return true;
374  }
375  return Term::eq(first, f, get_len());
376}
377
378inline bool Expr::eq (Expr const& _expr, uintptr_t _index)
379{
380  Term *f = _expr.first + _index;
381  if (first == f) {
382    #if DEBUG
383    identical++;
384    #endif
385    return true;
386  }
387  bool res = Term::eq(first, f, get_len());
388  if (res) {
389    #if DEBUG
390    unifications++;
391    #endif
392    uintptr_t new_flags = flags | _expr.flags;
393    drop();
394    new(this) Expr(f, f + get_len(), _expr.mem_chunk, new_flags);
395  }
396  return res;
397}
398
399inline bool Expr::operator == (Expr const& _expr) const
400{
401  if (get_len() != _expr.get_len()) return false;
402  return eq(_expr, 0);
403}
404
405inline bool Expr::operator != (Expr const& _expr) const
406{
407  if (get_len() != _expr.get_len()) return true;
408  return !eq(_expr, 0);
409}
410
411inline bool Expr::operator == (Expr& _expr)
412{
413  if (first == _expr.first && last == _expr.last) {
414    #if DEBUG
415    identical++;
416    #endif
417    return true;
418  } else {
419    bool res = Term::eq(first, last, _expr.first, _expr.last);
420    if (res) {
421      #if DEBUG
422      unifications++;
423      #endif
424      if (mem_chunk->get_ref_count() >= _expr.mem_chunk->get_ref_count()) {
425        flags |= _expr.flags;
426        _expr = self;
427      } else {
428        _expr.flags |= flags;
429        self = _expr;
430      }
431    }
432    return res;
433  }
434}
435
436inline bool Expr::operator != (Expr& _expr)
437{
438  return !(self == _expr);
439}
440
441inline int Expr::compare (Expr const& _expr1, Expr const& _expr2)
442{
443  return Term::compare(_expr1.get_first(), _expr1.get_last(),
444                       _expr2.get_first(), _expr2.get_last());
445}
446
447inline MemoryChunk* Expr::get_mem_chunk () const
448{
449  return mem_chunk;
450}
451
452inline void Expr::set_mem_chunk (MemoryChunk* _ptr)
453{
454  mem_chunk = _ptr;
455}
456
457//
458// explicit specialization for SplitIterator constructor with left splitting
459template <>
460inline SplitIterator<d_lt>::SplitIterator (
461  Expr const& _expr, uintptr_t _min_len
462) :
463  lt (_expr.get_first(), _expr.get_first() + _min_len,
464      _expr.get_mem_chunk(), _expr.get_flags()),
465  rt (_expr.get_first() + _min_len, _expr.get_last(),
466      _expr.get_mem_chunk(), _expr.get_flags()),
467  state (true)
468{
469//  if (_min_len == 0) lt.flags = FLAT_BIT;
470}
471
472template <Direction D>
473SplitIterator<D>::~SplitIterator ()
474{}
475
476template <Direction D>
477inline SplitIterator<D>& SplitIterator<D>::operator ++ ()
478{
479  if (lt.last < rt.last) {
480    //
481    // FIXME: correctly we only should clear FLAT_BIT
482//    if (lt.last->is_ref()) lt.flags = 0;
483    lt.last++;
484    rt.first++;
485  } else {
486    state = false;
487  }
488  return *this;
489}
490
491template <Direction D>
492inline SplitIterator<D>& SplitIterator<D>::operator ++ (int)
493{
494  return operator++();
495}
496
497template <Direction D>
498inline SplitIterator<D>& SplitIterator<D>::operator -- ()
499{
500  if (lt.first < rt.first) {
501    lt.last--;
502    rt.first--;
503    //
504    // FIXME: correctly we only should clear FLAT_BIT
505//    if (rt.first->is_ref()) rt.flags = 0;
506  } else {
507    state = false;
508  }
509  return *this;
510}
511
512template <Direction D>
513inline SplitIterator<D>& SplitIterator<D>::operator -- (int)
514{
515  return operator--();
516}
517
518template <Direction D>
519inline SplitIterator<D>::operator bool ()
520{
521  return state;
522}
523
524template <Direction D>
525inline Expr const& SplitIterator<D>::get_left () const
526{
527  return lt;
528}
529
530template <Direction D>
531inline Expr const& SplitIterator<D>::get_right () const
532{
533  return rt;
534}
535
536#if defined(ALL_INLINE) || defined(INSTANTIATE_INLINE)
537
538INLINE Expr Expr::operator + (Expr const& _expr) const
539{
540  D(printf("Adding %p to %p\n", &_expr, this);)
541  if (last == _expr.first) {
542    #if DEBUG
543    empty_copy++;
544    #endif
545    //
546    // Call a generic constructor
547    return Expr (first, _expr.last, mem_chunk, flags & _expr.flags);
548  }
549  //
550  // Get lentgths of both arguments
551  uintptr_t len1 = last - first;
552  uintptr_t len2 = _expr.last - _expr.first;
553  //
554  // If a length of a second argument is zero do nothing and return a copy of
555  // a first argument
556  if (len2 == 0) {
557    #if DEBUG
558    empty_copy++;
559    #endif
560    return *this;
561  //
562  // If a length of a first argument is zero do nothing and return a copy of
563  // a second argument
564  } else if (len1 == 0) {
565    #if DEBUG
566    empty_copy++;
567    #endif
568    return _expr;
569  //
570  // Try to get a memory to the right of the first argument that able to
571  // contain a second argument
572  } else if (rt_alloc(len2)) {
573    //
574    // On success copy a contents of a second argument
575    #if DEBUG
576    rt_copy++;
577    #endif
578    //
579    // A legal method of copying expression contents is by perform per-term
580    // assignment. But in a case of a flat expression we need not that
581    // overhead. So we simply do memcpy() and advance child references only if
582    // needed.
583    //
584    // In a case of not flat expression advance reference counters for child
585    // memory blocks
586//    if (!_expr.is_flat()) _expr.ref_childs();
587    //
588    // Initialize expression by a copy of a first argument
589    Expr e(*this);
590//    memcpy(e.last, _expr.first, len2 * sizeof(Term));
591    if (_expr.is_flat())
592      memcpy(e.last, _expr.first, len2 * sizeof(Term));
593    else {
594      Term* to = e.last;
595      Term const* from = _expr.first;
596      while (from != _expr.last) {
597        new(to) Term(*from);
598        from++; to++;
599      }
600    }
601    //
602    // Adjust flags
603    e.flags &= _expr.flags;
604    //
605    // Adjust expression length
606    e.last += len2;
607    return e;
608  //
609  // Try to get a memory to the left of the second argument that able to
610  // contain a first argument
611  } else if (_expr.lt_alloc(len1)) {
612    //
613    // On success copy a contents of a first argument. This is almost the
614    // same as described above.
615    #if DEBUG
616    lt_copy++;
617    #endif
618//    if (!is_flat()) ref_childs();
619    Expr e(_expr);
620    e.first -= len1;
621//    memcpy(e.first, first, len1 * sizeof(Term));
622    if (is_flat()) memcpy(e.first, first, len1 * sizeof(Term));
623    else {
624      Term* to = e.first;
625      Term const* from = first;
626      while (from != last) {
627        new(to) Term(*from);
628        from++; to++;
629      }
630    }
631    e.flags &= flags;
632    return e;
633  //
634  // If all optimized copy methods fail, copy both arguments
635  } else {
636    #if DEBUG
637    both_copy++;
638    #endif
639    //
640    // Create a new expression with specified length. Use simple euristic to
641    // define appropriate alignment
642    Expr e(len1 + len2, len1 >= len2 ? 1 : -1);
643    //
644    // Child references are incremented separately for two arguments rather
645    // then for the resulting expression. This advances our chances to avoid
646    // some work in a case if at least one of two expressions is flat.
647    if (is_flat()) memcpy(e.first, first, len1 * sizeof(Term));
648    else {
649      Term* to = e.first;
650      Term const* from = first;
651      while (from != last) {
652        new(to) Term(*from);
653        from++; to++;
654      }
655    }
656    if (_expr.is_flat())
657      memcpy(e.first + len1, _expr.first, len2 * sizeof(Term));
658    else {
659      Term* to = e.first + len1;
660      Term const* from = _expr.first;
661      while (from != _expr.last) {
662        new(to) Term(*from);
663        from++; to++;
664      }
665    }
666    //
667    // Adjust flags
668    e.flags = flags & _expr.flags;
669//    if (!e.is_flat()) e.ref_childs();
670    return e;
671  }
672}
673
674INLINE void Expr::init (size_t _len, int _align)
675{
676  D(printf("init is called for %p\n", this);)
677  //
678  // Create a new memory block via allocator
679  mem_chunk = MemoryChunk::create_instance(_len * sizeof(Term));
680  //
681  // Get pointers to the first and beyond the last terms in allocated block
682  Term *start = static_cast<Term*>(mem_chunk->get_first());
683  Term *end   = static_cast<Term*>(mem_chunk->get_last());
684  //
685  // Compute expression margins depending on alignment inside memory block
686  if( _align > 0 ) {
687    //
688    // Left aligned expression
689    first = start;
690    last  = first + _len;
691  } else if( _align < 0 ) {
692    //
693    // Right aligned expression
694    last  = end;
695    first = last - _len;
696  } else {
697    //
698    // Center aligned expression
699    first = start + (mem_chunk->get_size() / sizeof(Term) - _len) / 2;
700    last  = first + _len;
701  }
702  //
703  // Setup border symbols if necessary
704  // FIXME: it is possible to slightly optimize this by moving a code below
705  // into appropriate parts of conditional operator above (for example, in a
706  // case of left aligned expression we never need to setup left border
707  // symbol).
708  if (first > start) {
709    (first - 1)->data1 = SYM_BORDER;
710  }
711  if (last < end) {
712    last->data1 = SYM_BORDER;
713  }
714  //
715  // Expression with zero length is always "flat"
716  if (_len == 0) flags = FLAT_BIT;
717  else flags = 0;
718}
719
720INLINE void Expr::deref_childs (
721  Term* _first, Term* _last, MemoryChunk* _mem
722)
723{
724  //
725  // First go to the left, and deal with all reference terms there.
726  _first--;
727  Term* p = _mem->get_first();
728  while (is_not_left_margin(_first, p)) {
729    _first->~Term();
730    _first--;
731  }
732  //
733  // Go to the right, and deal with all reference terms there.
734  p = _mem->get_last();
735  while (is_not_right_margin(_last, p)) {
736    _last->~Term();
737    _last++;
738  }
739}
740
741INLINE void Expr::deref_childs () const
742{
743  //
744  // First go to the left, and deal with all reference terms there.
745  Term* r = first - 1;
746  Term* p = mem_chunk->get_first();
747  while (is_not_left_margin(r, p)) {
748    r->~Term();
749    r--;
750  }
751  //
752  // If our expression is flat we may skip its body
753  r = is_flat() ? last : first;
754  //
755  // Go to the right, and deal with all reference terms there.
756  p = mem_chunk->get_last();
757  while (is_not_right_margin(r, p)) {
758    r->~Term();
759    r++;
760  }
761}
762
763static INLINE bool is_good_wstr (WString const& _ws)
764{
765  wchar_t const* p = _ws.get_data();
766  wchar_t wc;
767  bool first = true;
768  if (*p == null) return false;
769  while ((wc = *p++) != null) {
770    if (!iswalnum(wc) && wc != L'!' && wc != L'?' && wc != L'-') return false;
771    if (first && !iswupper(wc)) return false;
772    first = false;
773  }
774  return true;
775}
776
777static INLINE bool write_wstr (FILE* _fp, WString const& _ws)
778{
779  wchar_t const* p = _ws.get_data();
780  wchar_t wc;
781  char buf[MB_CUR_MAX + 1];
782  while ((wc = *p++) != null) {
783    switch (wc) {
784    case L'\t':
785      if (fputs("\\t", _fp) == EOF) return false; break;
786    case L'\r':
787      if (fputs("\\r", _fp) == EOF) return false; break;
788    case L'\n':
789      if (fputs("\\n", _fp) == EOF) return false; break;
790    case L'\v':
791      if (fputs("\\v", _fp) == EOF) return false; break;
792    case L'\\':
793      if (fputs("\\\\", _fp) == EOF) return false; break;
794    case L'\'':
795      if (fputs("\\\'", _fp) == EOF) return false; break;
796    case L'\"':
797      if (fputs("\\\"", _fp) == EOF) return false; break;
798    default:
799      if (iswprint(wc)) {
800        size_t n = wctomb(buf, wc);
801        if (n != (size_t)(-1)) {
802          buf[n] = 0;
803          if (fputs(buf, _fp) == EOF) return false;
804        } else {
805          if (fprintf(_fp, "\\%04x", wc) == -1) return false;
806        }
807      } else {
808        if (fprintf(_fp, "\\%04x", wc) == -1) return false;
809      }
810    }
811  }
812  return true;
813}
814
815INLINE bool Expr::write (FILE* _fp) const
816{
817  bool chars_flag = false;
818  for (Term* p = first; p < last; p++) {
819    if (p->get_type() == type_char) {
820      if (!chars_flag) {
821        if (p != first) {
822          if (fputc(' ', _fp) == EOF) return false;
823        }
824        if (fputc('\'', _fp) == EOF) return false;
825        chars_flag = true;
826      }
827      if (!write_wstr(_fp, (WString)(*p))) return false;
828    } else {
829      if (chars_flag) {
830        if (fputc('\'', _fp) == EOF) return false;
831        chars_flag = false;
832      }
833      if (p != first) fputc(' ', _fp);
834      if (p->get_type() == type_ref) {
835        if (fputs("( ", _fp) == EOF) return false;
836        Expr e(p);
837        if (!e.write(_fp)) return false;
838        if (fputs(" )", _fp) == EOF) return false;
839      } else if (p->get_type() == type_word) {
840        WString ws = (WString)(*p);
841        bool f = is_good_wstr(ws);
842        if (!f) fputc('\"', _fp);
843        if (!write_wstr(_fp, ws)) return false;
844        if (!f) fputc('\"', _fp);
845      } else if (p->get_type() == type_int32) {
846        if (fprintf(_fp, "%" PRIdPTR, ((Int32 const&)(*p)).to_int()) == -1)
847          return false;
848      } else {
849        FATAL("Not supported yet");
850      }
851    }
852  }
853  if (chars_flag) {
854    if (fputc('\'', _fp) == EOF) return false;
855  }
856  return true;
857}
858
859INLINE bool Expr::print (FILE* _fp) const
860{
861  for (Term* p = first; p < last; p++) {
862    if (p->is_sym()) {
863      WString s = (WString)(*p);
864      size_t len = s.get_length();
865      char buf[MB_CUR_MAX + 1];
866      for (size_t i = 0; i < len; i++) {
867        size_t n = wctomb(buf, s[i]);
868        if (n != (size_t)(-1)) {
869          buf[n] = 0;
870          if (fputs(buf, _fp) == EOF) return false;
871        } else {
872          if (fputc('?', _fp) == EOF) return false;
873        }
874      }
875    } else if (p->is_ref()) {
876      if (fputc('(', _fp) == EOF) return false;
877      Expr e(p);
878      if (!e.print(_fp)) return false;
879      if (fputc(')', _fp) == EOF) return false;
880    } else {
881      FATAL("Not supported yet");
882    }
883  }
884  return true;
885}
886
887INLINE Expr::operator WString () const
888{
889  WString res;
890  for (Term* p = first; p < last; p++) {
891    if (p->is_sym()) {
892      res = res + (WString)(*p);
893    } else if (p->is_ref()) {
894      res = res + WString(L"(") + (WString)(Expr(p)) + WString(L")");
895    } else {
896      FATAL("Not supported yet");
897    }
898  }
899  return res;
900}
901
902#endif // ALL_INLINE
903
904#undef is_not_right_margin
905#undef is_not_left_margin
906
907}
908
909#endif // __rf_expr_ih__
Note: See TracBrowser for help on using the repository browser.