Faster, better (recursive descent) expression parser.
[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.]+
39         if (isdigit(c) || c == '.') {
40                 str = "";
41                 do {
42                         str += c;
43                         c = input->get();
44                 } while (isdigit(c) || c == '.');
45                 return token_type::number;
46         }
47
48         // Comment until end of line.
49         if (c == '#') {
50                 c = skipline(input);
51                 ++line_num;
52                 if (c != EOF)
53                         return gettok();
54         }
55
56         // Check for end of file.  Don't eat the EOF.
57         if (c == EOF)
58                 return token_type::eof;
59
60         // Otherwise, just return the character as its ascii value.
61         int current = c;
62         c = input->get();
63         return current;
64 }
65
66 static int skipline(std::istream* s)
67 {
68         int c;
69         do {
70                 c = s->get();
71         } while (c != EOF && c != '\n' && c != '\r');
72         return c;
73 }
74
75 static int skipspace(std::istream* s, int c, std::size_t& line)
76 {
77         while (isspace(c)) {
78                 if (c == '\n')
79                         ++line;
80                 c = s->get();
81         }
82         return c;
83 }
84
85 static bool literal_p(const std::string& name)
86 {
87         if (name == "I")
88                 return true;
89         else if (name == "Pi")
90                 return true;
91         else if (name == "Euler")
92                 return true;
93         else if (name == "Catalan")
94                 return true;
95         else
96                 return false; 
97 }
98
99 lexer::lexer(std::istream* in, std::ostream* out, std::ostream* err)
100 {
101         if (in)
102                 input = in;
103         else
104                 in = &std::cin;
105
106         if (out)
107                 output = out;
108         else
109                 output = &std::cout;
110
111         if (err)
112                 error = err;
113         else
114                 error = &std::cerr;
115
116         c = ' ';
117         str = "";
118         line_num = 0;
119         column = 0;
120 }
121
122 lexer::~lexer() { }
123
124 void lexer::switch_input(std::istream* in)
125 {
126         input = in;
127         line_num = 0;
128         column = 0;
129 }
130
131 } // namespace GiNaC
132