]> matita.cs.unibo.it Git - helm.git/blob - helm/DEVEL/mathml_editor/src/LPushLexer.cc
C++ 3.2 aware changes
[helm.git] / helm / DEVEL / mathml_editor / src / LPushLexer.cc
1 /* This file is part of EdiTeX, an editor of mathematical
2  * expressions based on TeX syntax.
3  * 
4  * Copyright (C) 2002-2003 Luca Padovani <lpadovan@cs.unibo.it>,
5  *                    2003 Paolo Marinelli <pmarinel@cs.unibo.it>.
6  *
7  * This library is free software; you can redistribute it and/or
8  * modify it under the terms of the GNU Lesser General Public
9  * License as published by the Free Software Foundation; either
10  * version 2.1 of the License, or (at your option) any later version.
11  *
12  * This library 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 GNU
15  * Lesser General Public License for more details.
16  *
17  * You should have received a copy of the GNU Lesser General Public
18  * License along with this library; if not, write to the Free Software
19  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
20  *
21  * For more information, please visit the project's home page
22  * http://helm.cs.unibo.it/editex/
23  * or send an email to <lpadovan@cs.unibo.it>
24  */
25
26 #include <string>
27 #include <cctype>
28
29 #include "ALogger.hh"
30 #include "TToken.hh"
31 #include "LPushLexer.hh"
32 #include "APushParser.hh"
33
34 LPushLexer::LPushLexer(ALogger& l, APushParser& p) : APushLexer(l, p)
35 {
36   state = ACCEPT;
37 }
38
39 void
40 LPushLexer::reset()
41 {
42   buffer.erase();
43   state = ACCEPT;
44 }
45
46 void
47 LPushLexer::flush()
48 {
49   push(-1);
50 }
51
52 void
53 LPushLexer::transaction(char ch, State newState)
54 {
55   switch (ch)
56     {
57     case '{': parser.push(TToken(TToken::BEGIN)); break;
58     case '}': parser.push(TToken(TToken::END)); break;
59     case '$': parser.push(TToken(TToken::SHIFT)); break;
60     case '&': parser.push(TToken(TToken::ALIGN)); break;
61     case '\n':
62     case '\r': parser.push(TToken(TToken::EOL, ch)); break;
63     case '^': parser.push(TToken(TToken::SUPERSCRIPT)); break;
64     case '_': parser.push(TToken(TToken::SUBSCRIPT)); break;
65     case '\t': parser.push(TToken(TToken::IGNORABLE_SPACE, ch)); break;
66     case ' ': parser.push(TToken(TToken::SPACE, ch)); break;
67     case '~': parser.push(TToken(TToken::ACTIVE, ch)); break;
68     case '%': parser.push(TToken(TToken::COMMENT)); break;     
69     default: parser.push(TToken(TToken::OTHER, ch)); break;
70     }
71   state = newState;
72 }
73
74 void
75 LPushLexer::push(char ch)
76 {
77   switch (state)
78     {
79     case ACCEPT:
80       if (ch == '\\') state = ESCAPE;
81       else if (ch == '#') state = PARAMETER;
82       else if (ch == -1) ;
83       else if (isalpha(ch))
84         {
85           buffer.push_back(ch);
86           state = IDENTIFIER;
87         }
88       else if (isdigit(ch))
89         {
90           buffer.push_back(ch);
91           state = NUMBER;
92         }
93       else transaction(ch, ACCEPT);
94       break;
95     case ESCAPE:
96       if (isalpha(ch))
97         {
98           buffer.push_back(ch);
99           state = MACRO;
100         }
101       else if (ch == -1) error();
102       else if (isdigit(ch))
103         {
104           // in this case, the previous '\' is ignored
105           buffer.push_back(ch);
106           state = NUMBER;
107         }
108       else
109         {
110           parser.push(TToken(TToken::CONTROL, ch));
111           state = ACCEPT;
112         }
113       break;
114     case MACRO:
115       if (ch == '\\')
116         {
117           parser.push(TToken(TToken::CONTROL, buffer));
118           buffer.erase();
119           state = ESCAPE;
120         }
121       else if (ch == '#')
122         {
123           parser.push(TToken(TToken::CONTROL, buffer));
124           buffer.erase();
125           state = PARAMETER;
126         }
127       else if (isalpha(ch))
128         buffer.push_back(ch);
129       else if (ch == -1)
130         {
131           parser.push(TToken(TToken::CONTROL, buffer));
132           buffer.erase();
133           state = ACCEPT;
134         }
135       else if (isspace(ch))
136           {
137             // we don't call transaction, because a white space is useful to exit from the macro,
138             // without "side effect". It's the TeX syntax.
139             parser.push(TToken(TToken::CONTROL, buffer));
140             buffer.erase();
141             state = ACCEPT;
142         }
143       else if (isdigit(ch))
144         {
145           parser.push(TToken(TToken::CONTROL, buffer));
146           buffer.erase();
147           buffer.push_back(ch);
148           state = NUMBER;
149         }
150       else
151         {
152           parser.push(TToken(TToken::CONTROL, buffer));
153           buffer.erase();
154           transaction(ch, ACCEPT);
155         }
156       break;
157     case PARAMETER:
158       if (ch == -1) error();
159       else
160         {
161           parser.push(TToken(TToken::PARAMETER, ch));
162           state = ACCEPT;
163         }
164       break;
165     case IDENTIFIER:
166       if (ch == -1)
167         {
168           parser.push(TToken(TToken::LETTER, buffer));
169           buffer.erase();
170           state = ACCEPT;
171         }
172       else if (isalpha(ch) || isdigit(ch))
173         {
174           buffer.push_back(ch);
175         }
176       else if (ch == '\\') state = ESCAPED_CHARACTER;
177       else if (ch == '#')
178         {
179           parser.push(TToken(TToken::LETTER, buffer));
180           buffer.erase();
181           state = PARAMETER;
182         }
183       else
184         {
185           parser.push(TToken(TToken::LETTER, buffer));
186           buffer.erase();
187           transaction(ch, ACCEPT);
188         }
189       break;
190     case ESCAPED_CHARACTER:
191       if ((ch == '-') || (ch == '_'))
192         {
193           buffer.push_back(ch);
194           state = IDENTIFIER;
195         }
196       else if (isalpha(ch))
197         {
198           parser.push(TToken(TToken::LETTER, buffer));
199           buffer.erase();
200           buffer.push_back(ch);
201           state = MACRO;
202         }
203       else if (ch == -1) error();
204       else if (isdigit(ch))
205         {
206           parser.push(TToken(TToken::LETTER, buffer));
207           buffer.erase();
208           buffer.push_back(ch);
209           state = NUMBER;
210         }
211       else
212         {
213           parser.push(TToken(TToken::LETTER, buffer));
214           buffer.erase();
215           parser.push(TToken(TToken::CONTROL, ch));
216           state = ACCEPT;
217         }
218       break;
219     case NUMBER:
220       if (isdigit(ch)) buffer.push_back(ch);
221       else if (isalpha(ch))
222         {
223           parser.push(TToken(TToken::DIGIT, buffer));
224           buffer.erase();
225           buffer.push_back(ch);
226           state = IDENTIFIER;
227         }
228       else if (ch == -1)
229         {
230           parser.push(TToken(TToken::DIGIT, buffer));
231           buffer.erase();
232           state = ACCEPT;
233         }
234       else if (ch == '\\')
235         {
236           parser.push(TToken(TToken::DIGIT, buffer));
237           buffer.erase();
238           state = ESCAPE;
239         }
240       else if (ch == '#')
241         {
242           parser.push(TToken(TToken::DIGIT, buffer));
243           buffer.erase();
244           state = PARAMETER;
245         }
246       else
247         {
248           parser.push(TToken(TToken::DIGIT, buffer));
249           buffer.erase();
250           transaction(ch, ACCEPT);
251         }
252       break;
253     default:
254       assert(0);
255       break;
256     }
257
258   displayCursor();
259
260 }
261
262 void
263 LPushLexer::drop(bool alt)
264 {
265   std::string restore = "";
266
267   switch (state)
268     {
269     case ACCEPT:
270       {
271         restore = parser.drop(alt);
272         long bs_pos = restore.find('\\');
273         if ((restore.length() > 0) && (bs_pos != std::string::npos))
274           {
275             // in this case we have to control the blackslash's position
276             if (bs_pos == 0)
277               {
278                 //logger.debug(restore);
279                 buffer = std::string(restore, 1, restore.length() - 1);
280                 state = (buffer.length() > 0) ? MACRO : ESCAPE;
281               }
282             else
283               {
284                 assert(bs_pos == restore.length() - 1);
285                 buffer = std::string(restore, 0, bs_pos);
286                 state = ESCAPED_CHARACTER;
287               }
288           }
289         else if (restore.length() > 0 && isdigit(restore[0]))
290           {
291             buffer = restore;
292             state = NUMBER;
293           }
294         else if (restore.length() > 0 && isalpha(restore[0]))
295           {
296             buffer = restore;
297             state = IDENTIFIER;
298           }
299       }
300       break;
301 /*      if (restore.length() > 0 && restore[0] == '\\')
302         {
303           logger.debug(restore);
304           buffer = std::string(restore, 1, restore.length() - 1);
305           state = (buffer.length() > 0) ? MACRO : ESCAPE;
306         }
307       else if (restore.length() > 0 && isdigit(restore[0]))
308         {
309           buffer = restore;
310           state = NUMBER;
311         }
312       else if (restore.length() > 0 && isalpha(restore[0]))
313         {
314           buffer = restore;
315           state = IDENTIFIER;
316         }
317       break;*/
318     case ESCAPED_CHARACTER:
319       state = IDENTIFIER;
320       break;
321     case ESCAPE:
322       state = ACCEPT;
323       break;
324     case MACRO:
325       if (alt) buffer.erase();
326       else buffer.erase(buffer.length() - 1, 1);
327       if (buffer.length() == 0) state = ESCAPE;
328       break;
329     case IDENTIFIER:
330       switch (buffer[buffer.length() - 1])
331         {
332         case '-':
333         case '_':
334           buffer.erase(buffer.length() - 1, 1);
335           if (alt) state = ESCAPED_CHARACTER;
336           break;
337         default:
338           if (alt) buffer.erase(); 
339           else buffer.erase(buffer.length() - 1, 1);
340           if (buffer.length() == 0) state = ACCEPT;
341           break;
342         }
343       break;
344     case NUMBER:
345       if (alt) buffer.erase();
346       else buffer.erase(buffer.length() - 1, 1);
347       if (buffer.length() == 0) state = ACCEPT;
348       break;
349     case PARAMETER:
350     default:
351       //assert(0);
352       error();
353       break;
354     }
355
356   displayCursor();
357
358 }
359
360 void
361 LPushLexer::displayCursor()
362 {
363   switch (state)
364     {
365     case ESCAPE: parser.setCursorHint("\\"); break;
366     case ESCAPED_CHARACTER: parser.setCursorHint(buffer + "\\"); break;
367     case MACRO: parser.setCursorHint("\\" + buffer); break;
368     case PARAMETER: parser.setCursorHint("#"); break;
369     case IDENTIFIER: parser.setCursorHint(buffer); break;
370     case NUMBER: parser.setCursorHint(buffer); break;
371     default: parser.setCursorHint(""); break;
372     }
373 }
374
375 bool
376 LPushLexer::error() const
377 {
378   return false;
379 }