Parser can parse (some) floating point numbers now.
[ginac.git] / ginac / parser / lexer.cpp
1 #include <string>
2 #include <iostream>
3 #include <sstream>
4 #include "lexer.hpp"
5 #include "compiler.h"
6
7 namespace GiNaC
8 {
9 /// Skip to the end of line
10 static int skipline(std::istream* s);
11 /// Skip to the next non-whitespace character
12 static int skipspace(std::istream* s, int c, std::size_t& line);
13 /// Check if the identifier is predefined literal
14 static bool literal_p(const std::string& name);
15
16 /// gettok - Return the next token from standard input.
17 int lexer::gettok()
18 {
19         // Skip any whitespace.
20         c = skipspace(input, c, line_num);
21
22         // identifier: [a-zA-Z][a-zA-Z0-9]*
23         if (isalpha(c)) { 
24                 str = c;
25                 do {
26                         c = input->get();
27                         if (isalnum(c))
28                                 str += c;
29                         else
30                                 break;
31                 } while (true);
32                 if (unlikely(literal_p(str)))
33                         return token_type::literal;
34                 else
35                         return token_type::identifier;
36         }
37
38         // Number: [0-9]+([.][0-9]*(eE[+-][0-9]+)*)*
39         if (isdigit(c) || c == '.') {
40                 str = "";
41                 do {
42                         str += c;
43                         c = input->get();
44                 } while (isdigit(c) || c == '.');
45                 if (c == 'E' || c == 'e') {
46                         str += 'E';
47                         c = input->get();
48                         if (isdigit(c))
49                                 str += '+';
50                         do {
51                                 str += c;
52                                 c = input->get();
53                         } while (isdigit(c));
54                 }
55                 return token_type::number;
56         }
57
58         // Comment until end of line.
59         if (c == '#') {
60                 c = skipline(input);
61                 ++line_num;
62                 if (c != EOF)
63                         return gettok();
64         }
65
66         // Check for end of file.  Don't eat the EOF.
67         if (c == EOF)
68                 return token_type::eof;
69
70         // Otherwise, just return the character as its ascii value.
71         int current = c;
72         c = input->get();
73         return current;
74 }
75
76 static int skipline(std::istream* s)
77 {
78         int c;
79         do {
80                 c = s->get();
81         } while (c != EOF && c != '\n' && c != '\r');
82         return c;
83 }
84
85 static int skipspace(std::istream* s, int c, std::size_t& line)
86 {
87         while (isspace(c)) {
88                 if (c == '\n')
89                         ++line;
90                 c = s->get();
91         }
92         return c;
93 }
94
95 static bool literal_p(const std::string& name)
96 {
97         if (name == "I")
98                 return true;
99         else if (name == "Pi")
100                 return true;
101         else if (name == "Euler")
102                 return true;
103         else if (name == "Catalan")
104                 return true;
105         else
106                 return false; 
107 }
108
109 lexer::lexer(std::istream* in, std::ostream* out, std::ostream* err)
110 {
111         if (in)
112                 input = in;
113         else
114                 in = &std::cin;
115
116         if (out)
117                 output = out;
118         else
119                 output = &std::cout;
120
121         if (err)
122                 error = err;
123         else
124                 error = &std::cerr;
125
126         c = ' ';
127         str = "";
128         line_num = 0;
129         column = 0;
130 }
131
132 lexer::~lexer() { }
133
134 void lexer::switch_input(std::istream* in)
135 {
136         input = in;
137         line_num = 0;
138         column = 0;
139         c = ' ';
140 }
141
142 /// Symbolic name of current token (for error reporting)
143 std::string lexer::tok2str(const int tok) const
144 {
145         switch (tok) {
146                 case lexer::token_type::identifier:
147                 case lexer::token_type::number:
148                         return std::string("\"") + str + "\"";
149                 case lexer::token_type::eof:
150                         return std::string("EOF");
151                 default:
152                         return std::string("\"") + char(tok) + "\"";
153         }
154 }
155
156 } // namespace GiNaC
157