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