]> matita.cs.unibo.it Git - helm.git/blob - helm/DEVEL/mathml_editor/src/LPushLexer.cc
New version 0.0.2:
[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   displayCursor();
46 }
47
48 void
49 LPushLexer::flush()
50 {
51   push(-1);
52 }
53
54 void
55 LPushLexer::transaction(char ch, State newState)
56 {
57   switch (ch)
58     {
59     case '{': parser.push(TToken(TToken::BEGIN)); break;
60     case '}': parser.push(TToken(TToken::END)); break;
61     case '$': parser.push(TToken(TToken::SHIFT)); break;
62     case '&': parser.push(TToken(TToken::ALIGN)); break;
63     case '\n':
64     case '\r': parser.push(TToken(TToken::EOL, ch)); break;
65     case '^': parser.push(TToken(TToken::SUPERSCRIPT)); break;
66     case '_': parser.push(TToken(TToken::SUBSCRIPT)); break;
67     case '\t': parser.push(TToken(TToken::IGNORABLE_SPACE, ch)); break;
68     case ' ': parser.push(TToken(TToken::SPACE, ch)); break;
69     case '~': parser.push(TToken(TToken::ACTIVE, ch)); break;
70     case '%': parser.push(TToken(TToken::COMMENT)); break;     
71     default: parser.push(TToken(TToken::OTHER, ch)); break;
72     }
73   state = newState;
74 }
75
76 void
77 LPushLexer::push(char ch)
78 {
79   switch (state)
80     {
81     case ACCEPT:
82       if (ch == '\\') state = ESCAPE;
83       else if (ch == '#') state = PARAMETER;
84       else if (ch == -1) ;
85       else if (isalpha(ch))
86         {
87           buffer.push_back(ch);
88           state = IDENTIFIER;
89         }
90       else if (isdigit(ch))
91         {
92           buffer.push_back(ch);
93           state = NUMBER;
94         }
95       else transaction(ch, ACCEPT);
96       break;
97     case ESCAPE:
98       if (isalpha(ch))
99         {
100           buffer.push_back(ch);
101           state = MACRO;
102         }
103       else if (ch == -1) error();
104       else if (isdigit(ch))
105         {
106           // in this case, the previous '\' is ignored
107           buffer.push_back(ch);
108           state = NUMBER;
109         }
110       else
111         {
112           parser.push(TToken(TToken::CONTROL, ch));
113           state = ACCEPT;
114         }
115       break;
116     case MACRO:
117       if (ch == '\\')
118         {
119           parser.push(TToken(TToken::CONTROL, buffer));
120           buffer.erase();
121           state = ESCAPE;
122         }
123       else if (ch == '#')
124         {
125           parser.push(TToken(TToken::CONTROL, buffer));
126           buffer.erase();
127           state = PARAMETER;
128         }
129       else if (isalpha(ch))
130         buffer.push_back(ch);
131       else if (ch == -1)
132         {
133           parser.push(TToken(TToken::CONTROL, buffer));
134           buffer.erase();
135           state = ACCEPT;
136         }
137       else if (isspace(ch))
138           {
139             // we don't call transaction, because a white space is useful to exit from the macro,
140             // without "side effect". It's the TeX syntax.
141             parser.push(TToken(TToken::CONTROL, buffer));
142             buffer.erase();
143             state = ACCEPT;
144         }
145       else if (isdigit(ch))
146         {
147           parser.push(TToken(TToken::CONTROL, buffer));
148           buffer.erase();
149           buffer.push_back(ch);
150           state = NUMBER;
151         }
152       else
153         {
154           parser.push(TToken(TToken::CONTROL, buffer));
155           buffer.erase();
156           transaction(ch, ACCEPT);
157         }
158       break;
159     case PARAMETER:
160       if (ch == -1) error();
161       else
162         {
163           parser.push(TToken(TToken::PARAMETER, ch));
164           state = ACCEPT;
165         }
166       break;
167     case IDENTIFIER:
168       if (ch == -1)
169         {
170           parser.push(TToken(TToken::LETTER, buffer));
171           buffer.erase();
172           state = ACCEPT;
173         }
174       else if (isalpha(ch) || isdigit(ch))
175         {
176           buffer.push_back(ch);
177         }
178       else if (ch == '\\') state = ESCAPED_CHARACTER;
179       else if (ch == '#')
180         {
181           parser.push(TToken(TToken::LETTER, buffer));
182           buffer.erase();
183           state = PARAMETER;
184         }
185       else
186         {
187           parser.push(TToken(TToken::LETTER, buffer));
188           buffer.erase();
189           transaction(ch, ACCEPT);
190         }
191       break;
192     case ESCAPED_CHARACTER:
193       if ((ch == '-') || (ch == '_') || (ch == '/'))
194         {
195           buffer.push_back(ch);
196           state = IDENTIFIER;
197         }
198       else if (isalpha(ch))
199         {
200           parser.push(TToken(TToken::LETTER, buffer));
201           buffer.erase();
202           buffer.push_back(ch);
203           state = MACRO;
204         }
205       else if (ch == -1) error();
206       else if (isdigit(ch))
207         {
208           parser.push(TToken(TToken::LETTER, buffer));
209           buffer.erase();
210           buffer.push_back(ch);
211           state = NUMBER;
212         }
213       else
214         {
215           parser.push(TToken(TToken::LETTER, buffer));
216           buffer.erase();
217           parser.push(TToken(TToken::CONTROL, ch));
218           state = ACCEPT;
219         }
220       break;
221     case NUMBER:
222       if (isdigit(ch)) buffer.push_back(ch);
223       else if (isalpha(ch))
224         {
225           parser.push(TToken(TToken::DIGIT, buffer));
226           buffer.erase();
227           buffer.push_back(ch);
228           state = IDENTIFIER;
229         }
230       else if (ch == -1)
231         {
232           parser.push(TToken(TToken::DIGIT, buffer));
233           buffer.erase();
234           state = ACCEPT;
235         }
236       else if (ch == '\\')
237         {
238           parser.push(TToken(TToken::DIGIT, buffer));
239           buffer.erase();
240           state = ESCAPE;
241         }
242       else if (ch == '#')
243         {
244           parser.push(TToken(TToken::DIGIT, buffer));
245           buffer.erase();
246           state = PARAMETER;
247         }
248       else
249         {
250           parser.push(TToken(TToken::DIGIT, buffer));
251           buffer.erase();
252           transaction(ch, ACCEPT);
253         }
254       break;
255     default:
256       assert(0);
257       break;
258     }
259
260   displayCursor();
261
262 }
263
264 void
265 LPushLexer::drop(bool alt)
266 {
267   std::string restore = "";
268
269   switch (state)
270     {
271     case ACCEPT:
272       {
273         restore = parser.drop(alt);
274         long bs_pos = restore.find('\\');
275         if ((restore.length() > 0) && (bs_pos != std::string::npos))
276           {
277             // in this case we have to control the blackslash's position
278             if (bs_pos == 0)
279               {
280                 //logger.debug(restore);
281                 buffer = std::string(restore, 1, restore.length() - 1);
282                 state = (buffer.length() > 0) ? MACRO : ESCAPE;
283               }
284             else
285               {
286                 assert(bs_pos == restore.length() - 1);
287                 buffer = std::string(restore, 0, bs_pos);
288                 state = ESCAPED_CHARACTER;
289               }
290           }
291         else if (restore.length() > 0 && isdigit(restore[0]))
292           {
293             buffer = restore;
294             state = NUMBER;
295           }
296         else if (restore.length() > 0 && isalpha(restore[0]))
297           {
298             buffer = restore;
299             state = IDENTIFIER;
300           }
301       }
302       break;
303 /*      if (restore.length() > 0 && restore[0] == '\\')
304         {
305           logger.debug(restore);
306           buffer = std::string(restore, 1, restore.length() - 1);
307           state = (buffer.length() > 0) ? MACRO : ESCAPE;
308         }
309       else if (restore.length() > 0 && isdigit(restore[0]))
310         {
311           buffer = restore;
312           state = NUMBER;
313         }
314       else if (restore.length() > 0 && isalpha(restore[0]))
315         {
316           buffer = restore;
317           state = IDENTIFIER;
318         }
319       break;*/
320     case ESCAPED_CHARACTER:
321       state = IDENTIFIER;
322       break;
323     case ESCAPE:
324       state = ACCEPT;
325       break;
326     case MACRO:
327       if (alt) buffer.erase();
328       else buffer.erase(buffer.length() - 1, 1);
329       if (buffer.length() == 0) state = ESCAPE;
330       break;
331     case IDENTIFIER:
332       switch (buffer[buffer.length() - 1])
333         {
334         case '-':
335         case '_':
336           buffer.erase(buffer.length() - 1, 1);
337           if (alt) state = ESCAPED_CHARACTER;
338           break;
339         default:
340           if (alt) buffer.erase(); 
341           else buffer.erase(buffer.length() - 1, 1);
342           if (buffer.length() == 0) state = ACCEPT;
343           break;
344         }
345       break;
346     case NUMBER:
347       if (alt) buffer.erase();
348       else buffer.erase(buffer.length() - 1, 1);
349       if (buffer.length() == 0) state = ACCEPT;
350       break;
351     case PARAMETER:
352     default:
353       //assert(0);
354       error();
355       break;
356     }
357
358   displayCursor();
359
360 }
361
362 void
363 LPushLexer::displayCursor()
364 {
365   switch (state)
366     {
367     case ESCAPE: parser.setCursorHint("\\"); break;
368     case ESCAPED_CHARACTER: parser.setCursorHint(buffer + "\\"); break;
369     case MACRO: parser.setCursorHint("\\" + buffer); break;
370     case PARAMETER: parser.setCursorHint("#"); break;
371     case IDENTIFIER: parser.setCursorHint(buffer); break;
372     case NUMBER: parser.setCursorHint(buffer); break;
373     default: parser.setCursorHint(""); break;
374     }
375 }
376
377 bool
378 LPushLexer::error() const
379 {
380   return false;
381 }