]> matita.cs.unibo.it Git - helm.git/blob - helm/DEVEL/mathml_editor/src/TDictionary.cc
* added license and copyright to every source file
[helm.git] / helm / DEVEL / mathml_editor / src / TDictionary.cc
1 /* Copyright (C) 2002-2003, Luca Padovani <luca.padovani@cs.unibo.it>,
2  *                    2003, Paolo Marinelli <pmarinel@cs.unibo.it>.
3  *
4  * This file is part of EdiTeX, an editor of mathematical
5  * expressions based on TeX syntax
6  * 
7  * EdiTeX is free software; you can redistribute it and/or
8  * modify it under the terms of the GNU General Public License
9  * as published by the Free Software Foundation; either version 2
10  * of the License, or (at your option) any later version.
11  *
12  * EdiTeX is distributed in the hope that it will be useful,
13  * but WITHOUT ANY WARRANTY; without even the implied warranty of
14  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15  * GNU General Public License for more details.
16  *
17  * You should have received a copy of the GNU General Public License
18  * along with EdiTeX; if not, write to the Free Software
19  * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
20  * 
21  * For details, see the EdiTeX World-Wide-Web page,
22  * http://helm.cs.unibo.it/editex, or send a mail to
23  * <luca.padovani@cs.unibo.it>
24  */
25
26 #include <sstream>
27
28 #include "dom.hh"
29 #include "TDictionary.hh"
30 #include "TTokenizer.hh"
31 #include "CLoggerConsole.hh"
32
33 static TDictionary::Entry undefinedEntry;
34
35 static std::string
36 getURIBase(const std::string& uri)
37 {
38   std::string::size_type slash = uri.rfind('/');
39   if (slash != std::string::npos) return uri.substr(0, slash + 1);
40   else return "";
41 }
42
43 static std::string
44 getURIName(const std::string& uri)
45 {
46   std::string::size_type slash = uri.rfind('/');
47   if (slash != std::string::npos) return uri.substr(slash + 1, uri.size());
48   else return uri;
49 }
50
51 void
52 TDictionary::load(const std::string& uri)
53 {
54   load(getURIName(uri), getURIBase(uri));
55 }
56
57 void
58 TDictionary::load(const std::string& name, const std::string& base)
59 {
60   logger.debug("Dictionary: loading `" + base + name + "'");
61
62   DOM::DOMImplementation di;
63   DOM::Document doc = di.createDocumentFromURI((base + name).c_str());
64   assert(doc);
65   load(doc, base);
66 }
67
68 void
69 TDictionary::load(const DOM::Document& doc, const std::string& base)
70 {
71   assert(doc);
72
73   DOM::Element root = doc.get_documentElement();
74   assert(root);
75
76   CLoggerConsole logger;
77   TTokenizer tokenizer(logger);
78
79   for (DOM::Node p = root.get_firstChild(); p; p = p.get_nextSibling())
80     if (p.get_nodeType() == DOM::Node::ELEMENT_NODE && p.get_nodeName() == "include")
81       {
82         DOM::Element el = p;
83         assert(el);
84         if (el.hasAttribute("href"))
85           {
86             // WARNING: this may result into an infinite loop!
87             std::string href = el.getAttribute("href");
88             std::string newBase = getURIBase(href);
89             std::string newName = getURIName(href);
90             if (newBase != "") load(newName, newBase);
91             else load(newName, base);
92           }
93         else
94           logger.warning("Dictionary: include statement with no href attribute (ignored)");
95       }
96     else if (p.get_nodeType() == DOM::Node::ELEMENT_NODE && p.get_nodeName() == "entry")
97       {
98         DOM::Element el = p;
99         assert(el);
100         assert(el.hasAttribute("name"));
101
102         std::string name = el.getAttribute("name");
103         if (entries.find(name) != entries.end())
104           logger.info("Dictionary: `" + name + "' is being redefined");
105
106         Entry entry;
107
108         if (el.hasAttribute("class"))
109           {
110             std::string cls = el.getAttribute("class");
111             if (cls == "o") entry.cls = OPERATOR;
112             else if (cls == "i") entry.cls = IDENTIFIER;
113             else if (cls == "n") entry.cls == NUMBER;
114             else entry.cls = MACRO;
115           }
116         else
117           entry.cls = MACRO;
118
119         if (el.hasAttribute("val"))
120           {
121             entry.value = el.getAttribute("val");
122             if (entry.cls == MACRO)
123               logger.warning("Dictionary: `" + name + "' has a specified value, but is classified as macro");
124           }
125
126         if (el.hasAttribute("pattern"))
127           {
128             if (entry.cls != MACRO)
129               logger.warning("Dictionary: `" + name + "' has a specified pattern, but is not classified as macro");
130
131             std::string pattern = el.getAttribute("pattern");
132             if (pattern == "{}")
133               entry.leftOpen = entry.rightOpen = 1;
134             else if (pattern == "{")
135               entry.leftOpen = 1;
136             else if (pattern == "}")
137               entry.rightOpen = 1;
138             else
139               entry.pattern = tokenizer.tokenize(pattern);
140           }
141
142 #if 0
143         if (el.hasAttribute("infix"))
144           {
145             std::istringstream is(el.getAttribute("infix"));
146             unsigned infix;
147             is >> infix;
148             entry.infix = infix;
149             if (!el.hasAttribute("prefix")) entry.prefix = infix;
150             if (!el.hasAttribute("postfix")) entry.postfix = infix;
151           }
152
153         if (el.hasAttribute("prefix"))
154           {
155             std::istringstream is(el.getAttribute("prefix"));
156             unsigned prefix;
157             is >> prefix;
158             entry.prefix = prefix;
159             if (!el.hasAttribute("infix"))
160               {
161                 entry.infix = prefix;
162                 if (!el.hasAttribute("postfix")) entry.postfix = prefix;
163               }
164           }
165
166         if (el.hasAttribute("postfix"))
167           {
168             std::istringstream is(el.getAttribute("postfix"));
169             unsigned postfix;
170             is >> postfix;
171             entry.postfix = postfix;
172             if (!el.hasAttribute("infix"))
173               {
174                 entry.infix = postfix;
175                 if (!el.hasAttribute("prefix")) entry.prefix = postfix;
176               }
177           }
178 #endif
179
180         if (el.hasAttribute("limits"))
181           {
182             std::istringstream is(el.getAttribute("limits"));
183             unsigned limits;
184             is >> limits;
185             entry.limits = limits;
186           }
187
188         if (el.hasAttribute("embellishment"))
189           {
190             std::istringstream is(el.getAttribute("embellishment"));
191             unsigned embellishment;
192             is >> embellishment;
193             entry.embellishment = embellishment;
194           }
195
196         if (el.hasAttribute("delimiter"))
197           {
198             if (entry.cls != OPERATOR && !entry.embellishment)
199               logger.warning("Dictionary: `" + name + "' delimiter ignored for non-operator");
200
201             std::istringstream is(el.getAttribute("delimiter"));
202             unsigned delimiter;
203             is >> delimiter;
204             entry.delimiter = delimiter;
205           }
206
207         if (el.hasAttribute("table"))
208           {
209             if (entry.cls != MACRO)
210               logger.warning("Dictionary: `" + name + "' table ignored for non-macro");
211
212             std::istringstream is(el.getAttribute("table"));
213             unsigned table;
214             is >> table;
215             entry.table = table;
216           }
217
218         entries[name] = entry;
219       }
220 }
221
222 const TDictionary::Entry&
223 TDictionary::find(const std::string& name) const
224 {
225   Dictionary::const_iterator p = entries.find(name);
226   if (p != entries.end()) return (*p).second;
227   else
228     {
229       cerr << "ERROR: unknown entry `" << name << "'" << endl;
230       return undefinedEntry;
231     }
232 }
233
234 bool
235 TDictionary::Entry::paramDelimited(unsigned i) const
236 {
237   assert(i < pattern.size());
238   assert(pattern[i].category == TToken::PARAMETER);
239   // a parameter is delimited if it is NOT the last one
240   // AND the next argument is not a parameter
241   return i + 1 < pattern.size() && pattern[i + 1].category != TToken::PARAMETER;
242 }
243
244 bool
245 TDictionary::Entry::lastDelimiter(unsigned i) const
246 {
247   assert(i < pattern.size());
248   assert(pattern[i].category != TToken::PARAMETER);
249   // a token is the last delimiter if it is the last token 
250   // of the pattern or if the next token is a parameter)
251   return i + 1 == pattern.size() || pattern[i + 1].category == TToken::PARAMETER;
252 }
253
254 unsigned
255 TDictionary::Entry::previousParam(unsigned i) const
256 {
257   // this method return the position in the pattern of the 
258   // parameter placed in a position preceding i.
259   // If no preceding i parameter present, the method return
260   // pattern.size().
261   // To know the position of the last parameter, call this 
262   // method with i == pattern.size()
263   unsigned j = i - 1;
264
265   while (pattern[j].category != TToken::PARAMETER)
266     {
267       if (j) j--;
268       else return pattern.size();
269     }
270   return j;
271 }