diff interps/rail/src/MultiLexer.cpp @ 996:859f9b4339e6

<Gregor> tar xf egobot.tar.xz
author HackBot
date Sun, 09 Dec 2012 19:30:08 +0000
parents
children
line wrap: on
line diff
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/interps/rail/src/MultiLexer.cpp	Sun Dec 09 19:30:08 2012 +0000
@@ -0,0 +1,312 @@
+// MultiLexer.cpp
+
+#include "lib.h"
+#include "MultiLexer.h"
+#include "Error.h"
+
+using namespace std;
+
+MultiLexer::MultiLexer()
+  : state(EMPTY)
+  , openChar('\0')
+  , closeChar('\0')
+{
+}
+
+void MultiLexer::reset(void)
+{
+  token.clear();
+  state = EMPTY;
+  openChar = '\0';
+  closeChar = '\0';
+}
+
+void MultiLexer::add(char letter)
+{
+  switch (state)
+  {
+  case EMPTY:
+    if (letter == '{')
+    {
+      state = FUNCTION_BEGIN;
+      openChar = '{';
+      closeChar = '}';
+    }
+    else if (letter == '}')
+    {
+      state = FUNCTION_BEGIN;
+      openChar = '}';
+      closeChar = '{';
+    }
+    else if (letter == '[')
+    {
+      state = CONSTANT_BEGIN;
+      openChar = '[';
+      closeChar = ']';
+    }
+    else if (letter == ']')
+    {
+      state = CONSTANT_BEGIN;
+      openChar = ']';
+      closeChar = '[';
+    }
+    else if (letter == '(')
+    {
+      state = VARIABLE_BEGIN;
+      openChar = '(';
+      closeChar = ')';
+    }
+    else if (letter == ')')
+    {
+      state = VARIABLE_BEGIN;
+      openChar = ')';
+      closeChar = '(';
+    }
+    else
+    {
+      throw InternalException(string("Invalid opening character: '") + letter + "'");
+    }
+    break;
+  case FUNCTION_BEGIN:
+  case FUNCTION_END:
+    inFunction(letter);
+    break;
+  case CONSTANT_BEGIN:
+  case CONSTANT_END:
+  case ESCAPE_BEGIN:
+  case ESCAPE_END:
+    inConstant(letter);
+    break;
+  case VARIABLE_BEGIN:
+    if (letter == openChar || letter == '{' || letter == '}' || letter == '\'')
+    {
+      throw CrashException(Error::invalidCharInVariableName);
+    }
+    else if (letter == closeChar)
+    {
+      state = USE_END;
+    }
+    else if (letter == '!')
+    {
+      state = BIND_BEGIN;
+    }
+    else
+    {
+      state = USE_BEGIN;
+      token.push_back(letter);
+    }
+    break;
+  case USE_BEGIN:
+  case USE_END:
+    inUse(letter);
+    break;
+  case BIND_BEGIN:
+  case BIND_MIDDLE:
+  case BIND_END:
+    inBind(letter);
+    break;
+  default:
+    throw InternalException("Unknown state in MultiLexer: "
+                            + intToString(state));
+    break;
+  }
+}
+
+bool MultiLexer::isStarted(void) const
+{
+  return state != EMPTY;
+}
+
+bool MultiLexer::isDone(void) const
+{
+  return isFunction() || isConstant() || isUse() || isBind();
+}
+
+bool MultiLexer::isFunction(void) const
+{
+  return state == FUNCTION_END;
+}
+
+bool MultiLexer::isConstant(void) const
+{
+  return state == CONSTANT_END;
+}
+
+bool MultiLexer::isUse(void) const
+{
+  return state == USE_END;
+}
+
+bool MultiLexer::isBind(void) const
+{
+  return state == BIND_END;
+}
+
+string const & MultiLexer::getToken(void) const
+{
+  return token;
+}
+
+void MultiLexer::inFunction(char letter)
+{
+  switch (state)
+  {
+  case FUNCTION_BEGIN:
+    if (letter == '\'' || letter == openChar || letter == '!' || letter == '('
+      || letter == ')')
+    {
+      throw CrashException(Error::invalidCharInFunctionName);
+    }
+    else if (letter == closeChar)
+    {
+      state = FUNCTION_END;
+    }
+    else
+    {
+      state = FUNCTION_BEGIN;
+      token.push_back(letter);
+    }
+    break;
+  case FUNCTION_END:
+    tooManyLetters(letter);
+    break;
+  }
+}
+
+void MultiLexer::inConstant(char letter)
+{
+  switch (state)
+  {
+  case CONSTANT_BEGIN:
+    if (letter == '\\')
+    {
+      state = ESCAPE_BEGIN;
+    }
+    else if (letter == openChar)
+    {
+      throw CrashException(Error::invalidCharInConstant);
+    }
+    else if (letter == closeChar)
+    {
+      state = CONSTANT_END;
+    }
+    else
+    {
+      state = CONSTANT_BEGIN;
+      token.push_back(letter);
+    }
+    break;
+  case CONSTANT_END:
+    tooManyLetters(letter);
+    break;
+  case ESCAPE_BEGIN:
+    if (letter == '\\')
+    {
+      state = CONSTANT_BEGIN;
+      token.push_back('\\');
+    }
+    else if (letter == 'n')
+    {
+      state = ESCAPE_END;
+      token.push_back('\n');
+    }
+    else if (letter == 't')
+    {
+      state = ESCAPE_END;
+      token.push_back('\t');
+    }
+    else if (letter == '[')
+    {
+      state = ESCAPE_END;
+      token.push_back('[');
+    }
+    else if (letter == ']')
+    {
+      state = ESCAPE_END;
+      token.push_back(']');
+    }
+    else
+    {
+      throw CrashException(Error::invalidEscapeSequence);
+    }
+    break;
+  case ESCAPE_END:
+    if (letter == '\\')
+    {
+      state = CONSTANT_BEGIN;
+    }
+    else
+    {
+      throw CrashException(Error::invalidEscapeSequence);
+    }
+    break;
+  }
+}
+
+void MultiLexer::inUse(char letter)
+{
+  switch (state)
+  {
+  case USE_BEGIN:
+    if (letter == openChar || letter == '!' || letter == '{' || letter == '}'
+      || letter == '\'')
+    {
+      throw CrashException(Error::invalidCharInVariableName);
+    }
+    else if (letter == closeChar)
+    {
+      state = USE_END;
+    }
+    else
+    {
+      state = USE_BEGIN;
+      token.push_back(letter);
+    }
+    break;
+  case USE_END:
+    tooManyLetters(letter);
+    break;
+  }
+}
+
+void MultiLexer::inBind(char letter)
+{
+  switch (state)
+  {
+  case BIND_BEGIN:
+    if (letter == openChar || letter == closeChar || letter == '{'
+        || letter == '}' || letter == '\'')
+    {
+      throw CrashException(Error::invalidCharInVariableName);
+    }
+    else if (letter == '!')
+    {
+      state = BIND_MIDDLE;
+    }
+    else
+    {
+      state = BIND_BEGIN;
+      token.push_back(letter);
+    }
+    break;
+  case BIND_MIDDLE:
+    if (letter == closeChar)
+    {
+      state = BIND_END;
+    }
+    else
+    {
+      throw CrashException(Error::invalidCharInVariableName);
+    }
+    break;
+  case BIND_END:
+    tooManyLetters(letter);
+    break;
+  }
+}
+
+void MultiLexer::tooManyLetters(char letter)
+{
+  throw InternalException(string("MultiLexer is done but was sent a letter: '")
+                          + letter + "'");
+}