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 "macros.h"
14 #include <stdlib.h>
15 
16 #ifdef DSSSL_NAMESPACE
17 namespace DSSSL_NAMESPACE {
18 #endif
19 
20 const Char defaultChar = 0xfffd;
21 
22 static
maxObjSize()23 size_t maxObjSize()
24 {
25   static size_t sz[] = {
26     sizeof(UnresolvedQuantityObj),
27     sizeof(VarStyleObj),
28     sizeof(OverriddenStyleObj),
29     sizeof(MergeStyleObj),
30     sizeof(DeviceRGBColorObj),
31     sizeof(ColorSpaceObj),
32     sizeof(PairObj),
33     sizeof(QuantityObj),
34     sizeof(GlyphIdObj),
35     sizeof(NamedNodeListPtrNodeListObj),
36     sizeof(ProcessNodeSosofoObj),
37     sizeof(AppendSosofoObj),
38     sizeof(SetNonInheritedCsSosofoObj),
39     sizeof(LabelSosofoObj),
40     sizeof(MacroFlowObj),
41     sizeof(FlowObj) + sizeof(StringC), // for FormattingInstructionFlowObj
42   };
43   size_t n = sz[0];
44   for (size_t i = 1; i < SIZEOF(sz); i++)
45     if (sz[i] > n)
46       n = sz[i];
47   return n;
48 }
49 
Interpreter(GroveManager * groveManager,Messenger * messenger,int unitsPerInch,bool debugMode,bool dsssl2,const FOTBuilder::Extension * extensionTable)50 Interpreter::Interpreter(GroveManager *groveManager,
51 			 Messenger *messenger,
52 			 int unitsPerInch,
53 			 bool debugMode,
54 			 bool dsssl2,
55 			 const FOTBuilder::Extension *extensionTable)
56 : groveManager_(groveManager),
57   messenger_(messenger),
58   extensionTable_(extensionTable),
59   Collector(maxObjSize()),
60   partIndex_(1),  // 0 is for command-line definitions
61   lexCategory_(lexOther),
62   unitsPerInch_(unitsPerInch),
63   nInheritedC_(0),
64   initialProcessingMode_(StringC()),
65   currentPartFirstInitialValue_(0),
66   initialStyle_(0),
67   nextGlyphSubstTableUniqueId_(0),
68   debugMode_(debugMode),
69   dsssl2_(dsssl2)
70 {
71   makePermanent(theNilObj_ = new (*this) NilObj);
72   makePermanent(theFalseObj_ = new (*this) FalseObj);
73   makePermanent(theTrueObj_ = new (*this) TrueObj);
74   makePermanent(theErrorObj_ = new (*this) ErrorObj);
75   makePermanent(theUnspecifiedObj_ = new (*this) UnspecifiedObj);
76   makePermanent(addressNoneObj_
77                 = new (*this) AddressObj(FOTBuilder::Address::none));
78   makePermanent(emptyNodeListObj_
79 		= new (*this) NodePtrNodeListObj);
80   installSyntacticKeys();
81   installCValueSymbols();
82   installPortNames();
83   installPrimitives();
84   installUnits();
85   installCharNames();
86   installFlowObjs();
87   installInheritedCs();
88   installSdata();
89   installNodeProperties();
90 
91   static const char *lexCategories[] = {
92     "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz",
93     "!$%&*/<=>?~_^:",
94     "0123456789",
95     "-+.",
96     "();\"",
97     " \t\r\n\f",
98   };
99       //
100   for (size_t i = 0; i < SIZEOF(lexCategories); i++)
101     for (const char *s = lexCategories[i]; *s; s++)
102       lexCategory_.setChar(*s, i);
103   initialProcessingMode_.setDefined();
104 }
105 
compile()106 void Interpreter::compile()
107 {
108   // FIXME compile all definitions
109   compileInitialValues();
110   initialProcessingMode_.compile(*this);
111   NamedTableIter<ProcessingMode> iter(processingModeTable_);
112   for (;;) {
113     ProcessingMode *mode = iter.next();
114     if (!mode)
115       break;
116     mode->compile(*this);
117   }
118 }
119 
compileInitialValues()120 void Interpreter::compileInitialValues()
121 {
122   Vector<ConstPtr<InheritedC> > ics;
123   for (size_t i = 0; i < initialValueNames_.size(); i++) {
124     const Identifier *ident = initialValueNames_[i];
125     Owner<Expression> &expr = initialValueValues_[i];
126     ConstPtr<InheritedC> ic(ident->inheritedC());
127     expr->optimize(*this, Environment(), expr);
128     ELObj *val = expr->constantValue();
129     if (val) {
130       ConstPtr<InheritedC> tem(ic->make(val, expr->location(), *this));
131       if (!tem.isNull())
132 	ics.push_back(tem);
133     }
134     else
135       ics.push_back(new VarInheritedC(ic,
136     			              expr->compile(*this, Environment(), 0, InsnPtr()),
137 			              expr->location()));
138   }
139   if (ics.size()) {
140     Vector<ConstPtr<InheritedC> > forceIcs;
141     initialStyle_ = new (*this) VarStyleObj(new StyleSpec(forceIcs, ics), 0, 0, NodePtr());
142     makePermanent(initialStyle_);
143   }
144 }
145 
installInitialValue(Identifier * ident,Owner<Expression> & expr)146 void Interpreter::installInitialValue(Identifier *ident, Owner<Expression> &expr)
147 {
148   for (size_t i = 0; i < initialValueNames_.size(); i++) {
149     if (ident == initialValueNames_[i]) {
150       if (i >= currentPartFirstInitialValue_) {
151 	setNextLocation(expr->location());
152 	message(InterpreterMessages::duplicateInitialValue,
153 	        StringMessageArg(ident->name()),
154 		initialValueValues_[i]->location());
155       }
156       return;
157     }
158   }
159   initialValueValues_.resize(initialValueValues_.size() + 1);
160   expr.swap(initialValueValues_.back());
161   initialValueNames_.push_back(ident);
162 }
163 
defineVariable(const StringC & str)164 void Interpreter::defineVariable(const StringC &str)
165 {
166   lookup(str)->setValue(makeTrue(), 0);
167 }
168 
installUnits()169 void Interpreter::installUnits()
170 {
171   static struct {
172     const char *name;
173     int numer;
174     int denom;
175     bool dsssl2;
176   } units[] = {
177     { "m", 5000, 127 },
178     { "cm", 50, 127 },
179     { "mm", 5, 127 },
180     { "in", 1, 1 },
181     { "pt", 1, 72 },
182     { "pica", 1, 6 },
183     { "pc", 1, 6 } // a DSSSL2 addition
184   };
185   size_t nUnits = dsssl2() ? SIZEOF(units) : SIZEOF(units) - 1;
186   for (size_t i = 0; i < nUnits; i++) {
187     Unit *unit = lookupUnit(makeStringC(units[i].name));
188     long n = unitsPerInch_ * units[i].numer;
189     if (n % units[i].denom == 0)
190       unit->setValue(long(n / units[i].denom));
191     else
192       unit->setValue(double(n)/units[i].denom);
193   }
194 }
195 
installSyntacticKeys()196 void Interpreter::installSyntacticKeys()
197 {
198   static struct {
199     const char *name;
200     Identifier::SyntacticKey key;
201   } keys[] = {
202     { "quote", Identifier::keyQuote },
203     { "lambda", Identifier::keyLambda },
204     { "if", Identifier::keyIf },
205     { "cond", Identifier::keyCond },
206     { "and", Identifier::keyAnd },
207     { "or", Identifier::keyOr },
208     { "case", Identifier::keyCase },
209     { "let", Identifier::keyLet },
210     { "let*", Identifier::keyLetStar },
211     { "letrec", Identifier::keyLetrec },
212     { "quasiquote", Identifier::keyQuasiquote },
213     { "unquote", Identifier::keyUnquote },
214     { "unquote-splicing", Identifier::keyUnquoteSplicing },
215     { "define", Identifier::keyDefine },
216     { "else", Identifier::keyElse },
217     { "=>", Identifier::keyArrow },
218     { "make", Identifier::keyMake },
219     { "style", Identifier::keyStyle },
220     { "with-mode", Identifier::keyWithMode },
221     { "define-unit", Identifier::keyDefineUnit },
222     { "element", Identifier::keyElement },
223     { "default", Identifier::keyDefault },
224     { "root", Identifier::keyRoot },
225     { "id", Identifier::keyId },
226     { "mode", Identifier::keyMode },
227     { "declare-initial-value", Identifier::keyDeclareInitialValue },
228     { "declare-characteristic", Identifier::keyDeclareCharacteristic },
229     { "declare-flow-object-class", Identifier::keyDeclareFlowObjectClass },
230     { "declare-char-characteristic+property", Identifier::keyDeclareCharCharacteristicAndProperty },
231     { "declare-reference-value-type", Identifier::keyDeclareReferenceValueType },
232     { "declare-default-language", Identifier::keyDeclareDefaultLanguage },
233     { "declare-char-property", Identifier::keyDeclareCharProperty },
234     { "define-page-model", Identifier::keyDefinePageModel },
235     { "define-column-set-model", Identifier::keyDefineColumnSetModel },
236     { "define-language", Identifier::keyDefineLanguage },
237     { "add-char-properties", Identifier::keyAddCharProperties },
238     { "use", Identifier::keyUse },
239     { "label", Identifier::keyLabel },
240     { "content-map", Identifier::keyContentMap },
241     { "keep-with-previous?", Identifier::keyIsKeepWithPrevious },
242     { "keep-with-next?", Identifier::keyIsKeepWithNext },
243     { "space-before", Identifier::keySpaceBefore },
244     { "space-after", Identifier::keySpaceAfter },
245     { "left-header", Identifier::keyLeftHeader },
246     { "center-header", Identifier::keyCenterHeader },
247     { "right-header", Identifier::keyRightHeader },
248     { "left-footer", Identifier::keyLeftFooter },
249     { "center-footer", Identifier::keyCenterFooter },
250     { "right-footer", Identifier::keyRightFooter },
251     { "destination", Identifier::keyDestination },
252     { "type", Identifier::keyType },
253     { "coalesce-id", Identifier::keyCoalesceId },
254     { "display?", Identifier::keyIsDisplay },
255     { "scale", Identifier::keyScale },
256     { "max-width", Identifier::keyMaxWidth },
257     { "max-height", Identifier::keyMaxHeight },
258     { "entity-system-id", Identifier::keyEntitySystemId },
259     { "notation-system-id", Identifier::keyNotationSystemId },
260     { "position-point-x", Identifier::keyPositionPointX },
261     { "position-point-y", Identifier::keyPositionPointY },
262     { "escapement-direction", Identifier::keyEscapementDirection },
263     { "break-before-priority", Identifier::keyBreakBeforePriority },
264     { "break-after-priority", Identifier::keyBreakAfterPriority },
265     { "orientation", Identifier::keyOrientation },
266     { "length", Identifier::keyLength },
267     { "char", Identifier::keyChar },
268     { "glyph-id", Identifier::keyGlyphId },
269     { "space?", Identifier::keyIsSpace },
270     { "record-end?", Identifier::keyIsRecordEnd },
271     { "input-tab?", Identifier::keyIsInputTab },
272     { "input-whitespace?", Identifier::keyIsInputWhitespace },
273     { "punct?", Identifier::keyIsPunct },
274     { "drop-after-line-break?", Identifier::keyIsDropAfterLineBreak },
275     { "drop-unless-before-line-break?", Identifier::keyIsDropUnlessBeforeLineBreak },
276     { "math-class", Identifier::keyMathClass },
277     { "math-font-posture", Identifier::keyMathFontPosture },
278     { "script", Identifier::keyScript },
279     { "stretch-factor", Identifier::keyStretchFactor },
280     { "keep", Identifier::keyKeep },
281     { "break-before", Identifier::keyBreakBefore },
282     { "break-after", Identifier::keyBreakAfter },
283     { "may-violate-keep-before?", Identifier::keyIsMayViolateKeepBefore },
284     { "may-violate-keep-after?", Identifier::keyIsMayViolateKeepAfter },
285     { "before-row-border", Identifier::keyBeforeRowBorder },
286     { "after-row-border", Identifier::keyAfterRowBorder },
287     { "before-column-border", Identifier::keyBeforeColumnBorder },
288     { "after-column-border", Identifier::keyAfterColumnBorder },
289     { "column-number", Identifier::keyColumnNumber },
290     { "row-number", Identifier::keyRowNumber },
291     { "n-columns-spanned", Identifier::keyNColumnsSpanned },
292     { "n-rows-spanned", Identifier::keyNRowsSpanned },
293     { "width", Identifier::keyWidth },
294     { "starts-row?", Identifier::keyIsStartsRow },
295     { "ends-row?", Identifier::keyIsEndsRow },
296     { "table-width", Identifier::keyTableWidth },
297     { "multi-modes", Identifier::keyMultiModes },
298     { "data", Identifier::keyData },
299     { "min", Identifier::keyMin },
300     { "max", Identifier::keyMax },
301     { "conditional?", Identifier::keyIsConditional },
302     { "priority", Identifier::keyPriority },
303     { "grid-n-rows", Identifier::keyGridNRows },
304     { "grid-n-columns", Identifier::keyGridNColumns },
305     { "radical", Identifier::keyRadical },
306     { "null", Identifier::keyNull },
307     { "rcs?", Identifier::keyIsRcs },
308     { "parent", Identifier::keyParent },
309     { "active", Identifier::keyActive },
310     { "attributes", Identifier::keyAttributes },
311     { "children", Identifier::keyChildren },
312     { "repeat", Identifier::keyRepeat },
313     { "position", Identifier::keyPosition },
314     { "only", Identifier::keyOnly },
315     { "class", Identifier::keyClass },
316     { "importance", Identifier::keyImportance },
317     { "position-preference", Identifier::keyPositionPreference },
318     { "architecture", Identifier::keyArchitecture },
319   }, keys2[] = {
320     { "declare-class-attribute", Identifier::keyDeclareClassAttribute },
321     { "declare-id-attribute", Identifier::keyDeclareIdAttribute },
322     { "declare-flow-object-macro", Identifier::keyDeclareFlowObjectMacro },
323     { "or-element", Identifier::keyOrElement },
324     { "set!", Identifier::keySet },
325     { "begin", Identifier::keyBegin },
326   };
327   for (size_t i = 0; i < SIZEOF(keys); i++) {
328     StringC tem(makeStringC(keys[i].name));
329     lookup(tem)->setSyntacticKey(keys[i].key);
330     if (dsssl2() && tem[tem.size() - 1] == '?') {
331       tem.resize(tem.size() - 1);
332       lookup(tem)->setSyntacticKey(keys[i].key);
333     }
334   }
335   if (dsssl2()) {
336     for (size_t i = 0; i < SIZEOF(keys2); i++)
337       lookup(makeStringC(keys2[i].name))->setSyntacticKey(keys2[i].key);
338   }
339 }
340 
installCValueSymbols()341 void Interpreter::installCValueSymbols()
342 {
343   cValueSymbols_[0] = makeFalse();
344   cValueSymbols_[1] = makeTrue();
345   for (size_t i = 2; i < FOTBuilder::nSymbols; i++) {
346     SymbolObj *sym = makeSymbol(makeStringC(FOTBuilder::symbolName(FOTBuilder::Symbol(i))));
347     sym->setCValue(FOTBuilder::Symbol(i));
348     cValueSymbols_[i] = sym;
349   }
350 }
351 
installPortNames()352 void Interpreter::installPortNames()
353 {
354   // These must match the order in SymbolObj.
355   static const char *names[] = {
356     "numerator",
357     "denominator",
358     "pre-sup",
359     "pre-sub",
360     "post-sup",
361     "post-sub",
362     "mid-sup",
363     "mid-sub",
364     "over-mark",
365     "under-mark",
366     "open",
367     "close",
368     "degree",
369     "operator",
370     "lower-limit",
371     "upper-limit",
372     "header",
373     "footer"
374   };
375   ASSERT(SIZEOF(names) == nPortNames);
376   for (size_t i = 0; i < SIZEOF(names); i++)
377     portNames_[i] = makeSymbol(makeStringC(names[i]));
378 }
379 
installCharNames()380 void Interpreter::installCharNames()
381 {
382   static struct {
383     Char c;
384     const char *name;
385   } chars[] = {
386 #include "charNames.h"
387   };
388   for (size_t i = 0; i < SIZEOF(chars); i++)
389     namedCharTable_.insert(makeStringC(chars[i].name), chars[i].c);
390 }
391 
installSdata()392 void Interpreter::installSdata()
393 {
394   // This comes from uni2sgml.txt on ftp://unicode.org.
395   // It is marked there as obsolete, so it probably ought to be checked.
396   // The definitions of apos and quot have been fixed for consistency with XML.
397   static struct {
398     Char c;
399     const char *name;
400   } entities[] = {
401 #include "sdata.h"
402   };
403   for (size_t i = 0; i < SIZEOF(entities); i++)
404     sdataEntityNameTable_.insert(makeStringC(entities[i].name), entities[i].c);
405 }
406 
installNodeProperties()407 void Interpreter::installNodeProperties()
408 {
409   for (int i = 0; i < ComponentName::nIds; i++) {
410     ComponentName::Id id = ComponentName::Id(i);
411     nodePropertyTable_.insert(makeStringC(ComponentName::rcsName(id)), i);
412     nodePropertyTable_.insert(makeStringC(ComponentName::sdqlName(id)), i);
413   }
414 }
415 
sdataMap(GroveString name,GroveString,GroveChar & c) const416 bool Interpreter::sdataMap(GroveString name, GroveString, GroveChar &c) const
417 {
418   StringC tem(name.data(), name.size());
419   const Char *cp = sdataEntityNameTable_.lookup(tem);
420   if (cp) {
421     c = *cp;
422     return 1;
423   }
424   if (convertUnicodeCharName(tem, c))
425     return 1;
426   // I think this is the most thing to do.
427   // At least it makes preserve-sdata work with unknown SDATA entities.
428   c = defaultChar;
429   return 1;
430 }
431 
convertGlyphId(const Char * str,size_t len,const Location & loc)432 ELObj *Interpreter::convertGlyphId(const Char *str, size_t len, const Location &loc)
433 {
434   unsigned long n = 0;
435   const char *publicId = 0;
436   for (size_t i = len; i > 1; --i) {
437     if (str[i - 1] == ':' && str[i - 2] == ':' && i < len && str[i] != '0') {
438       for (size_t j = i; j < len; j++)
439 	n = n*10 + (str[j] - '0');
440       publicId = storePublicId(str, i - 2, loc);
441       break;
442     }
443     if (str[i - 1] < '0' || str[i - 1] > '9')
444       break;
445   }
446   if (!publicId)
447     publicId = storePublicId(str, len, loc);
448   return new (*this) GlyphIdObj(FOTBuilder::GlyphId(publicId, n));
449 }
450 
convertCharName(const StringC & str,Char & c) const451 bool Interpreter::convertCharName(const StringC &str, Char &c) const
452 {
453   const Char *cp = namedCharTable_.lookup(str);
454   if (cp) {
455     c = *cp;
456     return 1;
457   }
458   return convertUnicodeCharName(str, c);
459 }
460 
convertUnicodeCharName(const StringC & str,Char & c)461 bool Interpreter::convertUnicodeCharName(const StringC &str, Char &c)
462 {
463   if (str.size() != 6 || str[0] != 'U' || str[1] != '-')
464     return 0;
465   Char value = 0;
466   for (int i = 2; i < 6; i++) {
467     value <<= 4;
468     switch (str[i]) {
469     case '0':
470     case '1':
471     case '2':
472     case '3':
473     case '4':
474     case '5':
475     case '6':
476     case '7':
477     case '8':
478     case '9':
479       value |= str[i] - '0';
480       break;
481     case 'A':
482     case 'B':
483     case 'C':
484     case 'D':
485     case 'E':
486     case 'F':
487       value |= 10 + (str[i] - 'A');
488       break;
489     default:
490       return 0;
491     }
492   }
493   c = value;
494   return 1;
495 }
496 
makeSymbol(const StringC & str)497 SymbolObj *Interpreter::makeSymbol(const StringC &str)
498 {
499   SymbolObj *sym = symbolTable_.lookup(str);
500   if (!sym) {
501     StringObj *strObj = new (*this) StringObj(str);
502     makePermanent(strObj);
503     sym = new (*this) SymbolObj(strObj);
504     makePermanent(sym);
505     symbolTable_.insert(sym);
506   }
507   return sym;
508 }
509 
lookup(const StringC & str)510 Identifier *Interpreter::lookup(const StringC &str)
511 {
512   Identifier *ident = identTable_.lookup(str);
513   if (!ident) {
514     ident = new Identifier(str);
515     identTable_.insert(ident);
516   }
517   return ident;
518 }
519 
lookupNodeProperty(const StringC & str,ComponentName::Id & id)520 bool Interpreter::lookupNodeProperty(const StringC &str, ComponentName::Id &id)
521 {
522   const int *val = nodePropertyTable_.lookup(str);
523   if (!val) {
524     StringC tem(str);
525     for (size_t i = 0; i < tem.size(); i++) {
526       if (tem[i] >= 'A' && tem[i] <= 'Z')
527         tem[i] = 'a' + (tem[i] - 'A');
528     }
529     val = nodePropertyTable_.lookup(tem);
530     if (!val)
531       return 0;
532   }
533   id = ComponentName::Id(*val);
534   return 1;
535 }
536 
lookupUnit(const StringC & str)537 Unit *Interpreter::lookupUnit(const StringC &str)
538 {
539   Unit *unit = unitTable_.lookup(str);
540   if (!unit) {
541     unit = new Unit(str);
542     unitTable_.insert(unit);
543   }
544   return unit;
545 }
546 
lookupProcessingMode(const StringC & str)547 ProcessingMode *Interpreter::lookupProcessingMode(const StringC &str)
548 {
549   ProcessingMode *mode = processingModeTable_.lookup(str);
550   if (!mode) {
551     mode = new ProcessingMode(str, &initialProcessingMode_);
552     processingModeTable_.insert(mode);
553   }
554   return mode;
555 }
556 
makeStringC(const char * s)557 StringC Interpreter::makeStringC(const char *s)
558 {
559   StringC tem;
560   if (s)
561     while (*s)
562       tem += (unsigned char)*s++;
563   return tem;
564 }
565 
endPart()566 void Interpreter::endPart()
567 {
568   currentPartFirstInitialValue_ = initialValueNames_.size();
569   partIndex_++;
570 }
571 
normalizeGeneralName(const NodePtr & nd,StringC & str)572 void Interpreter::normalizeGeneralName(const NodePtr &nd, StringC &str)
573 {
574   NamedNodeListPtr nnl;
575   NodePtr root;
576   if (nd->getGroveRoot(root) == accessOK
577       && root->getElements(nnl) == accessOK)
578     str.resize(nnl->normalize(str.begin(), str.size()));
579 }
580 
makeLengthSpec(const FOTBuilder::LengthSpec & ls)581 ELObj *Interpreter::makeLengthSpec(const FOTBuilder::LengthSpec &ls)
582 {
583   if (ls.displaySizeFactor != 0.0) {
584     LengthSpec result(LengthSpec::displaySize, ls.displaySizeFactor);
585     result += double(ls.length);
586     return new (*this) LengthSpecObj(result);
587   }
588   else
589     return new (*this) LengthObj(ls.length);
590 }
591 
convertBooleanC(ELObj * obj,const Identifier * ident,const Location & loc,bool & result)592 bool Interpreter::convertBooleanC(ELObj *obj, const Identifier *ident, const Location &loc,
593 				  bool &result)
594 {
595   obj = convertFromString(obj, convertAllowBoolean, loc);
596   if (obj == makeFalse()) {
597     result = 0;
598     return 1;
599   }
600   if (obj == makeTrue()) {
601     result = 1;
602     return 1;
603   }
604   invalidCharacteristicValue(ident, loc);
605   return 0;
606 }
607 
convertPublicIdC(ELObj * obj,const Identifier * ident,const Location & loc,FOTBuilder::PublicId & pubid)608 bool Interpreter::convertPublicIdC(ELObj *obj, const Identifier *ident,
609 				   const Location &loc,
610 				   FOTBuilder::PublicId &pubid)
611 {
612   if (obj == makeFalse()) {
613     pubid = 0;
614     return 1;
615   }
616   const Char *s;
617   size_t n;
618   if (obj->stringData(s, n)) {
619     if (n == 0)
620       pubid = 0;
621     else
622       pubid = storePublicId(s, n, loc);
623     return 1;
624   }
625   invalidCharacteristicValue(ident, loc);
626   return 0;
627 }
628 
storePublicId(const Char * s,size_t n,const Location & loc)629 const char *Interpreter::storePublicId(const Char *s, size_t n, const Location &loc)
630 {
631   String<char> buf;
632   for (; n > 0; s++, n--) {
633     if (*s >= 128) {
634       setNextLocation(loc);
635       message(InterpreterMessages::invalidPublicIdChar,
636 	      StringMessageArg(StringC(s, 1)));
637     }
638     else
639       buf += char(*s);
640   }
641   buf += '\0';
642   return publicIds_.store(buf);
643 }
644 
convertStringC(ELObj * obj,const Identifier * ident,const Location & loc,StringC & result)645 bool Interpreter::convertStringC(ELObj *obj, const Identifier *ident, const Location &loc,
646 				 StringC &result)
647 {
648   const Char *s;
649   size_t n;
650   if (obj->stringData(s, n)) {
651     result.assign(s, n);
652     return 1;
653   }
654   invalidCharacteristicValue(ident, loc);
655   return 0;
656 }
657 
convertLengthSpec(ELObj * obj,FOTBuilder::LengthSpec & result)658 bool Interpreter::convertLengthSpec(ELObj *obj,
659 				    FOTBuilder::LengthSpec &result)
660 {
661   int dim;
662   double d;
663   switch (obj->quantityValue(result.length, d, dim)) {
664   case ELObj::longQuantity:
665     if (dim == 1)
666       return 1;
667     break;
668   case ELObj::doubleQuantity:
669     if (dim == 1) {
670       // FIXME catch overflow
671       result.length = d < 0.0 ? long(d - .5) : long(d + .5);
672       return 1;
673     }
674     break;
675   default:
676     {
677       const LengthSpec *ls = obj->lengthSpec();
678       if (ls)
679 	return ls->convert(result);
680     }
681     break;
682   }
683   return 0;
684 }
685 
convertLengthC(ELObj * obj,const Identifier * ident,const Location & loc,FOTBuilder::Length & n)686 bool Interpreter::convertLengthC(ELObj *obj, const Identifier *ident,
687 				 const Location &loc,
688 				 FOTBuilder::Length &n)
689 {
690   obj = convertFromString(obj, convertAllowNumber, loc);
691   int dim;
692   double d;
693   switch (obj->quantityValue(n, d, dim)) {
694   case ELObj::longQuantity:
695     if (dim == 1)
696       return 1;
697     break;
698   case ELObj::doubleQuantity:
699     if (dim == 1) {
700       // FIXME catch overflow
701       n = long(d);
702       return 1;
703     }
704     break;
705   default:
706     break;
707   }
708   invalidCharacteristicValue(ident, loc);
709   return 0;
710 }
711 
convertLengthSpecC(ELObj * obj,const Identifier * ident,const Location & loc,FOTBuilder::LengthSpec & result)712 bool Interpreter::convertLengthSpecC(ELObj *obj, const Identifier *ident,
713 				     const Location &loc,
714 				     FOTBuilder::LengthSpec &result)
715 {
716   obj = convertFromString(obj, convertAllowNumber, loc);
717   if (convertLengthSpec(obj, result))
718     return 1;
719   invalidCharacteristicValue(ident, loc);
720   return 0;
721 }
722 
convertOptLengthSpecC(ELObj * obj,const Identifier * ident,const Location & loc,FOTBuilder::OptLengthSpec & result)723 bool Interpreter::convertOptLengthSpecC(ELObj *obj, const Identifier *ident,
724 					const Location &loc,
725 					FOTBuilder::OptLengthSpec &result)
726 {
727   obj = convertFromString(obj, convertAllowBoolean|convertAllowNumber, loc);
728   if (obj == makeFalse()) {
729     result.hasLength = 0;
730     return 1;
731   }
732   if (convertLengthSpecC(obj, ident, loc, result.length)) {
733     result.hasLength = 1;
734     return 1;
735   }
736   return 0;
737 }
738 
convertOptPositiveIntegerC(ELObj * obj,const Identifier * ident,const Location & loc,long & result)739 bool Interpreter::convertOptPositiveIntegerC(ELObj *obj, const Identifier *ident, const Location &loc,
740 					     long &result)
741 {
742   obj = convertFromString(obj, convertAllowNumber|convertAllowBoolean, loc);
743   if (obj == makeFalse()) {
744     result = 0;
745     return 1;
746   }
747   if (obj->exactIntegerValue(result) && result > 0)
748     return 1;
749   // FIXME allow inexact value
750   invalidCharacteristicValue(ident, loc);
751   return 0;
752 }
753 
convertIntegerC(ELObj * obj,const Identifier * ident,const Location & loc,long & result)754 bool Interpreter::convertIntegerC(ELObj *obj, const Identifier *ident, const Location &loc,
755 				  long &result)
756 {
757   obj = convertFromString(obj, convertAllowNumber, loc);
758   if (obj->exactIntegerValue(result))
759     return 1;
760   // FIXME allow inexact value
761   invalidCharacteristicValue(ident, loc);
762   return 0;
763 }
764 
765 
convertLetter2C(ELObj * obj,const Identifier * ident,const Location & loc,FOTBuilder::Letter2 & code)766 bool Interpreter::convertLetter2C(ELObj *obj, const Identifier *ident, const Location &loc,
767 				  FOTBuilder::Letter2 &code)
768 {
769   StringObj *strObj = obj->convertToString();
770   if (strObj) {
771     const StringC &str = *strObj;
772     if (str.size() == 2
773 	&& str[0] >= 'A' && str[0] <= 'Z'
774 	&& str[1] >= 'A' && str[1] <= 'Z') {
775       code = SP_LETTER2(str[0], str[1]);
776       return 1;
777     }
778     if (str.size() == 0) {
779       code = 0;
780       return 1;
781     }
782   }
783   else if (obj == makeFalse()) {
784     code = 0;
785     return 1;
786   }
787   invalidCharacteristicValue(ident, loc);
788   return 0;
789 }
790 
convertCharC(ELObj * obj,const Identifier * ident,const Location & loc,Char & result)791 bool Interpreter::convertCharC(ELObj *obj, const Identifier *ident, const Location &loc,
792 			       Char &result)
793 {
794   if (obj->charValue(result))
795     return 1;
796   const Char *s;
797   size_t n;
798   if (obj->stringData(s, n) && n == 1) {
799     result = s[0];
800     return 1;
801   }
802   invalidCharacteristicValue(ident, loc);
803   return 0;
804 }
805 
convertColorC(ELObj * obj,const Identifier * ident,const Location & loc,ColorObj * & color)806 bool Interpreter::convertColorC(ELObj *obj, const Identifier *ident, const Location &loc, ColorObj *&color)
807 {
808   color = obj->asColor();
809   if (color)
810     return 1;
811   invalidCharacteristicValue(ident, loc);
812   return 0;
813 }
814 
convertOptColorC(ELObj * obj,const Identifier * ident,const Location & loc,ColorObj * & color)815 bool Interpreter::convertOptColorC(ELObj *obj, const Identifier *ident, const Location &loc, ColorObj *&color)
816 {
817   color = obj->asColor();
818   if (color)
819     return 1;
820   if (obj == makeFalse())
821     return 1;
822   invalidCharacteristicValue(ident, loc);
823   return 0;
824 }
825 
convertRealC(ELObj * obj,const Identifier * ident,const Location & loc,double & result)826 bool Interpreter::convertRealC(ELObj *obj, const Identifier *ident, const Location &loc,
827 			       double &result)
828 {
829   obj = convertFromString(obj, convertAllowNumber, loc);
830   if (obj->realValue(result))
831     return 1;
832   invalidCharacteristicValue(ident, loc);
833   return 0;
834 }
835 
convertEnumC(ELObj * obj,const Identifier * ident,const Location & loc,FOTBuilder::Symbol & sym)836 bool Interpreter::convertEnumC(ELObj *obj, const Identifier *ident, const Location &loc,
837 			       FOTBuilder::Symbol &sym)
838 {
839   obj = convertFromString(obj, convertAllowSymbol|convertAllowBoolean, loc);
840   if (obj == makeFalse()) {
841     sym = FOTBuilder::symbolFalse;
842     return 1;
843   }
844   SymbolObj *symObj = obj->asSymbol();
845   if (symObj) {
846     sym = symObj->cValue();
847     if (sym != FOTBuilder::symbolFalse)
848       return 1;
849   }
850   if (obj == makeTrue()) {
851     sym = FOTBuilder::symbolTrue;
852     return 1;
853   }
854   invalidCharacteristicValue(ident, loc);
855   return 0;
856 }
857 
convertEnumC(const FOTBuilder::Symbol * syms,size_t nSyms,ELObj * obj,const Identifier * ident,const Location & loc,FOTBuilder::Symbol & result)858 bool Interpreter::convertEnumC(const FOTBuilder::Symbol *syms,  size_t nSyms,
859 			       ELObj *obj, const Identifier *ident, const Location &loc,
860 			       FOTBuilder::Symbol &result)
861 {
862   obj = convertFromString(obj, convertAllowSymbol|convertAllowBoolean, loc);
863   SymbolObj *symObj = obj->asSymbol();
864   FOTBuilder::Symbol val;
865   if (symObj) {
866     val = symObj->cValue();
867     if (val == FOTBuilder::symbolFalse) {
868       invalidCharacteristicValue(ident, loc);
869       return 0;
870     }
871   }
872   else if (obj == makeFalse())
873     val = FOTBuilder::symbolFalse;
874   else if (obj == makeTrue())
875     val = FOTBuilder::symbolTrue;
876   else {
877     invalidCharacteristicValue(ident, loc);
878     return 0;
879   }
880   for (size_t i = 0; i < nSyms; i++)
881     if (val == syms[i]) {
882       result = val;
883       return 1;
884     }
885   invalidCharacteristicValue(ident, loc);
886   return 0;
887 }
888 
invalidCharacteristicValue(const Identifier * ident,const Location & loc)889 void Interpreter::invalidCharacteristicValue(const Identifier *ident, const Location &loc)
890 {
891   setNextLocation(loc);
892   message(InterpreterMessages::invalidCharacteristicValue,
893 	  StringMessageArg(ident->name()));
894 }
895 
896 static
equal(const Char * s1,const char * s2,size_t n)897 bool equal(const Char *s1, const char *s2, size_t n)
898 {
899   while (n > 0) {
900     if (*s1++ != (unsigned char)*s2++)
901       return 0;
902     --n;
903   }
904   return 1;
905 }
906 
convertFromString(ELObj * obj,unsigned hints,const Location & loc)907 ELObj *Interpreter::convertFromString(ELObj *obj, unsigned hints, const Location &loc)
908 {
909   // FIXME fold to lower case
910   const Char *s;
911   size_t n;
912   if (!dsssl2() || !obj->stringData(s, n))
913     return obj;
914   if (hints & convertAllowNumber) {
915     ELObj *tem = convertNumber(StringC(s, n));
916     if (tem)
917       return tem->resolveQuantities(1, *this, loc);
918   }
919   if (hints & convertAllowSymbol) {
920     StringC tem(s, n);
921     SymbolObj *sym = symbolTable_.lookup(tem);
922     if (sym && sym->cValue() != FOTBuilder::symbolFalse)
923       return sym;
924   }
925   if (hints & convertAllowBoolean) {
926     switch (n) {
927     case 2:
928       if (equal(s, "no", n))
929 	return makeFalse();
930       break;
931     case 3:
932       if (equal(s, "yes", n))
933 	return makeTrue();
934       break;
935     case 4:
936       if (equal(s, "true", n))
937 	return makeTrue();
938       break;
939     case 5:
940       if (equal(s, "false", n))
941 	return makeFalse();
942       break;
943     }
944   }
945   return obj;
946 }
947 
convertNumber(const StringC & str,int radix)948 ELObj *Interpreter::convertNumber(const StringC &str, int radix)
949 {
950   {
951     if (str.size() == 0)
952       return 0;
953     size_t i = 0;
954     if (str[0] == '#') {
955       if (str.size() < 2)
956 	return 0;
957       switch (str[1]) {
958       case 'd':
959 	radix = 10;
960 	break;
961       case 'x':
962 	radix = 16;
963 	break;
964       case 'o':
965 	radix = 8;
966 	break;
967       case 'b':
968 	radix = 2;
969 	break;
970       default:
971 	return 0;
972       }
973       i += 2;
974     }
975     if (i >= str.size())
976       return 0;
977     bool negative;
978     if (str[i] == '-') {
979       negative = 1;
980       i++;
981     }
982     else {
983       negative = 0;
984       if (str[i] == '+')
985       i++;
986     }
987     bool hadDecimalPoint = 0;
988     bool hadDigit = 0;
989     long n = 0;
990     int exp = 0;
991     for (; i < str.size(); i++) {
992       Char c = str[i];
993       int weight;
994       switch (c) {
995       case '0':
996 	weight = 0;
997 	break;
998       case '1':
999 	weight = 1;
1000 	break;
1001       case '2':
1002 	weight = 2;
1003 	break;
1004       case '3':
1005 	weight = 3;
1006 	break;
1007       case '4':
1008 	weight = 4;
1009 	break;
1010       case '5':
1011 	weight = 5;
1012 	break;
1013       case '6':
1014 	weight = 6;
1015 	break;
1016       case '7':
1017 	weight = 7;
1018 	break;
1019       case '8':
1020 	weight = 8;
1021 	break;
1022       case '9':
1023 	weight = 9;
1024 	break;
1025       case 'a':
1026 	weight = 10;
1027 	break;
1028       case 'b':
1029 	weight = 11;
1030 	break;
1031       case 'c':
1032 	weight = 12;
1033 	break;
1034       case 'd':
1035 	weight = 13;
1036 	break;
1037       case 'e':
1038 	weight = 14;
1039 	break;
1040       case 'f':
1041 	weight = 15;
1042 	break;
1043       default:
1044 	weight = -1;
1045 	break;
1046       }
1047       if (weight >= 0 && weight < radix) {
1048 	hadDigit = 1;
1049 	if (negative) {
1050 	  if (-(unsigned long)n > (-(unsigned long)LONG_MIN - weight)/radix) {
1051 	    if (radix != 10)
1052 	      return 0;
1053 	    return convertNumberFloat(str);
1054 	  }
1055 	  else
1056 	    n = n*radix - weight;
1057 	}
1058 	else {
1059 	  if (n > (LONG_MAX - weight)/radix) {
1060 	    if (radix != 10)
1061 	      return 0;
1062 	    return convertNumberFloat(str);
1063 	  }
1064 	  else
1065 	    n = n*radix + weight;
1066 	}
1067 	if (hadDecimalPoint)
1068 	  exp--;
1069       }
1070       else if (c == '.' && radix == 10) {
1071 	if (hadDecimalPoint)
1072 	  return 0;
1073 	hadDecimalPoint = 1;
1074       }
1075       else
1076 	break;
1077     }
1078     if (!hadDigit || (radix != 10 && i < str.size()))
1079       return 0;
1080     if (i + 1 < str.size() && str[i] == 'e'
1081         && lexCategory(str[i + 1]) != lexLetter) {
1082       hadDecimalPoint = 1;
1083       i++;
1084       int e;
1085       if (!scanSignDigits(str, i, e))
1086 	return 0;
1087       exp += e;
1088     }
1089     if (i < str.size()) {
1090       int unitExp;
1091       Unit *unit = scanUnit(str, i, unitExp);
1092       if (!unit)
1093 	return 0;
1094       if (unitExp == 1)
1095 	return new (*this) UnresolvedLengthObj(n, exp, unit);
1096       else
1097 	return convertNumberFloat(str);
1098     }
1099     if (hadDecimalPoint)
1100       return convertNumberFloat(str);
1101     return makeInteger(n);
1102   }
1103 }
1104 
scanSignDigits(const StringC & str,size_t & i,int & n)1105 bool Interpreter::scanSignDigits(const StringC &str, size_t &i, int &n)
1106 {
1107   bool negative = 0;
1108   if (i < str.size()) {
1109     if (str[i] == '-') {
1110       i++;
1111       negative = 1;
1112     } else if (str[i] == '+')
1113       i++;
1114   }
1115   size_t j = i;
1116   n = 0;
1117   while (i < str.size()
1118 	 && ('0' <= str[i] && str[i] <= '9')) {
1119     if (negative)
1120       n = n*10 - (str[i] - '0');
1121     else
1122       n = n*10 + (str[i] - '0');
1123     i++;
1124   }
1125   if (i == j)
1126     return 0;
1127   return 1;
1128 }
1129 
convertNumberFloat(const StringC & str)1130 ELObj *Interpreter::convertNumberFloat(const StringC &str)
1131 {
1132   String<char> buf;
1133   // omit an optional radix prefix
1134   size_t i0 = 0;
1135   if (str.size() > 1 && str[0] == '#' && str[1] == 'd')
1136     i0 = 2;
1137   for (size_t i = i0; i < str.size(); i++) {
1138     if (str[i] > CHAR_MAX || str[i] == '\0')
1139       return 0;
1140     // 'E' is a valid exponent marker for C but not us
1141     if (str[i] == 'E')
1142       break;
1143     buf += char(str[i]);
1144   }
1145   buf += '\0';
1146   const char *endPtr;
1147   double val = strtod((char *)buf.data(), (char **)&endPtr);
1148   if (endPtr - buf.data() == str.size() - i0)
1149     return new (*this) RealObj(val);
1150   if (endPtr == buf.data())
1151     return 0;
1152   int unitExp;
1153   Unit *unit = scanUnit(str, endPtr - buf.data(), unitExp);
1154   if (!unit)
1155     return 0;
1156   return new (*this) UnresolvedQuantityObj(val, unit, unitExp);
1157 }
1158 
1159 // Return 0 for error.
1160 
scanUnit(const StringC & str,size_t i,int & unitExp)1161 Unit *Interpreter::scanUnit(const StringC &str, size_t i, int &unitExp)
1162 {
1163   StringC unitName;
1164   while (i < str.size()) {
1165     if (str[i] == '-' || str[i] == '+' || ('0' <= str[i] && str[i] <= '9'))
1166       break;
1167     unitName += str[i++];
1168   }
1169   if (i >= str.size())
1170     unitExp = 1;
1171   else {
1172     unitExp = 0;
1173     bool neg = 0;
1174     if (str[i] == '-' || str[i] == '+') {
1175       if (str[i] == '-')
1176       neg = 1;
1177       i++;
1178       if (i >= str.size())
1179 	return 0;
1180     }
1181     while (i < str.size()) {
1182       if (str[i] < '0' || str[i] > '9')
1183 	return 0;
1184       unitExp *= 10;
1185       if (neg)
1186 	unitExp -= (str[i] - '0');
1187       else
1188 	unitExp += (str[i] - '0');
1189       i++;
1190     }
1191   }
1192   return lookupUnit(unitName);
1193 }
1194 
setNodeLocation(const NodePtr & nd)1195 void Interpreter::setNodeLocation(const NodePtr &nd)
1196 {
1197   const LocNode *lnp;
1198   Location nodeLoc;
1199   if ((lnp = LocNode::convert(nd)) != 0
1200       && lnp->getLocation(nodeLoc) == accessOK)
1201     setNextLocation(nodeLoc);
1202 }
1203 
convertToPattern(ELObj * obj,const Location & loc,Pattern & pattern)1204 bool Interpreter::convertToPattern(ELObj *obj, const Location &loc, Pattern &pattern)
1205 {
1206   IList<Pattern::Element> list;
1207   if (!convertToPattern(obj, loc, 0, list))
1208     return 0;
1209   Pattern tem(list);
1210   tem.swap(pattern);
1211   return 1;
1212 }
1213 
convertToPattern(ELObj * obj,const Location & loc,bool isChild,IList<Pattern::Element> & list)1214 bool Interpreter::convertToPattern(ELObj *obj, const Location &loc,
1215 				   bool isChild,
1216 				   IList<Pattern::Element> &list)
1217 {
1218   StringObj *str = obj->convertToString();
1219   if (str) {
1220     const Char *s;
1221     size_t n;
1222     str->stringData(s, n);
1223     if (!n) {
1224       setNextLocation(loc);
1225       message(InterpreterMessages::patternEmptyGi);
1226       return 0;
1227     }
1228     list.insert(new Pattern::Element(StringC(s, n)));
1229     return 1;
1230   }
1231   if (obj == makeTrue()) {
1232     list.insert(new Pattern::Element(StringC()));
1233     return 1;
1234   }
1235   Pattern::Element *curElement = 0;
1236   while (!obj->isNil()) {
1237     PairObj *pair = obj->asPair();
1238     if (!pair) {
1239       setNextLocation(loc);
1240       message(InterpreterMessages::patternNotList);
1241       return 0;
1242     }
1243     ELObj *head = pair->car();
1244     obj = pair->cdr();
1245     if (head == makeTrue() && dsssl2()) {
1246       list.insert(curElement = new Pattern::Element(StringC()));
1247       continue;
1248     }
1249     str = head->convertToString();
1250     if (str) {
1251       const Char *s;
1252       size_t n;
1253       str->stringData(s, n);
1254       if (!n) {
1255 	setNextLocation(loc);
1256 	message(InterpreterMessages::patternEmptyGi);
1257 	return 0;
1258       }
1259       list.insert(curElement = new Pattern::Element(StringC(s, n)));
1260       continue;
1261     }
1262     if (!curElement) {
1263       setNextLocation(loc);
1264       message(InterpreterMessages::patternBadGi,
1265 	      ELObjMessageArg(head, *this));
1266       return 0;
1267     }
1268     if (head->isNil())
1269       continue; // empty attribute list
1270     if (head->asPair()) {
1271       if (!patternAddAttributeQualifiers(head, loc, *curElement)) {
1272 	setNextLocation(loc);
1273 	message(InterpreterMessages::patternBadAttributeQualifier);
1274 	return 0;
1275       }
1276       continue;
1277     }
1278     KeywordObj *key = dsssl2() ? head->asKeyword() : 0;
1279     if (!key) {
1280       setNextLocation(loc);
1281       message(InterpreterMessages::patternBadMember,
1282 	      ELObjMessageArg(head, *this));
1283       return 0;
1284     }
1285     pair = obj->asPair();
1286     if (!pair) {
1287       setNextLocation(loc);
1288       message(obj->isNil()
1289 	      ? InterpreterMessages::patternMissingQualifierValue
1290 	      : InterpreterMessages::patternNotList);
1291       return 0;
1292     }
1293     ELObj *value = pair->car();
1294     obj = pair->cdr();
1295     Identifier::SyntacticKey k;
1296     if (!key->identifier()->syntacticKey(k)) {
1297       setNextLocation(loc);
1298       message(InterpreterMessages::patternUnknownQualifier,
1299 	      StringMessageArg(key->identifier()->name()));
1300       return 0;
1301     }
1302     switch (k) {
1303     case Identifier::keyAttributes:
1304       if (!patternAddAttributeQualifiers(value, loc, *curElement)) {
1305 	setNextLocation(loc);
1306 	message(InterpreterMessages::patternBadAttributeQualifier);
1307 	return 0;
1308       }
1309       break;
1310     case Identifier::keyChildren:
1311       {
1312 	IList<Pattern::Element> children;
1313 	if (!convertToPattern(value, loc, 1, children))
1314 	  return 0;
1315 	if (!children.empty())
1316 	  curElement->addQualifier(new Pattern::ChildrenQualifier(children));
1317       }
1318       break;
1319     case Identifier::keyRepeat:
1320       {
1321 	if (isChild) {
1322 	  setNextLocation(loc);
1323 	  message(InterpreterMessages::patternChildRepeat);
1324 	  return 0;
1325 	}
1326         SymbolObj *sym = value->asSymbol();
1327 	if (sym) {
1328 	  const StringC &str = *sym->name();
1329 	  if (str.size() == 1) {
1330 	    switch (str[0]) {
1331 	    case '*':
1332 	      curElement->setRepeat(0, Pattern::Repeat(-1));
1333 	      value = 0;
1334 	      break;
1335 	    case '?':
1336 	      curElement->setRepeat(0, 1);
1337 	      value = 0;
1338 	      break;
1339 	    case '+':
1340 	      curElement->setRepeat(1, Pattern::Repeat(-1));
1341 	      value = 0;
1342 	      break;
1343 	    default:
1344 	      break;
1345 	    }
1346 	  }
1347 	}
1348 	if (value) {
1349 	  setNextLocation(loc);
1350 	  message(InterpreterMessages::patternBadQualifierValue,
1351 	          ELObjMessageArg(value, *this),
1352 		  StringMessageArg(key->identifier()->name()));
1353 	  return 0;
1354 	}
1355       }
1356       break;
1357     case Identifier::keyPosition:
1358       {
1359         SymbolObj *sym = value->asSymbol();
1360 	if (sym) {
1361 	  Pattern::Qualifier *qual = 0;
1362 	  const StringC &str = *sym->name();
1363 	  if (str == "first-of-type")
1364 	    qual = new Pattern::FirstOfTypeQualifier;
1365 	  else if (str == "last-of-type")
1366 	    qual = new Pattern::LastOfTypeQualifier;
1367 	  else if (str == "first-of-any")
1368 	    qual = new Pattern::FirstOfAnyQualifier;
1369 	  else if (str == "last-of-any")
1370 	    qual = new Pattern::LastOfAnyQualifier;
1371 	  if (qual) {
1372 	    curElement->addQualifier(qual);
1373 	    break;
1374 	  }
1375 	}
1376         setNextLocation(loc);
1377 	message(InterpreterMessages::patternBadQualifierValue,
1378 	        ELObjMessageArg(value, *this),
1379 		StringMessageArg(key->identifier()->name()));
1380 	return 0;
1381       }
1382     case Identifier::keyOnly:
1383       {
1384         SymbolObj *sym = value->asSymbol();
1385 	if (sym) {
1386 	  Pattern::Qualifier *qual = 0;
1387 	  const StringC &str = *sym->name();
1388 	  if (str == "of-type")
1389 	    qual = new Pattern::OnlyOfTypeQualifier;
1390 	  else if (str == "of-any")
1391 	    qual = new Pattern::OnlyOfAnyQualifier;
1392 	  if (qual) {
1393 	    curElement->addQualifier(qual);
1394 	    break;
1395 	  }
1396 	}
1397 	setNextLocation(loc);
1398     	message(InterpreterMessages::patternBadQualifierValue,
1399 	        ELObjMessageArg(value, *this),
1400 		StringMessageArg(key->identifier()->name()));
1401 	return 0;
1402       }
1403       break;
1404     case Identifier::keyId:
1405       {
1406 	StringObj *str = value->convertToString();
1407 	if (!str) {
1408 	  setNextLocation(loc);
1409 	  message(InterpreterMessages::patternBadQualifierValue,
1410 	          ELObjMessageArg(value, *this),
1411 		  StringMessageArg(key->identifier()->name()));
1412 	  return 0;
1413 	}
1414 	const Char *s;
1415 	size_t n;
1416 	str->stringData(s, n);
1417 	curElement->addQualifier(new Pattern::IdQualifier(StringC(s, n)));
1418       }
1419       break;
1420     case Identifier::keyClass:
1421       {
1422 	StringObj *str = value->convertToString();
1423 	if (!str) {
1424 	  setNextLocation(loc);
1425 	  message(InterpreterMessages::patternBadQualifierValue,
1426 	          ELObjMessageArg(value, *this),
1427 		  StringMessageArg(key->identifier()->name()));
1428 	  return 0;
1429 	}
1430 	const Char *s;
1431 	size_t n;
1432 	str->stringData(s, n);
1433 	curElement->addQualifier(new Pattern::ClassQualifier(StringC(s, n)));
1434       }
1435       break;
1436     case Identifier::keyImportance:
1437       {
1438 	long n;
1439 	if (!value->exactIntegerValue(n)) {
1440 	  setNextLocation(loc);
1441 	  message(InterpreterMessages::patternBadQualifierValue,
1442 	          ELObjMessageArg(value, *this),
1443 		  StringMessageArg(key->identifier()->name()));
1444 	  return 0;
1445 	}
1446 	curElement->addQualifier(new Pattern::ImportanceQualifier(n));
1447       }
1448       break;
1449     case Identifier::keyPriority:
1450       {
1451 	long n;
1452 	if (!value->exactIntegerValue(n)) {
1453 	  setNextLocation(loc);
1454 	  message(InterpreterMessages::patternBadQualifierValue,
1455 	          ELObjMessageArg(value, *this),
1456 		  StringMessageArg(key->identifier()->name()));
1457 	  return 0;
1458 	}
1459 	curElement->addQualifier(new Pattern::PriorityQualifier(n));
1460       }
1461       break;
1462     default:
1463       setNextLocation(loc);
1464       message(InterpreterMessages::patternUnknownQualifier,
1465 	      StringMessageArg(key->identifier()->name()));
1466       return 0;
1467     }
1468   }
1469   return 1;
1470 }
1471 
patternAddAttributeQualifiers(ELObj * obj,const Location & loc,Pattern::Element & elem)1472 bool Interpreter::patternAddAttributeQualifiers(ELObj *obj,
1473 						const Location &loc,
1474 						Pattern::Element &elem)
1475 {
1476   while (!obj->isNil()) {
1477     PairObj *pair = obj->asPair();
1478     if (!pair)
1479       return 0;
1480     StringObj *tem = pair->car()->convertToString();
1481     if (!tem)
1482       return 0;
1483     const Char *s;
1484     size_t n;
1485     tem->stringData(s, n);
1486     if (n == 0)
1487       return 0;
1488     StringC name(s, n);
1489     obj = pair->cdr();
1490     pair = obj->asPair();
1491     if (!pair)
1492       return 0;
1493     obj = pair->cdr();
1494     if (pair->car() == makeFalse() && dsssl2())
1495       elem.addQualifier(new Pattern::AttributeMissingValueQualifier(name));
1496     else if (pair->car() == makeTrue() && dsssl2())
1497       elem.addQualifier(new Pattern::AttributeHasValueQualifier(name));
1498     else {
1499       tem = pair->car()->convertToString();
1500       if (!tem)
1501 	return 0;
1502       tem->stringData(s, n);
1503       elem.addQualifier(new Pattern::AttributeQualifier(name, StringC(s, n)));
1504     }
1505   }
1506   return 1;
1507 }
1508 
dispatchMessage(Message & msg)1509 void Interpreter::dispatchMessage(Message &msg)
1510 {
1511   messenger_->dispatchMessage(msg);
1512 }
1513 
dispatchMessage(const Message & msg)1514 void Interpreter::dispatchMessage(const Message &msg)
1515 {
1516   messenger_->dispatchMessage(msg);
1517 }
1518 
StringSet()1519 Interpreter::StringSet::StringSet()
1520 {
1521 }
1522 
store(String<char> & str)1523 const char *Interpreter::StringSet::store(String<char> &str)
1524 {
1525   str += '\0';
1526   const String<char> *p = table_.lookup(str);
1527   if (!p) {
1528     String<char> *tem = new String<char>;
1529     str.swap(*tem);
1530     table_.insert(tem);
1531     p = tem;
1532   }
1533   return p->data();
1534 }
1535 
hash(const String<char> & str)1536 unsigned long Interpreter::StringSet::hash(const String<char> &str)
1537 {
1538   const char *p = str.data();
1539   unsigned long h = 0;
1540   for (size_t n = str.size(); n > 0; n--)
1541     h = (h << 5) + h + (unsigned char)*p++;	// from Chris Torek
1542   return h;
1543 }
1544 
Identifier(const StringC & name)1545 Identifier::Identifier(const StringC &name)
1546 : Named(name), value_(0), syntacticKey_(notKey), beingComputed_(0), flowObj_(0)
1547 {
1548 }
1549 
setDefinition(Owner<Expression> & expr,unsigned part,const Location & loc)1550 void Identifier::setDefinition(Owner<Expression> &expr,
1551 			       unsigned part,
1552 			       const Location &loc)
1553 {
1554   def_.swap(expr);
1555   defPart_ = part;
1556   defLoc_ = loc;
1557   value_ = 0;
1558 }
1559 
setValue(ELObj * value,unsigned partIndex)1560 void Identifier::setValue(ELObj *value, unsigned partIndex)
1561 {
1562   value_ = value;
1563   // Built in functions have lowest priority.
1564   defPart_ = partIndex;
1565 }
1566 
defined(unsigned & part,Location & loc) const1567 bool Identifier::defined(unsigned &part, Location &loc) const
1568 {
1569   if (!def_ && !value_)
1570     return 0;
1571   part = defPart_;
1572   loc = defLoc_;
1573   return 1;
1574 }
1575 
computeValue(bool force,Interpreter & interp) const1576 ELObj *Identifier::computeValue(bool force, Interpreter &interp) const
1577 {
1578   if (value_)
1579     return value_;
1580   ASSERT(def_);
1581   if (beingComputed_) {
1582     if (force) {
1583       interp.setNextLocation(defLoc_);
1584       interp.message(InterpreterMessages::identifierLoop,
1585 	             StringMessageArg(name()));
1586       ((Identifier *)this)->value_ = interp.makeError();
1587     }
1588   }
1589   else {
1590     ((Identifier *)this)->beingComputed_ = 1;
1591     if (insn_.isNull())
1592       ((Identifier *)this)->insn_
1593         = Expression::optimizeCompile(((Identifier *)this)->def_, interp,
1594 	                              Environment(), 0, InsnPtr());
1595     if (force || def_->canEval(0)) {
1596       VM vm(interp);
1597       ELObj *v = vm.eval(insn_.pointer());
1598       interp.makePermanent(v);
1599       ((Identifier *)this)->value_ = v;
1600     }
1601     ((Identifier *)this)->beingComputed_ = 0;
1602   }
1603   return value_;
1604 }
1605 
Unit(const StringC & name)1606 Unit::Unit(const StringC &name)
1607 : Named(name), computed_(notComputed)
1608 {
1609 }
1610 
defined(unsigned & part,Location & loc) const1611 bool Unit::defined(unsigned &part, Location &loc) const
1612 {
1613   if (!def_ && computed_ == notComputed)
1614     return 0;
1615   part = defPart_;
1616   loc = defLoc_;
1617   return 1;
1618 }
1619 
setDefinition(Owner<Expression> & expr,unsigned part,const Location & loc)1620 void Unit::setDefinition(Owner<Expression> &expr,
1621 			 unsigned part,
1622 			 const Location &loc)
1623 {
1624   def_.swap(expr);
1625   defPart_ = part;
1626   defLoc_ = loc;
1627   computed_ = notComputed;
1628 }
1629 
setValue(long n)1630 void Unit::setValue(long n)
1631 {
1632   computed_ = computedExact;
1633   exact_ = n;
1634   dim_ = 1;
1635   defPart_ = unsigned(-1);
1636 }
1637 
setValue(double n)1638 void Unit::setValue(double n)
1639 {
1640   computed_ = computedInexact;
1641   inexact_ = n;
1642   dim_ = 1;
1643   defPart_ = unsigned(-1);
1644 }
1645 
tryCompute(bool force,Interpreter & interp)1646 void Unit::tryCompute(bool force, Interpreter &interp)
1647 {
1648   if (computed_ == notComputed) {
1649     computed_ = beingComputed;
1650     if (insn_.isNull())
1651       insn_ = Expression::optimizeCompile(def_, interp, Environment(), 0, InsnPtr());
1652     if (force || def_->canEval(0)) {
1653       VM vm(interp);
1654       ELObj *v = vm.eval(insn_.pointer());
1655       switch (v->quantityValue(exact_, inexact_, dim_)) {
1656       case ELObj::noQuantity:
1657 	if (!interp.isError(v)) {
1658 	  interp.setNextLocation(defLoc_);
1659 	  interp.message(InterpreterMessages::badUnitDefinition,
1660 			 StringMessageArg(name()));
1661 	}
1662 	computed_ = computedError;
1663 	break;
1664       case ELObj::longQuantity:
1665 	computed_ = computedExact;
1666 	break;
1667       case ELObj::doubleQuantity:
1668 	computed_ = computedInexact;
1669 	break;
1670       default:
1671 	CANNOT_HAPPEN();
1672       }
1673     }
1674     if (computed_ == beingComputed)
1675       computed_ = notComputed;
1676   }
1677   else if (computed_ == beingComputed) {
1678     interp.setNextLocation(defLoc_);
1679     interp.message(InterpreterMessages::unitLoop,
1680 		   StringMessageArg(name()));
1681     computed_ = computedError;
1682   }
1683 }
1684 
1685 // multiply by 10^valExp
1686 // quantity has exponent of 1
1687 
resolveQuantity(bool force,Interpreter & interp,long val,int valExp)1688 ELObj *Unit::resolveQuantity(bool force, Interpreter &interp,
1689 			     long val, int valExp)
1690 {
1691   tryCompute(force, interp);
1692   long result;
1693   if (computed_ == computedExact && scale(val, valExp, exact_, result))
1694     return new (interp) LengthObj(result);
1695   double x = val;
1696   while (valExp > 0) {
1697     x *= 10.0;
1698     valExp--;
1699   }
1700   while (valExp < 0) {
1701     x /= 10.0;
1702     valExp++;
1703   }
1704   return resolveQuantity(force, interp, x, 1);
1705 }
1706 
1707 // val * 10^valExp * factor
1708 // return 0 if it can't be done without overflow
1709 
scale(long val,int valExp,long factor,long & result)1710 bool Unit::scale(long val, int valExp, long factor, long &result)
1711 {
1712   if (factor <= 0)
1713     return 0; // feeble
1714   while (valExp > 0) {
1715     if (factor > LONG_MAX/10)
1716       return 0;
1717     valExp--;
1718     factor *= 10;
1719   }
1720   if (val >= 0) {
1721     if (val > LONG_MAX/factor)
1722       return 0;
1723   }
1724   else {
1725     if (-(unsigned long)val > -(unsigned long)LONG_MIN/factor)
1726       return 0;
1727   }
1728   result = val*factor;
1729   while (valExp < 0) {
1730     result /= 10;
1731     valExp++;
1732   }
1733   return 1;
1734 }
1735 
resolveQuantity(bool force,Interpreter & interp,double val,int unitExp)1736 ELObj *Unit::resolveQuantity(bool force, Interpreter &interp,
1737 			     double val, int unitExp)
1738 {
1739   tryCompute(force, interp);
1740   double factor;
1741   switch (computed_) {
1742   case computedExact:
1743     factor = exact_;
1744     break;
1745   case computedInexact:
1746     factor = inexact_;
1747     break;
1748   case computedError:
1749     return interp.makeError();
1750   default:
1751     return 0;
1752   }
1753   int resultDim = 0;
1754   double resultVal = val;
1755   while (unitExp > 0) {
1756     resultDim += dim_;
1757     resultVal *= factor;
1758     unitExp--;
1759   }
1760   while (unitExp < 0) {
1761     resultDim -= dim_;
1762     resultVal /= factor;
1763     unitExp++;
1764   }
1765   if (resultDim == 0)
1766     return new (interp) RealObj(resultVal);
1767   return new (interp) QuantityObj(resultVal, resultDim);
1768 }
1769 
trace(Collector & c) const1770 void ELObjDynamicRoot::trace(Collector &c) const
1771 {
1772   c.trace(obj_);
1773 }
1774 
operator ==(const StringC & s,const char * p)1775 bool operator==(const StringC &s, const char *p)
1776 {
1777   for (size_t i = 0; i < s.size(); i++)
1778     if (p[i] == '\0' || (unsigned char)p[i] != s[i])
1779       return 0;
1780   return p[s.size()] == '\0';
1781 }
1782 
1783 #ifdef DSSSL_NAMESPACE
1784 }
1785 #endif
1786