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

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