1 // Copyright (c) 1996 James Clark
2 // See the file copying.txt for copying permission.
3 
4 #include "stylelib.h"
5 #include "Interpreter.h"
6 #include "Insn.h"
7 #include "InterpreterMessages.h"
8 #include "LocNode.h"
9 #include "Pattern.h"
10 #include "MacroFlowObj.h"
11 #include "ELObjMessageArg.h"
12 #include "VM.h"
13 #include "Owner.h"
14 #include "SchemeParser.h"
15 #include "macros.h"
16 #include "InternalInputSource.h"
CheckSosofoInsn(const Location & loc,InsnPtr next)17 #include <stdlib.h>
18 #include "LangObj.h"
19 
20 #ifdef DSSSL_NAMESPACE
21 namespace DSSSL_NAMESPACE {
22 #endif
23 
24 const Char defaultChar = 0xfffd;
25 
26 static
27 size_t maxObjSize()
28 {
29   static size_t sz[] = {
30     sizeof(UnresolvedQuantityObj),
31     sizeof(VarStyleObj),
32     sizeof(OverriddenStyleObj),
33     sizeof(MergeStyleObj),
34     sizeof(DeviceRGBColorObj),
35     sizeof(ColorSpaceObj),
36     sizeof(PairObj),
37     sizeof(QuantityObj),
38     sizeof(GlyphIdObj),
39     sizeof(NamedNodeListPtrNodeListObj),
40     sizeof(ProcessNodeSosofoObj),
41     sizeof(AppendSosofoObj),
42     sizeof(SetNonInheritedCsSosofoObj),
43     sizeof(LabelSosofoObj),
44     sizeof(MacroFlowObj),
45     sizeof(FlowObj) + sizeof(StringC), // for FormattingInstructionFlowObj
46     sizeof(LangObj),
47 #ifdef SP_HAVE_LOCALE
48 #ifdef SP_HAVE_WCHAR
49     sizeof(RefLangObj),
50 #endif
51 #endif
52   };
53   size_t n = sz[0];
54   for (size_t i = 1; i < SIZEOF(sz); i++)
55     if (sz[i] > n)
56       n = sz[i];
57   return n;
58 }
59 
60 Interpreter::Interpreter(GroveManager *groveManager,
61 			 Messenger *messenger,
62 			 int unitsPerInch,
63 			 bool debugMode,
64 			 bool dsssl2,
65                          bool strictMode,
66 			 const FOTBuilder::Extension *extensionTable)
67 : groveManager_(groveManager),
68   messenger_(messenger),
69   extensionTable_(extensionTable),
70   Collector(maxObjSize()),
71   partIndex_(0),  // 0 is for command-line definitions
72   dPartIndex_(1),
73   lexCategory_(lexOther),
74   unitsPerInch_(unitsPerInch),
75   nInheritedC_(0),
76   initialProcessingMode_(StringC()),
77   currentPartFirstInitialValue_(0),
78   initialStyle_(0),
79   nextGlyphSubstTableUniqueId_(0),
80   debugMode_(debugMode),
81   dsssl2_(dsssl2),
82   strictMode_(strictMode)
83 {
84   makePermanent(theNilObj_ = new (*this) NilObj);
85   makePermanent(theFalseObj_ = new (*this) FalseObj);
86   makePermanent(theTrueObj_ = new (*this) TrueObj);
87   makePermanent(theErrorObj_ = new (*this) ErrorObj);
88   makePermanent(theUnspecifiedObj_ = new (*this) UnspecifiedObj);
89   makePermanent(addressNoneObj_
90                 = new (*this) AddressObj(FOTBuilder::Address::none));
91   makePermanent(emptyNodeListObj_
92 		= new (*this) NodePtrNodeListObj);
93   defaultLanguage_ = theFalseObj_;
94   installSyntacticKeys();
95   installCValueSymbols();
96   installPortNames();
97   installPrimitives();
98   installUnits();
99   if (!strictMode_) {
100     installCharNames();
101     installSdata();
102   }
103   installFlowObjs();
104   installInheritedCs();
105   installNodeProperties();
106 
107   static const char *lexCategories[] = {
108     "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz",
109     "!$%&*/<=>?~_^:",
110     "",
111     "0123456789",
112     "-+.",
113     "",
114     "();\"",
115     " \t\r\n\f",
116     "",
117   };
118   lexCategory_.setEe(lexDelimiter);
119   for (size_t i = 0; i < SIZEOF(lexCategories); i++)
120     for (const char *s = lexCategories[i]; *s; s++)
121       lexCategory_.setChar(*s, i);
122 
123   // #',@[\\]`{|} are ASCII chars not mentioned above,
124   // but I guess we don't want to allow any of these
125   // in names (as most of them have special meaning in
126   // scheme/dsssl).
127   if (!strictMode_)
128     for (Char i = 127; i < charMax; i++)
129       lexCategory_.setChar(i, lexAddNameStart);
130 
131   initialProcessingMode_.setDefined();
132   // can't be done before initializing lexCategory_
133   installBuiltins();
134   installCharProperties();
135 }
136 
137 void Interpreter::compile()
138 {
139   // FIXME compile all definitions
140   compileInitialValues();
141   initialProcessingMode_.compile(*this);
142   NamedTableIter<ProcessingMode> iter(processingModeTable_);
143   for (;;) {
144     ProcessingMode *mode = iter.next();
145     if (!mode)
146       break;
147     mode->compile(*this);
148   }
149   compileCharProperties();
150   compileDefaultLanguage();
151 }
152 
153 void Interpreter::compileInitialValues()
154 {
155   Vector<ConstPtr<InheritedC> > ics;
156   for (size_t i = 0; i < initialValueNames_.size(); i++) {
157     const Identifier *ident = initialValueNames_[i];
158     Owner<Expression> &expr = initialValueValues_[i];
159     ConstPtr<InheritedC> ic(ident->inheritedC());
160     expr->optimize(*this, Environment(), expr);
161     ELObj *val = expr->constantValue();
162     if (val) {
163       ConstPtr<InheritedC> tem(ic->make(val, expr->location(), *this));
164       if (!tem.isNull())
165 	ics.push_back(tem);
166     }
167     else
168       ics.push_back(new VarInheritedC(ic,
169     			              expr->compile(*this, Environment(), 0, InsnPtr()),
170 			              expr->location()));
171   }
172   if (ics.size()) {
173     Vector<ConstPtr<InheritedC> > forceIcs;
174     initialStyle_ = new (*this) VarStyleObj(new StyleSpec(forceIcs, ics), 0, 0, NodePtr());
175     makePermanent(initialStyle_);
176   }
177 }
178 
179 void Interpreter::installInitialValue(Identifier *ident, Owner<Expression> &expr)
180 {
181   for (size_t i = 0; i < initialValueNames_.size(); i++) {
182     if (ident == initialValueNames_[i]) {
183       if (i >= currentPartFirstInitialValue_) {
184 	setNextLocation(expr->location());
185 	message(InterpreterMessages::duplicateInitialValue,
186 	        StringMessageArg(ident->name()),
187 		initialValueValues_[i]->location());
188       }
189       return;
190     }
191   }
192   initialValueValues_.resize(initialValueValues_.size() + 1);
193   expr.swap(initialValueValues_.back());
194   initialValueNames_.push_back(ident);
195 }
196 
197 void Interpreter::installUnits()
198 {
199   static struct {
200     const char *name;
201     int numer;
202     int denom;
203     bool dsssl2;
204   } units[] = {
205     { "m", 5000, 127 },
206     { "cm", 50, 127 },
207     { "mm", 5, 127 },
208     { "in", 1, 1 },
209     { "pt", 1, 72 },
210     { "pica", 1, 6 },
211     { "pc", 1, 6 } // a DSSSL2 addition
212   };
213   size_t nUnits = dsssl2() ? SIZEOF(units) : SIZEOF(units) - 1;
214   for (size_t i = 0; i < nUnits; i++) {
215     Unit *unit = lookupUnit(makeStringC(units[i].name));
216     long n = unitsPerInch_ * units[i].numer;
217     if (n % units[i].denom == 0)
218       unit->setValue(long(n / units[i].denom));
219     else
220       unit->setValue(double(n)/units[i].denom);
221   }
222 }
223 
224 void Interpreter::installSyntacticKeys()
225 {
226   static struct {
227     const char *name;
228     Identifier::SyntacticKey key;
229   } keys[] = {
230     { "quote", Identifier::keyQuote },
231     { "lambda", Identifier::keyLambda },
232     { "if", Identifier::keyIf },
233     { "cond", Identifier::keyCond },
234     { "and", Identifier::keyAnd },
235     { "or", Identifier::keyOr },
236     { "case", Identifier::keyCase },
237     { "let", Identifier::keyLet },
238     { "let*", Identifier::keyLetStar },
239     { "letrec", Identifier::keyLetrec },
240     { "quasiquote", Identifier::keyQuasiquote },
241     { "unquote", Identifier::keyUnquote },
242     { "unquote-splicing", Identifier::keyUnquoteSplicing },
243     { "define", Identifier::keyDefine },
244     { "else", Identifier::keyElse },
245     { "=>", Identifier::keyArrow },
246     { "there-exists?", Identifier::keyThereExists },
247     { "for-all?", Identifier::keyForAll },
248     { "select-each", Identifier::keySelectEach },
249     { "union-for-each", Identifier::keyUnionForEach },
250     { "make", Identifier::keyMake },
251     { "style", Identifier::keyStyle },
252     { "with-mode", Identifier::keyWithMode },
253     { "define-unit", Identifier::keyDefineUnit },
254     { "query", Identifier::keyQuery },
255     { "element", Identifier::keyElement },
256     { "default", Identifier::keyDefault },
257     { "root", Identifier::keyRoot },
258     { "id", Identifier::keyId },
259     { "mode", Identifier::keyMode },
260     { "declare-initial-value", Identifier::keyDeclareInitialValue },
261     { "declare-characteristic", Identifier::keyDeclareCharacteristic },
262     { "declare-flow-object-class", Identifier::keyDeclareFlowObjectClass },
263     { "declare-char-characteristic+property", Identifier::keyDeclareCharCharacteristicAndProperty },
264     { "declare-reference-value-type", Identifier::keyDeclareReferenceValueType },
265     { "declare-default-language", Identifier::keyDeclareDefaultLanguage },
266     { "declare-char-property", Identifier::keyDeclareCharProperty },
267     { "define-page-model", Identifier::keyDefinePageModel },
268     { "define-column-set-model", Identifier::keyDefineColumnSetModel },
269     { "define-language", Identifier::keyDefineLanguage },
270     { "add-char-properties", Identifier::keyAddCharProperties },
271     { "use", Identifier::keyUse },
272     { "label", Identifier::keyLabel },
273     { "content-map", Identifier::keyContentMap },
274     { "keep-with-previous?", Identifier::keyIsKeepWithPrevious },
275     { "keep-with-next?", Identifier::keyIsKeepWithNext },
276     { "space-before", Identifier::keySpaceBefore },
277     { "space-after", Identifier::keySpaceAfter },
278     { "left-header", Identifier::keyLeftHeader },
279     { "center-header", Identifier::keyCenterHeader },
280     { "right-header", Identifier::keyRightHeader },
281     { "left-footer", Identifier::keyLeftFooter },
282     { "center-footer", Identifier::keyCenterFooter },
283     { "right-footer", Identifier::keyRightFooter },
284     { "destination", Identifier::keyDestination },
285     { "type", Identifier::keyType },
286     { "coalesce-id", Identifier::keyCoalesceId },
287     { "display?", Identifier::keyIsDisplay },
288     { "scale", Identifier::keyScale },
289     { "max-width", Identifier::keyMaxWidth },
290     { "max-height", Identifier::keyMaxHeight },
291     { "entity-system-id", Identifier::keyEntitySystemId },
292     { "notation-system-id", Identifier::keyNotationSystemId },
293     { "position-point-x", Identifier::keyPositionPointX },
294     { "position-point-y", Identifier::keyPositionPointY },
295     { "escapement-direction", Identifier::keyEscapementDirection },
296     { "break-before-priority", Identifier::keyBreakBeforePriority },
297     { "break-after-priority", Identifier::keyBreakAfterPriority },
298     { "orientation", Identifier::keyOrientation },
299     { "length", Identifier::keyLength },
300     { "char", Identifier::keyChar },
301     { "glyph-id", Identifier::keyGlyphId },
302     { "space?", Identifier::keyIsSpace },
303     { "record-end?", Identifier::keyIsRecordEnd },
304     { "input-tab?", Identifier::keyIsInputTab },
305     { "input-whitespace?", Identifier::keyIsInputWhitespace },
306     { "punct?", Identifier::keyIsPunct },
307     { "drop-after-line-break?", Identifier::keyIsDropAfterLineBreak },
308     { "drop-unless-before-line-break?", Identifier::keyIsDropUnlessBeforeLineBreak },
309     { "math-class", Identifier::keyMathClass },
310     { "math-font-posture", Identifier::keyMathFontPosture },
311     { "script", Identifier::keyScript },
312     { "stretch-factor", Identifier::keyStretchFactor },
313     { "keep", Identifier::keyKeep },
314     { "break-before", Identifier::keyBreakBefore },
315     { "break-after", Identifier::keyBreakAfter },
316     { "may-violate-keep-before?", Identifier::keyIsMayViolateKeepBefore },
317     { "may-violate-keep-after?", Identifier::keyIsMayViolateKeepAfter },
318     { "before-row-border", Identifier::keyBeforeRowBorder },
319     { "after-row-border", Identifier::keyAfterRowBorder },
320     { "before-column-border", Identifier::keyBeforeColumnBorder },
321     { "after-column-border", Identifier::keyAfterColumnBorder },
322     { "column-number", Identifier::keyColumnNumber },
323     { "row-number", Identifier::keyRowNumber },
324     { "n-columns-spanned", Identifier::keyNColumnsSpanned },
325     { "n-rows-spanned", Identifier::keyNRowsSpanned },
326     { "width", Identifier::keyWidth },
327     { "starts-row?", Identifier::keyIsStartsRow },
328     { "ends-row?", Identifier::keyIsEndsRow },
329     { "table-width", Identifier::keyTableWidth },
330     { "multi-modes", Identifier::keyMultiModes },
331     { "data", Identifier::keyData },
332     { "min", Identifier::keyMin },
333     { "max", Identifier::keyMax },
334     { "conditional?", Identifier::keyIsConditional },
335     { "priority", Identifier::keyPriority },
336     { "grid-n-rows", Identifier::keyGridNRows },
337     { "grid-n-columns", Identifier::keyGridNColumns },
338     { "radical", Identifier::keyRadical },
339     { "null", Identifier::keyNull },
340     { "rcs?", Identifier::keyIsRcs },
341     { "parent", Identifier::keyParent },
342     { "active", Identifier::keyActive },
343     { "attributes", Identifier::keyAttributes },
344     { "children", Identifier::keyChildren },
345     { "repeat", Identifier::keyRepeat },
346     { "position", Identifier::keyPosition },
347     { "only", Identifier::keyOnly },
348     { "class", Identifier::keyClass },
349     { "importance", Identifier::keyImportance },
350     { "position-preference", Identifier::keyPositionPreference },
351     { "collate", Identifier::keyCollate },
352     { "toupper", Identifier::keyToupper },
353     { "tolower", Identifier::keyTolower },
354     { "symbol", Identifier::keySymbol },
355     { "order", Identifier::keyOrder },
356     { "forward", Identifier::keyForward },
357     { "backward", Identifier::keyBackward },
358     { "white-point", Identifier::keyWhitePoint },
359     { "black-point", Identifier::keyBlackPoint },
360     { "range", Identifier::keyRange },
361     { "range-abc", Identifier::keyRangeAbc },
362     { "range-lmn", Identifier::keyRangeLmn },
363     { "range-a", Identifier::keyRangeA },
364     { "decode-abc", Identifier::keyDecodeAbc },
365     { "decode-lmn", Identifier::keyDecodeLmn },
366     { "decode-a", Identifier::keyDecodeA },
367     { "matrix-abc", Identifier::keyMatrixAbc },
368     { "matrix-lmn", Identifier::keyMatrixLmn },
369     { "matrix-a", Identifier::keyMatrixA },
370     { "architecture", Identifier::keyArchitecture },
371     { "height", Identifier::keyHeight },
372     { "contents-rotation", Identifier::keyContentsRotation },
373     { "open", Identifier::keyOpen },
374     { "close", Identifier::keyClose },
375     { "mark", Identifier::keyMark },
376     { "direction", Identifier::keyDirection },
377   }, keys2[] = {
378     { "declare-class-attribute", Identifier::keyDeclareClassAttribute },
379     { "declare-id-attribute", Identifier::keyDeclareIdAttribute },
380     { "declare-flow-object-macro", Identifier::keyDeclareFlowObjectMacro },
381     { "or-element", Identifier::keyOrElement },
382     { "set!", Identifier::keySet },
383     { "begin", Identifier::keyBegin },
384   };
385   for (size_t i = 0; i < SIZEOF(keys); i++) {
386     StringC tem(makeStringC(keys[i].name));
387     lookup(tem)->setSyntacticKey(keys[i].key);
388     if (dsssl2() && tem[tem.size() - 1] == '?') {
389       tem.resize(tem.size() - 1);
390       lookup(tem)->setSyntacticKey(keys[i].key);
391     }
392   }
393   if (dsssl2()) {
394     for (size_t i = 0; i < SIZEOF(keys2); i++)
395       lookup(makeStringC(keys2[i].name))->setSyntacticKey(keys2[i].key);
396   }
397 }
398 
399 void Interpreter::installCValueSymbols()
400 {
401   cValueSymbols_[0] = makeFalse();
402   cValueSymbols_[1] = makeTrue();
403   for (size_t i = 2; i < FOTBuilder::nSymbols; i++) {
404     SymbolObj *sym = makeSymbol(makeStringC(FOTBuilder::symbolName(FOTBuilder::Symbol(i))));
405     sym->setCValue(FOTBuilder::Symbol(i));
406     cValueSymbols_[i] = sym;
407   }
408 }
409 
410 void Interpreter::installPortNames()
411 {
412   // These must match the order in SymbolObj.
413   static const char *names[] = {
414     "numerator",
415     "denominator",
416     "pre-sup",
417     "pre-sub",
418     "post-sup",
419     "post-sub",
420     "mid-sup",
421     "mid-sub",
422     "over-mark",
423     "under-mark",
424     "open",
425     "close",
426     "degree",
427     "operator",
428     "lower-limit",
429     "upper-limit",
430     "header",
431     "footer"
432   };
433   ASSERT(SIZEOF(names) == nPortNames);
434   for (size_t i = 0; i < SIZEOF(names); i++)
435     portNames_[i] = makeSymbol(makeStringC(names[i]));
436 }
437 
438 void Interpreter::installCharNames()
439 {
440   static struct {
441     Char c;
442     const char *name;
443   } chars[] = {
444 #include "charNames.h"
445   };
446   for (size_t i = 0; i < SIZEOF(chars); i++) {
447     CharPart ch;
448     ch.c = chars[i].c;
449     ch.defPart = unsigned(-1);
450     namedCharTable_.insert(makeStringC(chars[i].name), ch, 1);
451   }
452 }
453 
454 void Interpreter::installSdata()
455 {
456   // This comes from uni2sgml.txt on ftp://unicode.org.
457   // It is marked there as obsolete, so it probably ought to be checked.
458   // The definitions of apos and quot have been fixed for consistency with XML.
459   static struct {
460     Char c;
461     const char *name;
462   } entities[] = {
463 #include "sdata.h"
464   };
465   for (size_t i = 0; i < SIZEOF(entities); i++) {
466     CharPart ch;
467     ch.c = entities[i].c;
468     ch.defPart = unsigned(-1);
469     sdataEntityNameTable_.insert(makeStringC(entities[i].name), ch, 1);
470   }
471 }
472 
473 void Interpreter::installNodeProperties()
474 {
475   for (int i = 0; i < ComponentName::nIds; i++) {
476     ComponentName::Id id = ComponentName::Id(i);
477     nodePropertyTable_.insert(makeStringC(ComponentName::rcsName(id)), i);
478     nodePropertyTable_.insert(makeStringC(ComponentName::sdqlName(id)), i);
479   }
480 }
481 
482 void Interpreter::setCharRepertoire(const StringC &pubid)
483 {
484   if (pubid == "UNREGISTERED::OpenJade//Character Repertoire::OpenJade") {
485     if (strictMode_) {
486       installCharNames();
487       installSdata();
488       // This assumes that we process char-repertoire
489       // declaration before any declarations which change
490       // lexical categories.
491       for (Char i = 127; i < charMax; i++)
492         lexCategory_.setChar(i, lexAddNameStart);
493       strictMode_ = 0;
494     }
495    } else
496      message(InterpreterMessages::unsupportedCharRepertoire,
497                 StringMessageArg(pubid));
498 }
499 
500 void Interpreter::addStandardChar(const StringC &name, const StringC &num)
501 {
502   int n;
503   size_t i = 0;
504   if (!scanSignDigits(num, i, n)) {
505     message(InterpreterMessages::invalidCharNumber, StringMessageArg(num));
506     return;
507   }
508 
509   const CharPart *def = namedCharTable_.lookup(name);
510   CharPart ch;
511   ch.c = n;
512   ch.defPart = dPartIndex_;
513   if (def) {
514     if (dPartIndex_ < def->defPart)
515       namedCharTable_.insert(name, ch, 1);
516     else if (def->defPart == dPartIndex_ && def->c != ch.c)
517       message(InterpreterMessages::duplicateCharName,
518     	      StringMessageArg(name));
519   }
520   else
521     namedCharTable_.insert(name, ch, 1);
522 }
523 
524 void Interpreter::addNameChar(const StringC &name)
525 {
526   const CharPart *cp = namedCharTable_.lookup(name);
527   if (!cp)
528     message(InterpreterMessages::badCharName,
529             StringMessageArg(name));
530   else if (lexCategory_[cp->c] != lexOther)
531     // FIXME give a more specific error
532     message(InterpreterMessages::badDeclaration);
533   else
534     lexCategory_.setChar(cp->c, lexAddNameStart);
535 }
536 
537 void Interpreter::addSeparatorChar(const StringC &name)
538 {
539   const CharPart *cp = namedCharTable_.lookup(name);
540   if (!cp)
541     message(InterpreterMessages::badCharName,
542             StringMessageArg(name));
543   else if (lexCategory_[cp->c] != lexOther)
544     // FIXME give a more specific error
545     message(InterpreterMessages::badDeclaration);
546   else
547     lexCategory_.setChar(cp->c, lexAddWhiteSpace);
548 }
549 
550 void Interpreter::addSdataEntity(const StringC &ename, const StringC &etext, const StringC &name)
551 {
552   const CharPart *cp = namedCharTable_.lookup(name);
553   if (!cp) {
554     message(InterpreterMessages::badCharName,
555             StringMessageArg(name));
556     return;
557   }
558 
559   CharPart ch;
560   ch.c = cp->c;
561   ch.defPart = dPartIndex_;
562 
563   if (ename.size() > 0) {
564     const CharPart *def = sdataEntityNameTable_.lookup(ename);
565     if (def) {
566       if (dPartIndex_ < def->defPart)
567 	sdataEntityNameTable_.insert(ename, ch);
568       else if (def->defPart == dPartIndex_ && def->c != cp->c)
569        	message(InterpreterMessages::duplicateSdataEntityName,
570 		StringMessageArg(ename));
571     }
572     else
573       sdataEntityNameTable_.insert(ename, ch);
574   }
575 
576   if (etext.size() > 0) {
577     const CharPart *def = sdataEntityTextTable_.lookup(etext);
578     if (def) {
579       if (dPartIndex_ < def->defPart)
580 	sdataEntityTextTable_.insert(etext, ch);
581       else if (def->defPart == dPartIndex_ && def->c != cp->c)
582        	message(InterpreterMessages::duplicateSdataEntityText,
583 		StringMessageArg(etext));
584     }
585     else
586       sdataEntityTextTable_.insert(etext, ch);
587   }
588 }
589 
590 bool Interpreter::sdataMap(GroveString name, GroveString text, GroveChar &c) const
591 {
592   StringC tem(name.data(), name.size());
593   StringC tem2(text.data(), text.size());
594 
595   const CharPart *cp = sdataEntityNameTable_.lookup(tem);
596   if (cp) {
597     c = cp->c;
598     return 1;
599   }
600 
601   cp = sdataEntityTextTable_.lookup(tem2);
602   if (cp) {
603     c = cp->c;
604     return 1;
605   }
606 
607   if (convertUnicodeCharName(tem, c))
608     return 1;
609   // I think this is the best thing to do.
610   // At least it makes preserve-sdata work with unknown SDATA entities.
611   c = defaultChar;
612   return 1;
613 }
614 
615 ELObj *Interpreter::convertGlyphId(const Char *str, size_t len, const Location &loc)
616 {
617   unsigned long n = 0;
618   const char *publicId = 0;
619   for (size_t i = len; i > 1; --i) {
620     if (str[i - 1] == ':' && str[i - 2] == ':' && i < len && str[i] != '0') {
621       for (size_t j = i; j < len; j++)
622 	n = n*10 + (str[j] - '0');
623       publicId = storePublicId(str, i - 2, loc);
624       break;
625     }
626     if (str[i - 1] < '0' || str[i - 1] > '9')
627       break;
628   }
629   if (!publicId)
630     publicId = storePublicId(str, len, loc);
631   return new (*this) GlyphIdObj(FOTBuilder::GlyphId(publicId, n));
632 }
633 
634 bool Interpreter::convertCharName(const StringC &str, Char &c) const
635 {
636   const CharPart *cp = namedCharTable_.lookup(str);
637   if (cp) {
638     c = cp->c;
639     return 1;
640   }
641   return convertUnicodeCharName(str, c);
642 }
643 
644 bool Interpreter::convertUnicodeCharName(const StringC &str, Char &c)
645 {
646   if (str.size() != 6 || str[0] != 'U' || str[1] != '-')
647     return 0;
648   Char value = 0;
649   for (int i = 2; i < 6; i++) {
650     value <<= 4;
651     switch (str[i]) {
652     case '0':
653     case '1':
654     case '2':
655     case '3':
656     case '4':
657     case '5':
658     case '6':
659     case '7':
660     case '8':
661     case '9':
662       value |= str[i] - '0';
663       break;
664     case 'A':
665     case 'B':
666     case 'C':
667     case 'D':
668     case 'E':
669     case 'F':
670       value |= 10 + (str[i] - 'A');
671       break;
672     default:
673       return 0;
674     }
675   }
676   c = value;
677   return 1;
678 }
679 
680 SymbolObj *Interpreter::makeSymbol(const StringC &str)
681 {
682   SymbolObj *sym = symbolTable_.lookup(str);
683   if (!sym) {
684     StringObj *strObj = new (*this) StringObj(str);
685     makePermanent(strObj);
686     sym = new (*this) SymbolObj(strObj);
687     makePermanent(sym);
688     symbolTable_.insert(sym);
689   }
690   return sym;
691 }
692 
693 Identifier *Interpreter::lookup(const StringC &str)
694 {
695   Identifier *ident = identTable_.lookup(str);
696   if (!ident) {
697     ident = new Identifier(str);
698     identTable_.insert(ident);
699   }
700   return ident;
701 }
702 
703 bool Interpreter::lookupNodeProperty(const StringC &str, ComponentName::Id &id)
704 {
705   const int *val = nodePropertyTable_.lookup(str);
706   if (!val) {
707     StringC tem(str);
708     for (size_t i = 0; i < tem.size(); i++) {
709       if (tem[i] >= 'A' && tem[i] <= 'Z')
710         tem[i] = 'a' + (tem[i] - 'A');
711     }
712     val = nodePropertyTable_.lookup(tem);
713     if (!val)
714       return 0;
715   }
716   id = ComponentName::Id(*val);
717   return 1;
718 }
719 
720 Unit *Interpreter::lookupUnit(const StringC &str)
721 {
722   Unit *unit = unitTable_.lookup(str);
723   if (!unit) {
724     unit = new Unit(str);
725     unitTable_.insert(unit);
726   }
727   return unit;
728 }
729 
730 ProcessingMode *Interpreter::lookupProcessingMode(const StringC &str)
731 {
732   ProcessingMode *mode = processingModeTable_.lookup(str);
733   if (!mode) {
734     mode = new ProcessingMode(str, &initialProcessingMode_);
735     processingModeTable_.insert(mode);
736   }
737   return mode;
738 }
739 
740 StringC Interpreter::makeStringC(const char *s)
741 {
742   StringC tem;
743   if (s)
744     while (*s)
745       tem += (unsigned char)*s++;
746   return tem;
747 }
748 
749 void Interpreter::endPart()
750 {
751   currentPartFirstInitialValue_ = initialValueNames_.size();
752   partIndex_++;
753 }
754 
755 void Interpreter::dEndPart()
756 {
757   dPartIndex_++;
758 }
759 
760 void Interpreter::normalizeGeneralName(const NodePtr &nd, StringC &str)
761 {
762   NamedNodeListPtr nnl;
763   NodePtr root;
764   if (nd->getGroveRoot(root) == accessOK
765       && root->getElements(nnl) == accessOK)
766     str.resize(nnl->normalize(str.begin(), str.size()));
767 }
768 
769 ELObj *Interpreter::makeLengthSpec(const FOTBuilder::LengthSpec &ls)
770 {
771   if (ls.displaySizeFactor != 0.0) {
772     LengthSpec result(LengthSpec::displaySize, ls.displaySizeFactor);
773     result += double(ls.length);
774     return new (*this) LengthSpecObj(result);
775   }
776   else
777     return new (*this) LengthObj(ls.length);
778 }
779 
780 bool Interpreter::convertBooleanC(ELObj *obj, const Identifier *ident, const Location &loc,
781 				  bool &result)
782 {
783   obj = convertFromString(obj, convertAllowBoolean, loc);
784   if (obj == makeFalse()) {
785     result = 0;
786     return 1;
787   }
788   if (obj == makeTrue()) {
789     result = 1;
790     return 1;
791   }
792   invalidCharacteristicValue(ident, loc);
793   return 0;
794 }
795 
796 bool Interpreter::convertPublicIdC(ELObj *obj, const Identifier *ident,
797 				   const Location &loc,
798 				   FOTBuilder::PublicId &pubid)
799 {
800   if (obj == makeFalse()) {
801     pubid = 0;
802     return 1;
803   }
804   const Char *s;
805   size_t n;
806   if (obj->stringData(s, n)) {
807     if (n == 0)
808       pubid = 0;
809     else
810       pubid = storePublicId(s, n, loc);
811     return 1;
812   }
813   invalidCharacteristicValue(ident, loc);
814   return 0;
815 }
816 
817 const char *Interpreter::storePublicId(const Char *s, size_t n, const Location &loc)
818 {
819   String<char> buf;
820   for (; n > 0; s++, n--) {
821     if (*s >= 128) {
822       setNextLocation(loc);
823       message(InterpreterMessages::invalidPublicIdChar,
824 	      StringMessageArg(StringC(s, 1)));
825     }
826     else
827       buf += char(*s);
828   }
829   buf += '\0';
830   return publicIds_.store(buf);
831 }
832 
833 bool Interpreter::convertStringC(ELObj *obj, const Identifier *ident, const Location &loc,
834 				 StringC &result)
835 {
836   const Char *s;
837   size_t n;
838   if (obj->stringData(s, n)) {
839     result.assign(s, n);
840     return 1;
841   }
842   invalidCharacteristicValue(ident, loc);
843   return 0;
844 }
845 
846 bool Interpreter::convertLengthSpec(ELObj *obj,
847 				    FOTBuilder::LengthSpec &result)
848 {
849   int dim;
850   double d;
851   switch (obj->quantityValue(result.length, d, dim)) {
852   case ELObj::longQuantity:
853     if (dim == 1)
854       return 1;
855     break;
856   case ELObj::doubleQuantity:
857     if (dim == 1) {
858       // FIXME catch overflow
859       result.length = d < 0.0 ? long(d - .5) : long(d + .5);
860       return 1;
861     }
862     break;
863   default:
864     {
865       const LengthSpec *ls = obj->lengthSpec();
866       if (ls)
867 	return ls->convert(result);
868     }
869     break;
870   }
871   return 0;
872 }
873 
874 bool Interpreter::convertLengthC(ELObj *obj, const Identifier *ident,
875 				 const Location &loc,
876 				 FOTBuilder::Length &n)
877 {
878   obj = convertFromString(obj, convertAllowNumber, loc);
879   int dim;
880   double d;
881   switch (obj->quantityValue(n, d, dim)) {
882   case ELObj::longQuantity:
883     if (dim == 1)
884       return 1;
885     break;
886   case ELObj::doubleQuantity:
887     if (dim == 1) {
888       // FIXME catch overflow
889       n = long(d);
890       return 1;
891     }
892     break;
893   default:
894     break;
895   }
896   invalidCharacteristicValue(ident, loc);
897   return 0;
898 }
899 
900 bool Interpreter::convertLengthSpecC(ELObj *obj, const Identifier *ident,
901 				     const Location &loc,
902 				     FOTBuilder::LengthSpec &result)
903 {
904   obj = convertFromString(obj, convertAllowNumber, loc);
905   if (convertLengthSpec(obj, result))
906     return 1;
907   invalidCharacteristicValue(ident, loc);
908   return 0;
909 }
910 
911 bool Interpreter::convertOptLengthSpecC(ELObj *obj, const Identifier *ident,
912 					const Location &loc,
913 					FOTBuilder::OptLengthSpec &result)
914 {
915   obj = convertFromString(obj, convertAllowBoolean|convertAllowNumber, loc);
916   if (obj == makeFalse()) {
917     result.hasLength = 0;
918     return 1;
919   }
920   if (convertLengthSpecC(obj, ident, loc, result.length)) {
921     result.hasLength = 1;
922     return 1;
923   }
924   return 0;
925 }
926 
927 bool Interpreter::convertOptPositiveIntegerC(ELObj *obj, const Identifier *ident, const Location &loc,
928 					     long &result)
929 {
930   obj = convertFromString(obj, convertAllowNumber|convertAllowBoolean, loc);
931   if (obj == makeFalse()) {
932     result = 0;
933     return 1;
934   }
935   if (obj->exactIntegerValue(result) && result > 0)
936     return 1;
937   // FIXME allow inexact value
938   invalidCharacteristicValue(ident, loc);
939   return 0;
940 }
941 
942 bool Interpreter::convertIntegerC(ELObj *obj, const Identifier *ident, const Location &loc,
943 				  long &result)
944 {
945   obj = convertFromString(obj, convertAllowNumber, loc);
946   if (obj->exactIntegerValue(result))
947     return 1;
948   // FIXME allow inexact value
949   invalidCharacteristicValue(ident, loc);
950   return 0;
951 }
952 
953 
954 bool Interpreter::convertLetter2C(ELObj *obj, const Identifier *ident, const Location &loc,
955 				  FOTBuilder::Letter2 &code)
956 {
957   StringObj *strObj = obj->convertToString();
958   if (strObj) {
959     const StringC &str = *strObj;
960     if (str.size() == 2
961 	&& str[0] >= 'A' && str[0] <= 'Z'
962 	&& str[1] >= 'A' && str[1] <= 'Z') {
963       code = SP_LETTER2(str[0], str[1]);
964       return 1;
965     }
966     if (str.size() == 0) {
967       code = 0;
968       return 1;
969     }
970   }
971   else if (obj == makeFalse()) {
972     code = 0;
973     return 1;
974   }
975   invalidCharacteristicValue(ident, loc);
976   return 0;
977 }
978 
979 bool Interpreter::convertCharC(ELObj *obj, const Identifier *ident, const Location &loc,
980 			       Char &result)
981 {
982   if (obj->charValue(result))
983     return 1;
984   const Char *s;
985   size_t n;
986   if (obj->stringData(s, n) && n == 1) {
987     result = s[0];
988     return 1;
989   }
990   invalidCharacteristicValue(ident, loc);
991   return 0;
992 }
993 
994 bool Interpreter::convertColorC(ELObj *obj, const Identifier *ident, const Location &loc, ColorObj *&color)
995 {
996   color = obj->asColor();
997   if (color)
998     return 1;
999   invalidCharacteristicValue(ident, loc);
1000   return 0;
1001 }
1002 
1003 bool Interpreter::convertOptColorC(ELObj *obj, const Identifier *ident, const Location &loc, ColorObj *&color)
1004 {
1005   color = obj->asColor();
1006   if (color)
1007     return 1;
1008   if (obj == makeFalse())
1009     return 1;
1010   invalidCharacteristicValue(ident, loc);
1011   return 0;
1012 }
1013 
1014 bool Interpreter::convertRealC(ELObj *obj, const Identifier *ident, const Location &loc,
1015 			       double &result)
1016 {
1017   obj = convertFromString(obj, convertAllowNumber, loc);
1018   if (obj->realValue(result))
1019     return 1;
1020   invalidCharacteristicValue(ident, loc);
1021   return 0;
1022 }
1023 
1024 bool Interpreter::convertEnumC(ELObj *obj, const Identifier *ident, const Location &loc,
1025 			       FOTBuilder::Symbol &sym)
1026 {
1027   obj = convertFromString(obj, convertAllowSymbol|convertAllowBoolean, loc);
1028   if (obj == makeFalse()) {
1029     sym = FOTBuilder::symbolFalse;
1030     return 1;
1031   }
1032   SymbolObj *symObj = obj->asSymbol();
1033   if (symObj) {
1034     sym = symObj->cValue();
1035     if (sym != FOTBuilder::symbolFalse)
1036       return 1;
1037   }
1038   if (obj == makeTrue()) {
1039     sym = FOTBuilder::symbolTrue;
1040     return 1;
1041   }
1042   invalidCharacteristicValue(ident, loc);
1043   return 0;
1044 }
1045 
1046 bool Interpreter::convertEnumC(const FOTBuilder::Symbol *syms,  size_t nSyms,
1047 			       ELObj *obj, const Identifier *ident, const Location &loc,
1048 			       FOTBuilder::Symbol &result)
1049 {
1050   obj = convertFromString(obj, convertAllowSymbol|convertAllowBoolean, loc);
1051   SymbolObj *symObj = obj->asSymbol();
1052   FOTBuilder::Symbol val;
1053   if (symObj) {
1054     val = symObj->cValue();
1055     if (val == FOTBuilder::symbolFalse) {
1056       invalidCharacteristicValue(ident, loc);
1057       return 0;
1058     }
1059   }
1060   else if (obj == makeFalse())
1061     val = FOTBuilder::symbolFalse;
1062   else if (obj == makeTrue())
1063     val = FOTBuilder::symbolTrue;
1064   else {
1065     invalidCharacteristicValue(ident, loc);
1066     return 0;
1067   }
1068   for (size_t i = 0; i < nSyms; i++)
1069     if (val == syms[i]) {
1070       result = val;
1071       return 1;
1072     }
1073   invalidCharacteristicValue(ident, loc);
1074   return 0;
1075 }
1076 
1077 void Interpreter::invalidCharacteristicValue(const Identifier *ident, const Location &loc)
1078 {
1079   setNextLocation(loc);
1080   message(InterpreterMessages::invalidCharacteristicValue,
1081 	  StringMessageArg(ident->name()));
1082 }
1083 
1084 static
1085 bool equal(const Char *s1, const char *s2, size_t n)
1086 {
1087   while (n > 0) {
1088     if (*s1++ != (unsigned char)*s2++)
1089       return 0;
1090     --n;
1091   }
1092   return 1;
1093 }
1094 
1095 ELObj *Interpreter::convertFromString(ELObj *obj, unsigned hints, const Location &loc)
1096 {
1097   // FIXME fold to lower case
1098   const Char *s;
1099   size_t n;
1100   if (!dsssl2() || !obj->stringData(s, n))
1101     return obj;
1102   if (hints & convertAllowNumber) {
1103     ELObj *tem = convertNumber(StringC(s, n));
1104     if (tem)
1105       return tem->resolveQuantities(1, *this, loc);
1106   }
1107   if (hints & convertAllowSymbol) {
1108     StringC tem(s, n);
1109     SymbolObj *sym = symbolTable_.lookup(tem);
1110     if (sym && sym->cValue() != FOTBuilder::symbolFalse)
1111       return sym;
1112   }
1113   if (hints & convertAllowBoolean) {
1114     switch (n) {
1115     case 2:
1116       if (equal(s, "no", n))
1117 	return makeFalse();
1118       break;
1119     case 3:
1120       if (equal(s, "yes", n))
1121 	return makeTrue();
1122       break;
1123     case 4:
1124       if (equal(s, "true", n))
1125 	return makeTrue();
1126       break;
1127     case 5:
1128       if (equal(s, "false", n))
1129 	return makeFalse();
1130       break;
1131     }
1132   }
1133   return obj;
1134 }
1135 
1136 ELObj *Interpreter::convertNumber(const StringC &str, int radix)
1137 {
1138   {
1139     if (str.size() == 0)
1140       return 0;
1141     size_t i = 0;
1142     if (str[0] == '#') {
1143       if (str.size() < 2)
1144 	return 0;
1145       switch (str[1]) {
1146       case 'd':
1147 	radix = 10;
1148 	break;
1149       case 'x':
1150 	radix = 16;
1151 	break;
1152       case 'o':
1153 	radix = 8;
1154 	break;
1155       case 'b':
1156 	radix = 2;
1157 	break;
1158       default:
1159 	return 0;
1160       }
1161       i += 2;
1162     }
1163     if (i >= str.size())
1164       return 0;
1165     bool negative;
1166     if (str[i] == '-') {
1167       negative = 1;
1168       i++;
1169     }
1170     else {
1171       negative = 0;
1172       if (str[i] == '+')
1173       i++;
1174     }
1175     bool hadDecimalPoint = 0;
1176     bool hadDigit = 0;
1177     long n = 0;
1178     int exp = 0;
1179     for (; i < str.size(); i++) {
1180       Char c = str[i];
1181       int weight;
1182       switch (c) {
1183       case '0':
1184 	weight = 0;
1185 	break;
1186       case '1':
1187 	weight = 1;
1188 	break;
1189       case '2':
1190 	weight = 2;
1191 	break;
1192       case '3':
1193 	weight = 3;
1194 	break;
1195       case '4':
1196 	weight = 4;
1197 	break;
1198       case '5':
1199 	weight = 5;
1200 	break;
1201       case '6':
1202 	weight = 6;
1203 	break;
1204       case '7':
1205 	weight = 7;
1206 	break;
1207       case '8':
1208 	weight = 8;
1209 	break;
1210       case '9':
1211 	weight = 9;
1212 	break;
1213       case 'a':
1214 	weight = 10;
1215 	break;
1216       case 'b':
1217 	weight = 11;
1218 	break;
1219       case 'c':
1220 	weight = 12;
1221 	break;
1222       case 'd':
1223 	weight = 13;
1224 	break;
1225       case 'e':
1226 	weight = 14;
1227 	break;
1228       case 'f':
1229 	weight = 15;
1230 	break;
1231       default:
1232 	weight = -1;
1233 	break;
1234       }
1235       if (weight >= 0 && weight < radix) {
1236 	hadDigit = 1;
1237 	if (negative) {
1238 	  if (-(unsigned long)n > (-(unsigned long)LONG_MIN - weight)/radix) {
1239 	    if (radix != 10)
1240 	      return 0;
1241 	    return convertNumberFloat(str);
1242 	  }
1243 	  else
1244 	    n = n*radix - weight;
1245 	}
1246 	else {
1247 	  if (n > (LONG_MAX - weight)/radix) {
1248 	    if (radix != 10)
1249 	      return 0;
1250 	    return convertNumberFloat(str);
1251 	  }
1252 	  else
1253 	    n = n*radix + weight;
1254 	}
1255 	if (hadDecimalPoint)
1256 	  exp--;
1257       }
1258       else if (c == '.' && radix == 10) {
1259 	if (hadDecimalPoint)
1260 	  return 0;
1261 	hadDecimalPoint = 1;
1262       }
1263       else
1264 	break;
1265     }
1266     if (!hadDigit || (radix != 10 && i < str.size()))
1267       return 0;
1268     if (i + 1 < str.size() && str[i] == 'e'
1269         && lexCategory(str[i + 1]) != lexLetter) {
1270       hadDecimalPoint = 1;
1271       i++;
1272       int e;
1273       if (!scanSignDigits(str, i, e))
1274 	return 0;
1275       exp += e;
1276     }
1277     if (i < str.size()) {
1278       int unitExp;
1279       Unit *unit = scanUnit(str, i, unitExp);
1280       if (!unit)
1281 	return 0;
1282       if (unitExp == 1)
1283 	return new (*this) UnresolvedLengthObj(n, exp, unit);
1284       else
1285 	return convertNumberFloat(str);
1286     }
1287     if (hadDecimalPoint)
1288       return convertNumberFloat(str);
1289     return makeInteger(n);
1290   }
1291 }
1292 
1293 bool Interpreter::scanSignDigits(const StringC &str, size_t &i, int &n)
1294 {
1295   bool negative = 0;
1296   if (i < str.size()) {
1297     if (str[i] == '-') {
1298       i++;
1299       negative = 1;
1300     } else if (str[i] == '+')
1301       i++;
1302   }
1303   size_t j = i;
1304   n = 0;
1305   while (i < str.size()
1306 	 && ('0' <= str[i] && str[i] <= '9')) {
1307     if (negative)
1308       n = n*10 - (str[i] - '0');
1309     else
1310       n = n*10 + (str[i] - '0');
1311     i++;
1312   }
1313   if (i == j)
1314     return 0;
1315   return 1;
1316 }
1317 
1318 ELObj *Interpreter::convertNumberFloat(const StringC &str)
1319 {
1320   String<char> buf;
1321   // omit an optional radix prefix
1322   size_t i0 = 0;
1323   if (str.size() > 1 && str[0] == '#' && str[1] == 'd')
1324     i0 = 2;
1325   for (size_t i = i0; i < str.size(); i++) {
1326     if (str[i] > CHAR_MAX || str[i] == '\0')
1327       return 0;
1328     // 'E' is a valid exponent marker for C but not us
1329     if (str[i] == 'E')
1330       break;
1331     buf += char(str[i]);
1332   }
1333   buf += '\0';
1334   const char *endPtr;
1335   double val = strtod((char *)buf.data(), (char **)&endPtr);
1336   if (endPtr - buf.data() == str.size() - i0)
1337     return new (*this) RealObj(val);
1338   if (endPtr == buf.data())
1339     return 0;
1340   int unitExp;
1341   Unit *unit = scanUnit(str, endPtr - buf.data() + i0, unitExp);
1342   if (!unit)
1343     return 0;
1344   return new (*this) UnresolvedQuantityObj(val, unit, unitExp);
1345 }
1346 
1347 // Return 0 for error.
1348 
1349 Unit *Interpreter::scanUnit(const StringC &str, size_t i, int &unitExp)
1350 {
1351   StringC unitName;
1352   while (i < str.size()) {
1353     if (str[i] == '-' || str[i] == '+' || ('0' <= str[i] && str[i] <= '9'))
1354       break;
1355     unitName += str[i++];
1356   }
1357   if (i >= str.size())
1358     unitExp = 1;
1359   else {
1360     unitExp = 0;
1361     bool neg = 0;
1362     if (str[i] == '-' || str[i] == '+') {
1363       if (str[i] == '-')
1364       neg = 1;
1365       i++;
1366       if (i >= str.size())
1367 	return 0;
1368     }
1369     while (i < str.size()) {
1370       if (str[i] < '0' || str[i] > '9')
1371 	return 0;
1372       unitExp *= 10;
1373       if (neg)
1374 	unitExp -= (str[i] - '0');
1375       else
1376 	unitExp += (str[i] - '0');
1377       i++;
1378     }
1379   }
1380   return lookupUnit(unitName);
1381 }
1382 
1383 void Interpreter::setNodeLocation(const NodePtr &nd)
1384 {
1385   const LocNode *lnp;
1386   Location nodeLoc;
1387   if ((lnp = LocNode::convert(nd)) != 0
1388       && lnp->getLocation(nodeLoc) == accessOK)
1389     setNextLocation(nodeLoc);
1390 }
1391 
1392 bool Interpreter::convertToPattern(ELObj *obj, const Location &loc, Pattern &pattern)
1393 {
1394   IList<Pattern::Element> list;
1395   if (!convertToPattern(obj, loc, 0, list))
1396     return 0;
1397   Pattern tem(list);
1398   tem.swap(pattern);
1399   return 1;
1400 }
1401 
1402 bool Interpreter::convertToPattern(ELObj *obj, const Location &loc,
1403 				   bool isChild,
1404 				   IList<Pattern::Element> &list)
1405 {
1406   StringObj *str = obj->convertToString();
1407   if (str) {
1408     const Char *s;
1409     size_t n;
1410     str->stringData(s, n);
1411     if (!n) {
1412       setNextLocation(loc);
1413       message(InterpreterMessages::patternEmptyGi);
1414       return 0;
1415     }
1416     list.insert(new Pattern::Element(StringC(s, n)));
1417     return 1;
1418   }
1419   if (obj == makeTrue()) {
1420     list.insert(new Pattern::Element(StringC()));
1421     return 1;
1422   }
1423   Pattern::Element *curElement = 0;
1424   while (!obj->isNil()) {
1425     PairObj *pair = obj->asPair();
1426     if (!pair) {
1427       setNextLocation(loc);
1428       message(InterpreterMessages::patternNotList);
1429       return 0;
1430     }
1431     ELObj *head = pair->car();
1432     obj = pair->cdr();
1433     if (head == makeTrue() && dsssl2()) {
1434       list.insert(curElement = new Pattern::Element(StringC()));
1435       continue;
1436     }
1437     str = head->convertToString();
1438     if (str) {
1439       const Char *s;
1440       size_t n;
1441       str->stringData(s, n);
1442       if (!n) {
1443 	setNextLocation(loc);
1444 	message(InterpreterMessages::patternEmptyGi);
1445 	return 0;
1446       }
1447       list.insert(curElement = new Pattern::Element(StringC(s, n)));
1448       continue;
1449     }
1450     if (!curElement) {
1451       setNextLocation(loc);
1452       message(InterpreterMessages::patternBadGi,
1453 	      ELObjMessageArg(head, *this));
1454       return 0;
1455     }
1456     if (head->isNil())
1457       continue; // empty attribute list
1458     if (head->asPair()) {
1459       if (!patternAddAttributeQualifiers(head, loc, *curElement)) {
1460 	setNextLocation(loc);
1461 	message(InterpreterMessages::patternBadAttributeQualifier);
1462 	return 0;
1463       }
1464       continue;
1465     }
1466     KeywordObj *key = dsssl2() ? head->asKeyword() : 0;
1467     if (!key) {
1468       setNextLocation(loc);
1469       message(InterpreterMessages::patternBadMember,
1470 	      ELObjMessageArg(head, *this));
1471       return 0;
1472     }
1473     pair = obj->asPair();
1474     if (!pair) {
1475       setNextLocation(loc);
1476       message(obj->isNil()
1477 	      ? InterpreterMessages::patternMissingQualifierValue
1478 	      : InterpreterMessages::patternNotList);
1479       return 0;
1480     }
1481     ELObj *value = pair->car();
1482     obj = pair->cdr();
1483     Identifier::SyntacticKey k;
1484     if (!key->identifier()->syntacticKey(k)) {
1485       setNextLocation(loc);
1486       message(InterpreterMessages::patternUnknownQualifier,
1487 	      StringMessageArg(key->identifier()->name()));
1488       return 0;
1489     }
1490     switch (k) {
1491     case Identifier::keyAttributes:
1492       if (!patternAddAttributeQualifiers(value, loc, *curElement)) {
1493 	setNextLocation(loc);
1494 	message(InterpreterMessages::patternBadAttributeQualifier);
1495 	return 0;
1496       }
1497       break;
1498     case Identifier::keyChildren:
1499       {
1500 	IList<Pattern::Element> children;
1501 	if (!convertToPattern(value, loc, 1, children))
1502 	  return 0;
1503 	if (!children.empty())
1504 	  curElement->addQualifier(new Pattern::ChildrenQualifier(children));
1505       }
1506       break;
1507     case Identifier::keyRepeat:
1508       {
1509 	if (isChild) {
1510 	  setNextLocation(loc);
1511 	  message(InterpreterMessages::patternChildRepeat);
1512 	  return 0;
1513 	}
1514         SymbolObj *sym = value->asSymbol();
1515 	if (sym) {
1516 	  const StringC &str = *sym->name();
1517 	  if (str.size() == 1) {
1518 	    switch (str[0]) {
1519 	    case '*':
1520 	      curElement->setRepeat(0, Pattern::Repeat(-1));
1521 	      value = 0;
1522 	      break;
1523 	    case '?':
1524 	      curElement->setRepeat(0, 1);
1525 	      value = 0;
1526 	      break;
1527 	    case '+':
1528 	      curElement->setRepeat(1, Pattern::Repeat(-1));
1529 	      value = 0;
1530 	      break;
1531 	    default:
1532 	      break;
1533 	    }
1534 	  }
1535 	}
1536 	if (value) {
1537 	  setNextLocation(loc);
1538 	  message(InterpreterMessages::patternBadQualifierValue,
1539 	          ELObjMessageArg(value, *this),
1540 		  StringMessageArg(key->identifier()->name()));
1541 	  return 0;
1542 	}
1543       }
1544       break;
1545     case Identifier::keyPosition:
1546       {
1547         SymbolObj *sym = value->asSymbol();
1548 	if (sym) {
1549 	  Pattern::Qualifier *qual = 0;
1550 	  const StringC &str = *sym->name();
1551 	  if (str == "first-of-type")
1552 	    qual = new Pattern::FirstOfTypeQualifier;
1553 	  else if (str == "last-of-type")
1554 	    qual = new Pattern::LastOfTypeQualifier;
1555 	  else if (str == "first-of-any")
1556 	    qual = new Pattern::FirstOfAnyQualifier;
1557 	  else if (str == "last-of-any")
1558 	    qual = new Pattern::LastOfAnyQualifier;
1559 	  if (qual) {
1560 	    curElement->addQualifier(qual);
1561 	    break;
1562 	  }
1563 	}
1564         setNextLocation(loc);
1565 	message(InterpreterMessages::patternBadQualifierValue,
1566 	        ELObjMessageArg(value, *this),
1567 		StringMessageArg(key->identifier()->name()));
1568 	return 0;
1569       }
1570     case Identifier::keyOnly:
1571       {
1572         SymbolObj *sym = value->asSymbol();
1573 	if (sym) {
1574 	  Pattern::Qualifier *qual = 0;
1575 	  const StringC &str = *sym->name();
1576 	  if (str == "of-type")
1577 	    qual = new Pattern::OnlyOfTypeQualifier;
1578 	  else if (str == "of-any")
1579 	    qual = new Pattern::OnlyOfAnyQualifier;
1580 	  if (qual) {
1581 	    curElement->addQualifier(qual);
1582 	    break;
1583 	  }
1584 	}
1585 	setNextLocation(loc);
1586     	message(InterpreterMessages::patternBadQualifierValue,
1587 	        ELObjMessageArg(value, *this),
1588 		StringMessageArg(key->identifier()->name()));
1589 	return 0;
1590       }
1591       break;
1592     case Identifier::keyId:
1593       {
1594 	StringObj *str = value->convertToString();
1595 	if (!str) {
1596 	  setNextLocation(loc);
1597 	  message(InterpreterMessages::patternBadQualifierValue,
1598 	          ELObjMessageArg(value, *this),
1599 		  StringMessageArg(key->identifier()->name()));
1600 	  return 0;
1601 	}
1602 	const Char *s;
1603 	size_t n;
1604 	str->stringData(s, n);
1605 	curElement->addQualifier(new Pattern::IdQualifier(StringC(s, n)));
1606       }
1607       break;
1608     case Identifier::keyClass:
1609       {
1610 	StringObj *str = value->convertToString();
1611 	if (!str) {
1612 	  setNextLocation(loc);
1613 	  message(InterpreterMessages::patternBadQualifierValue,
1614 	          ELObjMessageArg(value, *this),
1615 		  StringMessageArg(key->identifier()->name()));
1616 	  return 0;
1617 	}
1618 	const Char *s;
1619 	size_t n;
1620 	str->stringData(s, n);
1621 	curElement->addQualifier(new Pattern::ClassQualifier(StringC(s, n)));
1622       }
1623       break;
1624     case Identifier::keyImportance:
1625       {
1626 	long n;
1627 	if (!value->exactIntegerValue(n)) {
1628 	  setNextLocation(loc);
1629 	  message(InterpreterMessages::patternBadQualifierValue,
1630 	          ELObjMessageArg(value, *this),
1631 		  StringMessageArg(key->identifier()->name()));
1632 	  return 0;
1633 	}
1634 	curElement->addQualifier(new Pattern::ImportanceQualifier(n));
1635       }
1636       break;
1637     case Identifier::keyPriority:
1638       {
1639 	long n;
1640 	if (!value->exactIntegerValue(n)) {
1641 	  setNextLocation(loc);
1642 	  message(InterpreterMessages::patternBadQualifierValue,
1643 	          ELObjMessageArg(value, *this),
1644 		  StringMessageArg(key->identifier()->name()));
1645 	  return 0;
1646 	}
1647 	curElement->addQualifier(new Pattern::PriorityQualifier(n));
1648       }
1649       break;
1650     default:
1651       setNextLocation(loc);
1652       message(InterpreterMessages::patternUnknownQualifier,
1653 	      StringMessageArg(key->identifier()->name()));
1654       return 0;
1655     }
1656   }
1657   return 1;
1658 }
1659 
1660 bool Interpreter::patternAddAttributeQualifiers(ELObj *obj,
1661 						const Location &loc,
1662 						Pattern::Element &elem)
1663 {
1664   while (!obj->isNil()) {
1665     PairObj *pair = obj->asPair();
1666     if (!pair)
1667       return 0;
1668     StringObj *tem = pair->car()->convertToString();
1669     if (!tem)
1670       return 0;
1671     const Char *s;
1672     size_t n;
1673     tem->stringData(s, n);
1674     if (n == 0)
1675       return 0;
1676     StringC name(s, n);
1677     obj = pair->cdr();
1678     pair = obj->asPair();
1679     if (!pair)
1680       return 0;
1681     obj = pair->cdr();
1682     if (pair->car() == makeFalse() && dsssl2())
1683       elem.addQualifier(new Pattern::AttributeMissingValueQualifier(name));
1684     else if (pair->car() == makeTrue() && dsssl2())
1685       elem.addQualifier(new Pattern::AttributeHasValueQualifier(name));
1686     else {
1687       tem = pair->car()->convertToString();
1688       if (!tem)
1689 	return 0;
1690       tem->stringData(s, n);
1691       elem.addQualifier(new Pattern::AttributeQualifier(name, StringC(s, n)));
1692     }
1693   }
1694   return 1;
1695 }
1696 
1697 void Interpreter::dispatchMessage(Message &msg)
1698 {
1699   messenger_->dispatchMessage(msg);
1700 }
1701 
1702 void Interpreter::dispatchMessage(const Message &msg)
1703 {
1704   messenger_->dispatchMessage(msg);
1705 }
1706 
1707 Interpreter::StringSet::StringSet()
1708 {
1709 }
1710 
1711 const char *Interpreter::StringSet::store(String<char> &str)
1712 {
1713   str += '\0';
1714   const String<char> *p = table_.lookup(str);
1715   if (!p) {
1716     String<char> *tem = new String<char>;
1717     str.swap(*tem);
1718     table_.insert(tem);
1719     p = tem;
1720   }
1721   return p->data();
1722 }
1723 
1724 unsigned long Interpreter::StringSet::hash(const String<char> &str)
1725 {
1726   const char *p = str.data();
1727   unsigned long h = 0;
1728   for (size_t n = str.size(); n > 0; n--)
1729     h = (h << 5) + h + (unsigned char)*p++;	// from Chris Torek
1730   return h;
1731 }
1732 
1733 bool Identifier::preferBuiltin_ = 0;
1734 
1735 Identifier::Identifier(const StringC &name)
1736 : Named(name), value_(0), syntacticKey_(notKey), beingComputed_(0),
1737   flowObj_(0), builtin_(0), defPart_(0), charNIC_(0)
1738 {
1739 }
1740 
1741 void Identifier::maybeSaveBuiltin()
1742 {
1743   if (defPart_ == unsigned(-1) && !builtin_) {
1744     builtin_ = new Identifier(name());
1745     if (value_)
1746       builtin_->setValue(value_, defPart_);
1747     else
1748       builtin_->setDefinition(def_, defPart_, defLoc_);
1749   }
1750 }
1751 
1752 void Identifier::setDefinition(Owner<Expression> &expr,
1753 			       unsigned part,
1754 			       const Location &loc)
1755 {
1756   maybeSaveBuiltin();
1757   def_.swap(expr);
1758   defPart_ = part;
1759   defLoc_ = loc;
1760   value_ = 0;
1761 }
1762 
1763 void Identifier::setValue(ELObj *value, unsigned partIndex)
1764 {
1765   maybeSaveBuiltin();
1766   value_ = value;
1767   // Built in functions have lowest priority.
1768   defPart_ = partIndex;
1769 }
1770 
1771 bool Identifier::defined(unsigned &part, Location &loc) const
1772 {
1773   if (!def_ && !value_)
1774     return 0;
1775   part = defPart_;
1776   loc = defLoc_;
1777   return 1;
1778 }
1779 
1780 ELObj *Identifier::computeValue(bool force, Interpreter &interp) const
1781 {
1782   if (builtin_ && preferBuiltin_)
1783     return builtin_->computeValue(force, interp);
1784   if (value_)
1785     return value_;
1786   bool preferred = 0;
1787   if (defPart_ == unsigned(-1) && !preferBuiltin_) {
1788     preferBuiltin_ = 1;
1789     preferred = 1;
1790   }
1791   ASSERT(def_);
1792   if (beingComputed_) {
1793     if (force) {
1794       interp.setNextLocation(defLoc_);
1795       interp.message(InterpreterMessages::identifierLoop,
1796 	             StringMessageArg(name()));
1797       ((Identifier *)this)->value_ = interp.makeError();
1798     }
1799   }
1800   else {
1801     ((Identifier *)this)->beingComputed_ = 1;
1802     if (insn_.isNull())
1803       ((Identifier *)this)->insn_
1804         = Expression::optimizeCompile(((Identifier *)this)->def_, interp,
1805 	                              Environment(), 0, InsnPtr());
1806     if (force || def_->canEval(0)) {
1807       VM vm(interp);
1808       ELObj *v = vm.eval(insn_.pointer());
1809       interp.makePermanent(v);
1810       ((Identifier *)this)->value_ = v;
1811     }
1812     ((Identifier *)this)->beingComputed_ = 0;
1813   }
1814   if (preferred)
1815     preferBuiltin_ = 0;
1816   return value_;
1817 }
1818 
1819 ELObj *Identifier::computeBuiltinValue(bool force, Interpreter &interp) const
1820 {
1821   preferBuiltin_ = 1;
1822   ELObj *res = computeValue(force, interp);
1823   preferBuiltin_ = 0;
1824   return res;
1825 }
1826 
1827 Unit::Unit(const StringC &name)
1828 : Named(name), computed_(notComputed)
1829 {
1830 }
1831 
1832 bool Unit::defined(unsigned &part, Location &loc) const
1833 {
1834   if (!def_ && computed_ == notComputed)
1835     return 0;
1836   part = defPart_;
1837   loc = defLoc_;
1838   return 1;
1839 }
1840 
1841 void Unit::setDefinition(Owner<Expression> &expr,
1842 			 unsigned part,
1843 			 const Location &loc)
1844 {
1845   def_.swap(expr);
1846   defPart_ = part;
1847   defLoc_ = loc;
1848   computed_ = notComputed;
1849 }
1850 
1851 void Unit::setValue(long n)
1852 {
1853   computed_ = computedExact;
1854   exact_ = n;
1855   dim_ = 1;
1856   defPart_ = unsigned(-1);
1857 }
1858 
1859 void Unit::setValue(double n)
1860 {
1861   computed_ = computedInexact;
1862   inexact_ = n;
1863   dim_ = 1;
1864   defPart_ = unsigned(-1);
1865 }
1866 
1867 void Unit::tryCompute(bool force, Interpreter &interp)
1868 {
1869   if (computed_ == notComputed) {
1870     computed_ = beingComputed;
1871     if (insn_.isNull())
1872       insn_ = Expression::optimizeCompile(def_, interp, Environment(), 0, InsnPtr());
1873     if (force || def_->canEval(0)) {
1874       VM vm(interp);
1875       ELObj *v = vm.eval(insn_.pointer());
1876       switch (v->quantityValue(exact_, inexact_, dim_)) {
1877       case ELObj::noQuantity:
1878 	if (!interp.isError(v)) {
1879 	  interp.setNextLocation(defLoc_);
1880 	  interp.message(InterpreterMessages::badUnitDefinition,
1881 			 StringMessageArg(name()));
1882 	}
1883 	computed_ = computedError;
1884 	break;
1885       case ELObj::longQuantity:
1886 	computed_ = computedExact;
1887 	break;
1888       case ELObj::doubleQuantity:
1889 	computed_ = computedInexact;
1890 	break;
1891       default:
1892 	CANNOT_HAPPEN();
1893       }
1894     }
1895     if (computed_ == beingComputed)
1896       computed_ = notComputed;
1897   }
1898   else if (computed_ == beingComputed) {
1899     interp.setNextLocation(defLoc_);
1900     interp.message(InterpreterMessages::unitLoop,
1901 		   StringMessageArg(name()));
1902     computed_ = computedError;
1903   }
1904 }
1905 
1906 // multiply by 10^valExp
1907 // quantity has exponent of 1
1908 
1909 ELObj *Unit::resolveQuantity(bool force, Interpreter &interp,
1910 			     long val, int valExp)
1911 {
1912   tryCompute(force, interp);
1913   long result;
1914   if (computed_ == computedExact && scale(val, valExp, exact_, result))
1915     return new (interp) LengthObj(result);
1916   double x = val;
1917   while (valExp > 0) {
1918     x *= 10.0;
1919     valExp--;
1920   }
1921   while (valExp < 0) {
1922     x /= 10.0;
1923     valExp++;
1924   }
1925   return resolveQuantity(force, interp, x, 1);
1926 }
1927 
1928 // val * 10^valExp * factor
1929 // return 0 if it can't be done without overflow
1930 
1931 bool Unit::scale(long val, int valExp, long factor, long &result)
1932 {
1933   if (factor <= 0)
1934     return 0; // feeble
1935   while (valExp > 0) {
1936     if (factor > LONG_MAX/10)
1937       return 0;
1938     valExp--;
1939     factor *= 10;
1940   }
1941   if (val >= 0) {
1942     if (val > LONG_MAX/factor)
1943       return 0;
1944   }
1945   else {
1946     if (-(unsigned long)val > -(unsigned long)LONG_MIN/factor)
1947       return 0;
1948   }
1949   result = val*factor;
1950   while (valExp < 0) {
1951     result /= 10;
1952     valExp++;
1953   }
1954   return 1;
1955 }
1956 
1957 ELObj *Unit::resolveQuantity(bool force, Interpreter &interp,
1958 			     double val, int unitExp)
1959 {
1960   tryCompute(force, interp);
1961   double factor;
1962   switch (computed_) {
1963   case computedExact:
1964     factor = exact_;
1965     break;
1966   case computedInexact:
1967     factor = inexact_;
1968     break;
1969   case computedError:
1970     return interp.makeError();
1971   default:
1972     return 0;
1973   }
1974   int resultDim = 0;
1975   double resultVal = val;
1976   while (unitExp > 0) {
1977     resultDim += dim_;
1978     resultVal *= factor;
1979     unitExp--;
1980   }
1981   while (unitExp < 0) {
1982     resultDim -= dim_;
1983     resultVal /= factor;
1984     unitExp++;
1985   }
1986   if (resultDim == 0)
1987     return new (interp) RealObj(resultVal);
1988   return new (interp) QuantityObj(resultVal, resultDim);
1989 }
1990 
1991 void ELObjDynamicRoot::trace(Collector &c) const
1992 {
1993   c.trace(obj_);
1994 }
1995 
1996 bool operator==(const StringC &s, const char *p)
1997 {
1998   for (size_t i = 0; i < s.size(); i++)
1999     if (p[i] == '\0' || (unsigned char)p[i] != s[i])
2000       return 0;
2001   return p[s.size()] == '\0';
2002 }
2003 
2004 void Interpreter::installBuiltins()
2005 {
2006   partIndex_ = unsigned(-1);
2007   StringC sysid(makeStringC(DEFAULT_SCHEME_BUILTINS));
2008   StringC src;
2009   groveManager_->mapSysid(sysid);
2010   if (groveManager_->readEntity(sysid, src)) {
2011     Owner<InputSource> in(new InternalInputSource(src,
2012                               InputSourceOrigin::make()));
2013     SchemeParser scm(*this, in);
2014     scm.parse();
2015   }
2016   endPart();
2017   partIndex_ = 0;
2018 }
2019 
2020 void Interpreter::setDefaultLanguage(Owner<Expression> &expr,
2021 				     unsigned part,
2022 				     const Location &loc)
2023 {
2024   defaultLanguageDef_.swap(expr);
2025   defaultLanguageDefPart_ = part;
2026   defaultLanguageDefLoc_ = loc;
2027 }
2028 
2029 ELObj *Interpreter::defaultLanguage() const
2030 {
2031   return defaultLanguage_;
2032 }
2033 
2034 bool Interpreter::defaultLanguageSet(unsigned &part,Location &loc) const
2035 {
2036   if(defaultLanguageDef_) {
2037     part = defaultLanguageDefPart_;
2038     loc = defaultLanguageDefLoc_;
2039     return true;
2040   }
2041   return false;
2042 }
2043 
2044 void Interpreter::compileDefaultLanguage()
2045 {
2046   if(defaultLanguageDef_) {
2047     InsnPtr insn = Expression::optimizeCompile(defaultLanguageDef_, *this,
2048 					       Environment(), 0, InsnPtr());
2049     VM vm(*this);
2050     ELObj *obj = vm.eval(insn.pointer());
2051     if(!obj->asLanguage()) {
2052       if(!isError(obj)) {
2053 	setNextLocation(defaultLanguageDefLoc_);
2054 	message(InterpreterMessages::defLangDeclRequiresLanguage,
2055 		ELObjMessageArg(obj, *this));
2056       }
2057       return;
2058     }
2059     makePermanent(obj);
2060     defaultLanguage_ = obj;
2061   }
2062 }
2063 
2064 void Interpreter::installCharProperties()
2065 {
2066   //FIXME convert this to tables
2067   // initialize charProperties_;
2068   // if a character doesn't have a value for a property,
2069   // the CharMap contains 0.
2070 
2071   CharProp cp;
2072 
2073   cp.def = ELObjPart(makeFalse(), unsigned(-1));
2074   cp.loc = Location();
2075   cp.map = new CharMap<ELObjPart>(ELObjPart(0, 0));
2076   if (!strictMode_)
2077     for (int i = 0; i < 10; i++) {
2078       ELObjPart num(makeInteger(i), unsigned(-1));
2079       makePermanent(num.obj);
2080       cp.map->setChar(i+'0', num);
2081     }
2082   charProperties_.insert(makeStringC("numeric-equiv"), cp);
2083 
2084   cp.def = ELObjPart(makeFalse(), unsigned(-1));
2085   cp.map = new CharMap<ELObjPart>(ELObjPart(0, 0));
2086   if (!strictMode_) {
2087     static struct {
2088       Char c;
2089       unsigned num;
2090     } chars[] = {
2091 #define SPACE
2092 #include "charProps.h"
2093 #undef SPACE
2094     };
2095 
2096     for (size_t i = 0; i < SIZEOF(chars); i++)
2097       cp.map->setRange(chars[i].c, chars[i].c+chars[i].num-1,
2098 		       ELObjPart(makeTrue(), unsigned(-1)));
2099   }
2100   charProperties_.insert(makeStringC("space?"), cp);
2101 
2102   cp.def = ELObjPart(makeFalse(), unsigned(-1));
2103   cp.map = new CharMap<ELObjPart>(ELObjPart(0, 0));
2104   if (!strictMode_) {
2105     static struct {
2106       Char c;
2107       unsigned num;
2108     } chars[] = {
2109 #define RECORD_END
2110 #include "charProps.h"
2111 #undef RECORD_END
2112     };
2113 
2114     for (size_t i = 0; i < SIZEOF(chars); i++)
2115       cp.map->setRange(chars[i].c, chars[i].c+chars[i].num-1,
2116 		       ELObjPart(makeTrue(), unsigned(-1)));
2117   }
2118   charProperties_.insert(makeStringC("record-end?"), cp);
2119 
2120   cp.def = ELObjPart(makeFalse(), unsigned(-1));
2121   cp.map = new CharMap<ELObjPart>(ELObjPart(0, 0));
2122   if (!strictMode_) {
2123     static struct {
2124       Char c;
2125       unsigned num;
2126     } chars[] = {
2127 #define BLANK
2128 #include "charProps.h"
2129 #undef BLANK
2130     };
2131 
2132     for (size_t i = 0; i < SIZEOF(chars); i++)
2133       cp.map->setRange(chars[i].c, chars[i].c+chars[i].num-1,
2134 		       ELObjPart(makeTrue(), unsigned(-1)));
2135   }
2136   charProperties_.insert(makeStringC("blank?"), cp);
2137 
2138   cp.def = ELObjPart(makeFalse(), unsigned(-1));
2139   cp.map = new CharMap<ELObjPart>(ELObjPart(0, 0));
2140   if (!strictMode_) {
2141     static struct {
2142       Char c;
2143       unsigned num;
2144     } chars[] = {
2145 #define INPUT_TAB
2146 #include "charProps.h"
2147 #undef INPUT_TAB
2148     };
2149 
2150     for (size_t i = 0; i < SIZEOF(chars); i++)
2151       cp.map->setRange(chars[i].c, chars[i].c+chars[i].num-1,
2152 		       ELObjPart(makeTrue(), unsigned(-1)));
2153   }
2154   charProperties_.insert(makeStringC("input-tab?"), cp);
2155 
2156   cp.def = ELObjPart(makeFalse(), unsigned(-1));
2157   cp.map = new CharMap<ELObjPart>(ELObjPart(0, 0));
2158   if (!strictMode_) {
2159     static struct {
2160       Char c;
2161       unsigned num;
2162     } chars[] = {
2163 #define INPUT_WHITESPACE
2164 #include "charProps.h"
2165 #undef INPUT_WHITESPACE
2166     };
2167 
2168     for (size_t i = 0; i < SIZEOF(chars); i++)
2169       cp.map->setRange(chars[i].c, chars[i].c+chars[i].num-1,
2170 		       ELObjPart(makeTrue(), unsigned(-1)));
2171   }
2172   charProperties_.insert(makeStringC("input-whitespace?"), cp);
2173 
2174   cp.def = ELObjPart(makeFalse(), unsigned(-1));
2175   cp.map = new CharMap<ELObjPart>(ELObjPart(0, 0));
2176   if (!strictMode_) {
2177     static struct {
2178       Char c;
2179       unsigned num;
2180     } chars[] = {
2181 #define PUNCT
2182 #include "charProps.h"
2183 #undef PUNCT
2184     };
2185 
2186     for (size_t i = 0; i < SIZEOF(chars); i++)
2187       cp.map->setRange(chars[i].c, chars[i].c+chars[i].num-1,
2188 		       ELObjPart(makeTrue(), unsigned(-1)));
2189   }
2190   charProperties_.insert(makeStringC("punct?"), cp);
2191 
2192   cp.def = ELObjPart(makeFalse(), unsigned(-1));
2193   cp.map = new CharMap<ELObjPart>(ELObjPart(0, 0));
2194   if (!strictMode_) {
2195     static struct {
2196       Char c1, c2;
2197       char *script;
2198     } chars[] = {
2199 #define SCRIPT
2200 #include "charProps.h"
2201 #undef SCRIPT
2202     };
2203 
2204     StringC prefix = makeStringC("ISO/IEC 10179::1996//Script::");
2205     for (size_t i = 0; i < SIZEOF(chars); i++) {
2206       StringC tem(prefix);
2207       tem += makeStringC(chars[i].script);
2208       StringObj *obj = new (*this) StringObj(tem);
2209       makePermanent(obj);
2210       cp.map->setRange(chars[i].c1, chars[i].c2,
2211 		       ELObjPart(obj, unsigned(-1)));
2212     }
2213   }
2214   charProperties_.insert(makeStringC("script"), cp);
2215 
2216   cp.def = ELObjPart(makeFalse(), unsigned(-1));
2217   cp.map = new CharMap<ELObjPart>(ELObjPart(0, 0));
2218   charProperties_.insert(makeStringC("glyph-id"), cp);
2219 
2220   cp.def = ELObjPart(makeFalse(), unsigned(-1));
2221   cp.map = new CharMap<ELObjPart>(ELObjPart(0, 0));
2222   charProperties_.insert(makeStringC("drop-after-line-break?"), cp);
2223 
2224   cp.def = ELObjPart(makeFalse(), unsigned(-1));
2225   cp.map = new CharMap<ELObjPart>(ELObjPart(0, 0));
2226   charProperties_.insert(makeStringC("drop-unless-before-line-break?"), cp);
2227 
2228   cp.def = ELObjPart(makeInteger(0), unsigned(-1));
2229   makePermanent(cp.def.obj);
2230   cp.map = new CharMap<ELObjPart>(ELObjPart(0, 0));
2231   CharProp cp2;
2232   cp2.def = ELObjPart(cp.def.obj, unsigned(-1));
2233   cp2.loc = Location();
2234   cp2.map = new CharMap<ELObjPart>(ELObjPart(0, 0));
2235   if(!strictMode_) {
2236     static struct {
2237       Char c;
2238       unsigned short num;
2239       unsigned short bbp;
2240       unsigned short bap;
2241     } chars[] ={
2242 #define BREAK_PRIORITIES
2243 #include "charProps.h"
2244 #undef BREAK_PRIORITIES
2245     };
2246     for(size_t i = 0; i<SIZEOF(chars); ++i) {
2247       ELObj *obj = makeInteger(chars[i].bbp);
2248       makePermanent(obj);
2249       cp.map->setRange(chars[i].c, chars[i].c + chars[i].num-1,
2250 		       ELObjPart(obj, unsigned(-1)));
2251       if(chars[i].bap!=chars[i].bbp) {
2252 	obj = makeInteger(chars[i].bap);
2253 	makePermanent(obj);
2254       }
2255       cp2.map->setRange(chars[i].c, chars[i].c+chars[i].num-1,
2256 			ELObjPart(obj, unsigned(-1)));
2257     }
2258   }
2259 
2260   charProperties_.insert(makeStringC("break-before-priority"), cp);
2261   charProperties_.insert(makeStringC("break-after-priority"), cp2);
2262 
2263   cp.def = ELObjPart(makeSymbol(makeStringC("ordinary")), unsigned(-1));
2264   makePermanent(cp.def.obj);
2265   cp.map = new CharMap<ELObjPart>(ELObjPart(0, 0));
2266   charProperties_.insert(makeStringC("math-class"), cp);
2267 
2268   cp.def = ELObjPart(makeFalse(), unsigned(-1));
2269   cp.map = new CharMap<ELObjPart>(ELObjPart(0, 0));
2270   charProperties_.insert(makeStringC("math-font-posture"), cp);
2271 }
2272 
2273 // return 1 if the character has the property, return 0 if no such property
2274 // or the character doesn't have the property
2275 // set ret to the value or the default value
2276 ELObj *Interpreter::charProperty(const StringC &prop, Char c, const Location &loc, ELObj *def)
2277 {
2278   const CharProp *cp = charProperties_.lookup(prop);
2279   if (!cp) {
2280     setNextLocation(loc);
2281     message(InterpreterMessages::unknownCharProperty,
2282             StringMessageArg(prop));
2283     return makeError();
2284   }
2285 
2286   if ((*cp->map)[c].obj)
2287     return (*cp->map)[c].obj;
2288   else if (def)
2289     return def;
2290   else
2291     return cp->def.obj;
2292 }
2293 
2294 void Interpreter::addCharProperty(const Identifier *prop, Owner<Expression> &defval)
2295 {
2296   // FIXME: what about variable default values ?
2297   defval->optimize(*this, Environment(), defval);
2298   if(!defval->constantValue()) {
2299     setNextLocation(defval->location());
2300     message(InterpreterMessages::varCharPropertyExprUnsupported);
2301     return;
2302   }
2303   // FIXME: this is a kind of memory leak
2304   makePermanent(defval->constantValue());
2305   ELObjPart val(defval->constantValue(), partIndex_);
2306   const CharProp *cp = charProperties_.lookup(prop->name());
2307   if (cp) {
2308     if (partIndex_ < cp->def.defPart)
2309       ((CharProp *)cp)->def = val;
2310     else if (partIndex_ == cp->def.defPart &&
2311              !ELObj::eqv(*val.obj, *cp->def.obj)) {
2312       // FIXME: report previous location
2313       setNextLocation(defval->location());
2314       message(InterpreterMessages::duplicateCharPropertyDecl,
2315               StringMessageArg(prop->name()), cp->loc);
2316     }
2317   }
2318    else {
2319     CharProp ncp;
2320     ncp.map = new CharMap<ELObjPart>(ELObjPart(0,0));
2321     ncp.def = val;
2322     ncp.loc = defval->location();
2323     charProperties_.insert(prop->name(), ncp);
2324   }
2325 }
2326 
2327 void Interpreter::setCharProperty(const Identifier *prop, Char c, Owner<Expression> &val)
2328 {
2329   // FIXME: what about variable default values ?
2330   val->optimize(*this, Environment(), val);
2331   if(!val->constantValue()) {
2332     setNextLocation(val->location());
2333     message(InterpreterMessages::varCharPropertyExprUnsupported);
2334     return;
2335   }
2336   makePermanent(val->constantValue());
2337   const CharProp *cp = charProperties_.lookup(prop->name());
2338   if (!cp) {
2339     CharProp ncp;
2340     ncp.map = new CharMap<ELObjPart>(ELObjPart(0,0));
2341     ncp.def = ELObjPart(0, unsigned(-1));
2342     ncp.loc = val->location();
2343     charProperties_.insert(prop->name(), ncp);
2344     cp = charProperties_.lookup(prop->name());
2345   }
2346   ELObjPart obj = ELObjPart(val->constantValue(), partIndex_);
2347 
2348   ELObjPart def = (*cp->map)[c];
2349   if (def.obj) {
2350     if (partIndex_ < def.defPart)
2351       cp->map->setChar(c, obj);
2352     else if (partIndex_ == def.defPart && !ELObj::eqv(*obj.obj, *def.obj)) {
2353       setNextLocation(val->location());
2354       // FIXME: report previous location
2355       message(InterpreterMessages::duplicateAddCharProperty,
2356               StringMessageArg(prop->name()),
2357               StringMessageArg(StringC(&c, 1)));
2358     }
2359   }
2360   else
2361     cp->map->setChar(c, obj);
2362 }
2363 
2364 void
2365 Interpreter::compileCharProperties()
2366 {
2367   HashTableIter<StringC, CharProp> iter(charProperties_);
2368   const StringC *key;
2369   const CharProp *val;
2370   while (iter.next(key, val))
2371     if (!val->def.obj) {
2372       // FIXME location
2373       setNextLocation(val->loc);
2374       message(InterpreterMessages::unknownCharProperty,
2375               StringMessageArg(*key));
2376       ((CharProp *)val)->def = ELObjPart(makeError(), 0);
2377     }
2378 }
2379 
2380 
2381 void Interpreter::installExtensionCharNIC(Identifier *ident,
2382 					  const StringC &pubid,
2383 					  const Location &loc)
2384 {
2385   ident->setCharNIC(currentPartIndex(), loc);
2386 }
2387 
2388 #ifdef DSSSL_NAMESPACE
2389 }
2390 #endif
2391