G_do_hoelder: fix case with real x values which are not of type cl_R.
[ginac.git] / ginac / parser / lexer.cpp
1 /** @file lexer.cpp
2  *
3  *  Implementation of GiNaC's lexer. */
4
5 /*
6  *  GiNaC Copyright (C) 1999-2018 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 #include <cstdio>
30
31 namespace GiNaC {
32
33 /// Skip to the end of line
34 static int skipline(std::istream* s);
35 /// Skip to the next non-whitespace character
36 static int skipspace(std::istream* s, int c, std::size_t& line);
37 /// Check if the identifier is predefined literal
38 static bool literal_p(const std::string& name);
39
40 /// gettok - Return the next token from standard input.
41 int lexer::gettok()
42 {
43         // Skip any whitespace.
44         c = skipspace(input, c, line_num);
45
46         // identifier: [a-zA-Z][a-zA-Z0-9_]*
47         if (isalpha(c)) { 
48                 str = c;
49                 do {
50                         c = input->get();
51                         if ( isalnum(c) || c=='_' )
52                                 str += c;
53                         else
54                                 break;
55                 } while (true);
56                 if (unlikely(literal_p(str)))
57                         return token_type::literal;
58                 else
59                         return token_type::identifier;
60         }
61
62         // Number: [0-9]+([.][0-9]*(eE[+-][0-9]+)*)*
63         if (isdigit(c) || c == '.') {
64                 str = "";
65                 do {
66                         str += c;
67                         c = input->get();
68                 } while (isdigit(c) || c == '.');
69                 if (c == 'E' || c == 'e') {
70                         str += 'E';
71                         c = input->get();
72                         if (isdigit(c))
73                                 str += '+';
74                         do {
75                                 str += c;
76                                 c = input->get();
77                         } while (isdigit(c));
78                 }
79                 return token_type::number;
80         }
81
82         // Comment until end of line.
83         if (c == '#') {
84                 c = skipline(input);
85                 ++line_num;
86                 if (c != EOF)
87                         return gettok();
88         }
89
90         // Check for end of file.  Don't eat the EOF.
91         if (c == EOF)
92                 return token_type::eof;
93
94         // Otherwise, just return the character as its ascii value.
95         int current = c;
96         c = input->get();
97         return current;
98 }
99
100 static int skipline(std::istream* s)
101 {
102         int c;
103         do {
104                 c = s->get();
105         } while (c != EOF && c != '\n' && c != '\r');
106         return c;
107 }
108
109 static int skipspace(std::istream* s, int c, std::size_t& line)
110 {
111         while (isspace(c)) {
112                 if (c == '\n')
113                         ++line;
114                 c = s->get();
115         }
116         return c;
117 }
118
119 static bool literal_p(const std::string& name)
120 {
121         if (name == "I")
122                 return true;
123         else if (name == "Pi")
124                 return true;
125         else if (name == "Euler")
126                 return true;
127         else if (name == "Catalan")
128                 return true;
129         else
130                 return false; 
131 }
132
133 lexer::lexer(std::istream* in, std::ostream* out, std::ostream* err)
134 {
135         if (in)
136                 input = in;
137         else
138                 in = &std::cin;
139
140         if (out)
141                 output = out;
142         else
143                 output = &std::cout;
144
145         if (err)
146                 error = err;
147         else
148                 error = &std::cerr;
149
150         c = ' ';
151         str = "";
152         line_num = 0;
153         column = 0;
154 }
155
156 lexer::~lexer() { }
157
158 void lexer::switch_input(std::istream* in)
159 {
160         input = in;
161         line_num = 0;
162         column = 0;
163         c = ' ';
164 }
165
166 /// Symbolic name of current token (for error reporting)
167 std::string lexer::tok2str(const int tok) const
168 {
169         switch (tok) {
170                 case lexer::token_type::identifier:
171                 case lexer::token_type::number:
172                         return std::string("\"") + str + "\"";
173                 case lexer::token_type::eof:
174                         return std::string("EOF");
175                 default:
176                         return std::string("\"") + char(tok) + "\"";
177         }
178 }
179
180 } // namespace GiNaC