/** @file lexer.cpp * * Implementation of GiNaC's lexer. */ /* * GiNaC Copyright (C) 1999-2010 Johannes Gutenberg University Mainz, Germany * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ #include "lexer.h" #include "compiler.h" #include #include #include #include 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) || c=='_' ) str += c; else break; } while (true); if (unlikely(literal_p(str))) return token_type::literal; else return token_type::identifier; } // Number: [0-9]+([.][0-9]*(eE[+-][0-9]+)*)* if (isdigit(c) || c == '.') { str = ""; do { str += c; c = input->get(); } while (isdigit(c) || c == '.'); if (c == 'E' || c == 'e') { str += 'E'; c = input->get(); if (isdigit(c)) str += '+'; do { str += c; c = input->get(); } while (isdigit(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; c = ' '; } /// Symbolic name of current token (for error reporting) std::string lexer::tok2str(const int tok) const { switch (tok) { case lexer::token_type::identifier: case lexer::token_type::number: return std::string("\"") + str + "\""; case lexer::token_type::eof: return std::string("EOF"); default: return std::string("\"") + char(tok) + "\""; } } } // namespace GiNaC