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