]> www.ginac.de Git - ginac.git/blobdiff - ginac/parser/lexer.cpp
Faster, better (recursive descent) expression parser.
[ginac.git] / ginac / parser / lexer.cpp
diff --git a/ginac/parser/lexer.cpp b/ginac/parser/lexer.cpp
new file mode 100644 (file)
index 0000000..ed1f894
--- /dev/null
@@ -0,0 +1,132 @@
+#include <string>
+#include <iostream>
+#include <sstream>
+#include "lexer.hpp"
+#include "compiler.h"
+
+namespace GiNaC
+{
+/// Skip to the end of line
+static int skipline(std::istream* s);
+/// Skip to the next non-whitespace character
+static int skipspace(std::istream* s, int c, std::size_t& line);
+/// Check if the identifier is predefined literal
+static bool literal_p(const std::string& name);
+
+/// gettok - Return the next token from standard input.
+int lexer::gettok()
+{
+       // Skip any whitespace.
+       c = skipspace(input, c, line_num);
+
+       // identifier: [a-zA-Z][a-zA-Z0-9]*
+       if (isalpha(c)) { 
+               str = c;
+               do {
+                       c = input->get();
+                       if (isalnum(c))
+                               str += c;
+                       else
+                               break;
+               } while (true);
+               if (unlikely(literal_p(str)))
+                       return token_type::literal;
+               else
+                       return token_type::identifier;
+       }
+
+       // Number: [0-9.]+
+       if (isdigit(c) || c == '.') {
+               str = "";
+               do {
+                       str += c;
+                       c = input->get();
+               } while (isdigit(c) || c == '.');
+               return token_type::number;
+       }
+
+       // Comment until end of line.
+       if (c == '#') {
+               c = skipline(input);
+               ++line_num;
+               if (c != EOF)
+                       return gettok();
+       }
+
+       // Check for end of file.  Don't eat the EOF.
+       if (c == EOF)
+               return token_type::eof;
+
+       // Otherwise, just return the character as its ascii value.
+       int current = c;
+       c = input->get();
+       return current;
+}
+
+static int skipline(std::istream* s)
+{
+       int c;
+       do {
+               c = s->get();
+       } while (c != EOF && c != '\n' && c != '\r');
+       return c;
+}
+
+static int skipspace(std::istream* s, int c, std::size_t& line)
+{
+       while (isspace(c)) {
+               if (c == '\n')
+                       ++line;
+               c = s->get();
+       }
+       return c;
+}
+
+static bool literal_p(const std::string& name)
+{
+       if (name == "I")
+               return true;
+       else if (name == "Pi")
+               return true;
+       else if (name == "Euler")
+               return true;
+       else if (name == "Catalan")
+               return true;
+       else
+               return false; 
+}
+
+lexer::lexer(std::istream* in, std::ostream* out, std::ostream* err)
+{
+       if (in)
+               input = in;
+       else
+               in = &std::cin;
+
+       if (out)
+               output = out;
+       else
+               output = &std::cout;
+
+       if (err)
+               error = err;
+       else
+               error = &std::cerr;
+
+       c = ' ';
+       str = "";
+       line_num = 0;
+       column = 0;
+}
+
+lexer::~lexer() { }
+
+void lexer::switch_input(std::istream* in)
+{
+       input = in;
+       line_num = 0;
+       column = 0;
+}
+
+} // namespace GiNaC
+