--- /dev/null
+
+#include "TToken.hh"
+#include "LPushLexer.hh"
+#include "APushParser.hh"
+
+LPushLexer::LPushLexer(ALogger& l, APushParser& p) : APushLexer(l, p)
+{
+ state = ACCEPT;
+}
+
+void
+LPushLexer::reset()
+{
+ buffer.erase();
+ state = ACCEPT;
+}
+
+void
+LPushLexer::flush()
+{
+ push(-1);
+}
+
+void
+LPushLexer::transaction(char ch, State newState)
+{
+ switch (ch)
+ {
+ case '{': parser.push(TToken(TToken::BEGIN)); break;
+ case '}': parser.push(TToken(TToken::END)); break;
+ case '$': parser.push(TToken(TToken::SHIFT)); break;
+ case '&': parser.push(TToken(TToken::ALIGN)); break;
+ case '\n':
+ case '\r': parser.push(TToken(TToken::EOL, ch)); break;
+ case '^': parser.push(TToken(TToken::SUPERSCRIPT)); break;
+ case '_': parser.push(TToken(TToken::SUBSCRIPT)); break;
+ case '\t':
+ case ' ': parser.push(TToken(TToken::SPACE, ch)); break;
+ case '~': parser.push(TToken(TToken::ACTIVE, ch)); break;
+ case '%': parser.push(TToken(TToken::COMMENT)); break;
+ default:
+ if (isalpha(ch)) parser.push(TToken(TToken::LETTER, ch));
+ else if (isdigit(ch)) parser.push(TToken(TToken::DIGIT, ch));
+ else parser.push(TToken(TToken::OTHER, ch));
+ break;
+ }
+ state = newState;
+}
+
+void
+LPushLexer::push(char ch)
+{
+ switch (state)
+ {
+ case ACCEPT:
+ if (ch == '\\') state = ESCAPE;
+ else if (ch == '#') state = PARAMETER;
+ else if (ch == -1) ;
+ else if (isalpha(ch))
+ {
+ buffer.push_back(ch);
+ state = LONG_IDENTIFIER;
+ }
+ else transaction(ch, ACCEPT);
+ break;
+ case ESCAPE:
+ if (isalpha(ch))
+ {
+ buffer.push_back(ch);
+ state = MACRO;
+ }
+ else if (ch == -1) error();
+ else
+ {
+ parser.push(TToken(TToken::CONTROL, ch));
+ state = ACCEPT;
+ }
+ break;
+ case MACRO:
+ if (ch == '\\')
+ {
+ parser.push(TToken(TToken::CONTROL, buffer));
+ buffer.erase();
+ state = ESCAPE;
+ }
+ else if (ch == '#')
+ {
+ parser.push(TToken(TToken::CONTROL, buffer));
+ buffer.erase();
+ state = PARAMETER;
+ }
+ else if (isalpha(ch))
+ buffer.push_back(ch);
+ else if (ch == -1)
+ {
+ parser.push(TToken(TToken::CONTROL, buffer));
+ buffer.erase();
+ state = ACCEPT;
+ }
+ else
+ {
+ parser.push(TToken(TToken::CONTROL, buffer));
+ buffer.erase();
+ if (isspace(ch)) state = IGNORE_SPACE;
+ else transaction(ch, ACCEPT);
+ }
+ break;
+ case IGNORE_SPACE:
+ if (ch == '\\') state = ESCAPE;
+ else if (ch == '#') state = PARAMETER;
+ else if (isspace(ch)) ;
+ else if (ch == -1) state = ACCEPT;
+ else if (isalpha(ch))
+ {
+ buffer.push_back(ch);
+ state = LONG_IDENTIFIER;
+ }
+ else transaction(ch, ACCEPT);
+ break;
+ case PARAMETER:
+ if (ch == -1) error();
+ else
+ {
+ parser.push(TToken(TToken::PARAMETER, ch));
+ state = ACCEPT;
+ }
+ break;
+ case LONG_IDENTIFIER:
+ if (ch == -1)
+ {
+ parser.push(TToken(TToken::LETTER, buffer));
+ buffer.erase();
+ state = ACCEPT;
+ }
+ else if (isalpha(ch) || isdigit(ch))
+ {
+ buffer.push_back(ch);
+ }
+ else if (isspace(ch))
+ {
+ parser.push(TToken(TToken::LETTER, buffer));
+
+ // the parser ignores spaces. But in this case, the space
+ // is a significant. So, we transform this space in the MACRO
+ // \; which will not be ignored.
+ // This is not a good solution. Having a special token, that will be
+ // interpreted as "function application" is a better one.
+ buffer.erase();
+ buffer = ";";
+ parser.push(TToken(TToken::CONTROL, buffer));
+ buffer.erase();
+ state = IGNORE_SPACE;
+ }
+ else if (ch == '\\')
+ {
+ parser.push(TToken(TToken::LETTER, buffer));
+ buffer.erase();
+ state = ESCAPE;
+ }
+ else
+ {
+ parser.push(TToken(TToken::LETTER, buffer));
+ buffer.erase();
+ transaction(ch, ACCEPT);
+ }
+ break;
+ default:
+ assert(0);
+ break;
+ }
+
+ switch (state)
+ {
+ case ESCAPE: parser.setCursorHint("\\"); break;
+ case MACRO: parser.setCursorHint("\\" + buffer); break;
+ case PARAMETER: parser.setCursorHint("#"); break;
+ case LONG_IDENTIFIER: parser.setCursorHint(buffer); break;
+ default: parser.setCursorHint(""); break;
+ }
+}
+
+void
+LPushLexer::drop(bool alt)
+{
+ std::string restore = "";
+
+ switch (state)
+ {
+ case ACCEPT:
+ case IGNORE_SPACE:
+ restore = parser.drop();
+ if (restore.length() > 0 && restore[0] == '\\')
+ {
+ buffer = std::string(restore, 1, restore.length() - 1);
+ state = (buffer.length() > 0) ? MACRO : ESCAPE;
+ }
+ break;
+ case ESCAPE:
+ state = ACCEPT;
+ break;
+ case MACRO:
+ if (alt) buffer.erase();
+ else buffer.erase(buffer.length() - 1, 1);
+ if (buffer.length() == 0) state = ESCAPE;
+ break;
+ case LONG_IDENTIFIER:
+ buffer.erase(buffer.length() - 1, 1);
+ if (buffer.length() == 0) state = ACCEPT;
+ break;
+ case PARAMETER:
+ default:
+ assert(0);
+ break;
+ }
+
+ switch (state)
+ {
+ case ESCAPE: parser.setCursorHint("\\"); break;
+ case MACRO: parser.setCursorHint("\\" + buffer); break;
+ case PARAMETER: parser.setCursorHint("#"); break;
+ default: parser.setCursorHint(""); break;
+ }
+}
+
+bool
+LPushLexer::error() const
+{
+ return false;
+}