Prettified source code.
[ginac.git] / ginac / parser / lexer.cpp
1 /** @file lexer.cpp
2  *
3  *  Implementation of GiNaC's lexer. */
4
5 /*
6  *  GiNaC Copyright (C) 1999-2009 Johannes Gutenberg University Mainz, Germany
7  *
8  *  This program is free software; you can redistribute it and/or modify
9  *  it under the terms of the GNU General Public License as published by
10  *  the Free Software Foundation; either version 2 of the License, or
11  *  (at your option) any later version.
12  *
13  *  This program is distributed in the hope that it will be useful,
14  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
15  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
16  *  GNU General Public License for more details.
17  *
18  *  You should have received a copy of the GNU General Public License
19  *  along with this program; if not, write to the Free Software
20  *  Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
21  */
22
23 #include "lexer.h"
24 #include "compiler.h"
25
26 #include <iostream>
27 #include <sstream>
28 #include <string>
29
30 namespace GiNaC {
31
32 /// Skip to the end of line
33 static int skipline(std::istream* s);
34 /// Skip to the next non-whitespace character
35 static int skipspace(std::istream* s, int c, std::size_t& line);
36 /// Check if the identifier is predefined literal
37 static bool literal_p(const std::string& name);
38
39 /// gettok - Return the next token from standard input.
40 int lexer::gettok()
41 {
42         // Skip any whitespace.
43         c = skipspace(input, c, line_num);
44
45         // identifier: [a-zA-Z][a-zA-Z0-9]*
46         if (isalpha(c)) { 
47                 str = c;
48                 do {
49                         c = input->get();
50                         if (isalnum(c))
51                                 str += c;
52                         else
53                                 break;
54                 } while (true);
55                 if (unlikely(literal_p(str)))
56                         return token_type::literal;
57                 else
58                         return token_type::identifier;
59         }
60
61         // Number: [0-9]+([.][0-9]*(eE[+-][0-9]+)*)*
62         if (isdigit(c) || c == '.') {
63                 str = "";
64                 do {
65                         str += c;
66                         c = input->get();
67                 } while (isdigit(c) || c == '.');
68                 if (c == 'E' || c == 'e') {
69                         str += 'E';
70                         c = input->get();
71                         if (isdigit(c))
72                                 str += '+';
73                         do {
74                                 str += c;
75                                 c = input->get();
76                         } while (isdigit(c));
77                 }
78                 return token_type::number;
79         }
80
81         // Comment until end of line.
82         if (c == '#') {
83                 c = skipline(input);
84                 ++line_num;
85                 if (c != EOF)
86                         return gettok();
87         }
88
89         // Check for end of file.  Don't eat the EOF.
90         if (c == EOF)
91                 return token_type::eof;
92
93         // Otherwise, just return the character as its ascii value.
94         int current = c;
95         c = input->get();
96         return current;
97 }
98
99 static int skipline(std::istream* s)
100 {
101         int c;
102         do {
103                 c = s->get();
104         } while (c != EOF && c != '\n' && c != '\r');
105         return c;
106 }
107
108 static int skipspace(std::istream* s, int c, std::size_t& line)
109 {
110         while (isspace(c)) {
111                 if (c == '\n')
112                         ++line;
113                 c = s->get();
114         }
115         return c;
116 }
117
118 static bool literal_p(const std::string& name)
119 {
120         if (name == "I")
121                 return true;
122         else if (name == "Pi")
123                 return true;
124         else if (name == "Euler")
125                 return true;
126         else if (name == "Catalan")
127                 return true;
128         else
129                 return false; 
130 }
131
132 lexer::lexer(std::istream* in, std::ostream* out, std::ostream* err)
133 {
134         if (in)
135                 input = in;
136         else
137                 in = &std::cin;
138
139         if (out)
140                 output = out;
141         else
142                 output = &std::cout;
143
144         if (err)
145                 error = err;
146         else
147                 error = &std::cerr;
148
149         c = ' ';
150         str = "";
151         line_num = 0;
152         column = 0;
153 }
154
155 lexer::~lexer() { }
156
157 void lexer::switch_input(std::istream* in)
158 {
159         input = in;
160         line_num = 0;
161         column = 0;
162         c = ' ';
163 }
164
165 /// Symbolic name of current token (for error reporting)
166 std::string lexer::tok2str(const int tok) const
167 {
168         switch (tok) {
169                 case lexer::token_type::identifier:
170                 case lexer::token_type::number:
171                         return std::string("\"") + str + "\"";
172                 case lexer::token_type::eof:
173                         return std::string("EOF");
174                 default:
175                         return std::string("\"") + char(tok) + "\"";
176         }
177 }
178
179 } // namespace GiNaC