]> matita.cs.unibo.it Git - helm.git/blob - helm/DEVEL/mathml_editor/src/LPushLexer.cc
Bug fixed. In the previous version, all right open macros and all delimited arguments
[helm.git] / helm / DEVEL / mathml_editor / src / LPushLexer.cc
1
2 #include "TToken.hh"
3 #include "LPushLexer.hh"
4 #include "APushParser.hh"
5
6 LPushLexer::LPushLexer(ALogger& l, APushParser& p) : APushLexer(l, p)
7 {
8   state = ACCEPT;
9 }
10
11 void
12 LPushLexer::reset()
13 {
14   buffer.erase();
15   state = ACCEPT;
16 }
17
18 void
19 LPushLexer::flush()
20 {
21   push(-1);
22 }
23
24 void
25 LPushLexer::transaction(char ch, State newState)
26 {
27   switch (ch)
28     {
29     case '{': parser.push(TToken(TToken::BEGIN)); break;
30     case '}': parser.push(TToken(TToken::END)); break;
31     case '$': parser.push(TToken(TToken::SHIFT)); break;
32     case '&': parser.push(TToken(TToken::ALIGN)); break;
33     case '\n':
34     case '\r': parser.push(TToken(TToken::EOL, ch)); break;
35     case '^': parser.push(TToken(TToken::SUPERSCRIPT)); break;
36     case '_': parser.push(TToken(TToken::SUBSCRIPT)); break;
37     case '\t':
38     case ' ': parser.push(TToken(TToken::SPACE, ch)); break;
39     case '~': parser.push(TToken(TToken::ACTIVE, ch)); break;
40     case '%': parser.push(TToken(TToken::COMMENT)); break;     
41     default:
42       if (isalpha(ch)) parser.push(TToken(TToken::LETTER, ch));
43       else if (isdigit(ch)) parser.push(TToken(TToken::DIGIT, ch));
44       else parser.push(TToken(TToken::OTHER, ch));
45       break;
46     }
47   state = newState;
48 }
49
50 void
51 LPushLexer::push(char ch)
52 {
53   switch (state)
54     {
55     case ACCEPT:
56       if (ch == '\\') state = ESCAPE;
57       else if (ch == '#') state = PARAMETER;
58       else if (ch == -1) ;
59       else if (isalpha(ch))
60         {
61           buffer.push_back(ch);
62           state = LONG_IDENTIFIER;
63         }
64       else transaction(ch, ACCEPT);
65       break;
66     case ESCAPE:
67       if (isalpha(ch))
68         {
69           buffer.push_back(ch);
70           state = MACRO;
71         }
72       else if (ch == -1) error();
73       else
74         {
75           parser.push(TToken(TToken::CONTROL, ch));
76           state = ACCEPT;
77         }
78       break;
79     case MACRO:
80       if (ch == '\\')
81         {
82           parser.push(TToken(TToken::CONTROL, buffer));
83           buffer.erase();
84           state = ESCAPE;
85         }
86       else if (ch == '#')
87         {
88           parser.push(TToken(TToken::CONTROL, buffer));
89           buffer.erase();
90           state = PARAMETER;
91         }
92       else if (isalpha(ch))
93         buffer.push_back(ch);
94       else if (ch == -1)
95         {
96           parser.push(TToken(TToken::CONTROL, buffer));
97           buffer.erase();
98           state = ACCEPT;
99         }
100       else
101         {
102           parser.push(TToken(TToken::CONTROL, buffer));
103           buffer.erase();
104           if (isspace(ch)) state = IGNORE_SPACE;
105           else transaction(ch, ACCEPT);
106         }
107       break;
108     case IGNORE_SPACE:
109       if (ch == '\\') state = ESCAPE;
110       else if (ch == '#') state = PARAMETER;
111       else if (isspace(ch)) ;
112       else if (ch == -1) state = ACCEPT;
113       else if (isalpha(ch))
114         {
115           buffer.push_back(ch);
116           state = LONG_IDENTIFIER;
117         }
118       else transaction(ch, ACCEPT);
119       break;
120     case PARAMETER:
121       if (ch == -1) error();
122       else
123         {
124           parser.push(TToken(TToken::PARAMETER, ch));
125           state = ACCEPT;
126         }
127       break;
128     case LONG_IDENTIFIER:
129       if (ch == -1)
130         {
131           parser.push(TToken(TToken::LETTER, buffer));
132           buffer.erase();
133           state = ACCEPT;
134         }
135       else if (isalpha(ch) || isdigit(ch))
136         {
137           buffer.push_back(ch);
138         }
139       else if (isspace(ch))
140         {
141           parser.push(TToken(TToken::LETTER, buffer));
142
143           // the parser ignores spaces. But in this case, the space 
144           // is a significant. So, we transform this space in the MACRO 
145           // \; which will not be ignored. 
146           // This is not a good solution. Having a special token, that will be 
147           // interpreted as "function application" is a better one.
148           buffer.erase();
149           buffer = ";";
150           parser.push(TToken(TToken::CONTROL, buffer));
151           buffer.erase();
152           state = IGNORE_SPACE;
153         }
154       else if (ch == '\\')
155         {
156           parser.push(TToken(TToken::LETTER, buffer));
157           buffer.erase();
158           state = ESCAPE;
159         }
160       else
161         {
162           parser.push(TToken(TToken::LETTER, buffer));
163           buffer.erase();
164           transaction(ch, ACCEPT);
165         }
166       break;
167     default:
168       assert(0);
169       break;
170     }
171
172   switch (state)
173     {
174     case ESCAPE: parser.setCursorHint("\\"); break;
175     case MACRO: parser.setCursorHint("\\" + buffer); break;
176     case PARAMETER: parser.setCursorHint("#"); break;
177     case LONG_IDENTIFIER: parser.setCursorHint(buffer); break;
178     default: parser.setCursorHint(""); break;
179     }
180 }
181
182 void
183 LPushLexer::drop(bool alt)
184 {
185   std::string restore = "";
186
187   switch (state)
188     {
189     case ACCEPT:
190     case IGNORE_SPACE:
191       restore = parser.drop();
192       if (restore.length() > 0 && restore[0] == '\\')
193         {
194           buffer = std::string(restore, 1, restore.length() - 1);
195           state = (buffer.length() > 0) ? MACRO : ESCAPE;
196         }
197       break;
198     case ESCAPE:
199       state = ACCEPT;
200       break;
201     case MACRO:
202       if (alt) buffer.erase();
203       else buffer.erase(buffer.length() - 1, 1);
204       if (buffer.length() == 0) state = ESCAPE;
205       break;
206     case LONG_IDENTIFIER:
207       buffer.erase(buffer.length() - 1, 1);
208       if (buffer.length() == 0) state = ACCEPT;
209       break;
210     case PARAMETER:
211     default:
212       assert(0);
213       break;
214     }
215
216   switch (state)
217     {
218     case ESCAPE: parser.setCursorHint("\\"); break;
219     case MACRO: parser.setCursorHint("\\" + buffer); break;
220     case PARAMETER: parser.setCursorHint("#"); break;
221     default: parser.setCursorHint(""); break;
222     }
223 }
224
225 bool
226 LPushLexer::error() const
227 {
228   return false;
229 }