1 | // SExp - A S-Expression Parser for C++ |
2 | // Copyright (C) 2006 Matthias Braun <matze@braunis.de> |
3 | // 2015 Ingo Ruhnke <grumbel@gmail.com> |
4 | // |
5 | // This program is free software: you can redistribute it and/or modify |
6 | // it under the terms of the GNU General Public License as published by |
7 | // the Free Software Foundation, either version 3 of the License, or |
8 | // (at your option) any later version. |
9 | // |
10 | // This program is distributed in the hope that it will be useful, |
11 | // but WITHOUT ANY WARRANTY; without even the implied warranty of |
12 | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
13 | // GNU General Public License for more details. |
14 | // |
15 | // You should have received a copy of the GNU General Public License |
16 | // along with this program. If not, see <http://www.gnu.org/licenses/>. |
17 | |
18 | #include "sexp/parser.hpp" |
19 | |
20 | #include <sstream> |
21 | #include <stdexcept> |
22 | #include <string.h> |
23 | #include <iostream> |
24 | |
25 | #include "float.hpp" |
26 | |
27 | namespace sexp { |
28 | |
29 | Value |
30 | Parser::from_string(std::string const& str, bool use_arrays) |
31 | { |
32 | std::istringstream is(str); |
33 | return from_stream(is); |
34 | } |
35 | |
36 | Value |
37 | Parser::from_stream(std::istream& stream, bool use_arrays) |
38 | { |
39 | Lexer lexer(stream, use_arrays); |
40 | Parser parser(lexer); |
41 | Value result = parser.read(); |
42 | if (parser.m_token != Lexer::TOKEN_EOF) |
43 | { |
44 | parser.parse_error("trailing garbage in stream" ); |
45 | } |
46 | return result; |
47 | } |
48 | |
49 | std::vector<Value> |
50 | Parser::from_string_many(std::string const& str, bool use_arrays) |
51 | { |
52 | std::istringstream is(str); |
53 | return from_stream_many(is); |
54 | } |
55 | |
56 | std::vector<Value> |
57 | Parser::from_stream_many(std::istream& stream, bool use_arrays) |
58 | { |
59 | Lexer lexer(stream, use_arrays); |
60 | Parser parser(lexer); |
61 | return parser.read_many(); |
62 | } |
63 | |
64 | Parser::Parser(Lexer& lexer) : |
65 | m_lexer(lexer), |
66 | m_token(m_lexer.get_next_token()) |
67 | { |
68 | } |
69 | |
70 | Parser::~Parser() |
71 | { |
72 | } |
73 | |
74 | void |
75 | Parser::parse_error(const char* msg) const |
76 | { |
77 | std::stringstream emsg; |
78 | emsg << "Parse Error at line " << m_lexer.get_line_number() |
79 | << ": " << msg; |
80 | throw std::runtime_error(emsg.str()); |
81 | } |
82 | |
83 | std::vector<Value> |
84 | Parser::read_many() |
85 | { |
86 | std::vector<Value> results; |
87 | while(m_token != Lexer::TOKEN_EOF) |
88 | { |
89 | results.emplace_back(read()); |
90 | } |
91 | return results; |
92 | } |
93 | |
94 | Value |
95 | Parser::read() |
96 | { |
97 | Value result; |
98 | int line_number = m_lexer.get_line_number(); |
99 | |
100 | switch(m_token) |
101 | { |
102 | case Lexer::TOKEN_OPEN_PAREN: |
103 | m_token = m_lexer.get_next_token(); |
104 | if(m_token == Lexer::TOKEN_CLOSE_PAREN) |
105 | { |
106 | result = Value::nil(); |
107 | } |
108 | else |
109 | { |
110 | result = Value::cons(read(), Value::nil()); |
111 | Value* cur = &result; |
112 | while(m_token != Lexer::TOKEN_CLOSE_PAREN) |
113 | { |
114 | if (m_token == Lexer::TOKEN_DOT) |
115 | { |
116 | m_token = m_lexer.get_next_token(); |
117 | cur->set_cdr(read()); |
118 | if (m_token != Lexer::TOKEN_CLOSE_PAREN) |
119 | { |
120 | parse_error("Expected ')'" ); |
121 | } |
122 | break; |
123 | } |
124 | else |
125 | { |
126 | cur->set_cdr(Value::cons(read(), Value::nil())); |
127 | cur = &cur->get_cdr(); |
128 | } |
129 | } |
130 | } |
131 | break; |
132 | |
133 | case Lexer::TOKEN_SYMBOL: |
134 | result = Value::symbol(m_lexer.get_string()); |
135 | break; |
136 | |
137 | case Lexer::TOKEN_STRING: |
138 | result = Value::string(m_lexer.get_string()); |
139 | break; |
140 | |
141 | case Lexer::TOKEN_INTEGER: |
142 | result = Value::integer(std::stoi(m_lexer.get_string())); |
143 | break; |
144 | |
145 | case Lexer::TOKEN_REAL: |
146 | result = Value::real(string2float(m_lexer.get_string())); |
147 | break; |
148 | |
149 | case Lexer::TOKEN_TRUE: |
150 | result = Value::boolean(true); |
151 | break; |
152 | |
153 | case Lexer::TOKEN_FALSE: |
154 | result = Value::boolean(false); |
155 | break; |
156 | |
157 | case Lexer::TOKEN_ARRAY_START: |
158 | { |
159 | m_token = m_lexer.get_next_token(); |
160 | std::vector<Value> arr; |
161 | do |
162 | { |
163 | arr.emplace_back(read()); |
164 | } |
165 | while(m_token != Lexer::TOKEN_CLOSE_PAREN); |
166 | result = Value::array(std::move(arr)); |
167 | } |
168 | break; |
169 | |
170 | case Lexer::TOKEN_EOF: |
171 | parse_error("Unexpected EOF." ); |
172 | break; |
173 | |
174 | case Lexer::TOKEN_CLOSE_PAREN: |
175 | parse_error("Unexpected ')'." ); |
176 | break; |
177 | |
178 | case Lexer::TOKEN_DOT: |
179 | parse_error("Unexpected '.'." ); |
180 | break; |
181 | |
182 | default: |
183 | assert(false && "this should never happen" ); |
184 | break; |
185 | } |
186 | |
187 | m_token = m_lexer.get_next_token(); |
188 | |
189 | result.set_line(line_number); |
190 | return result; |
191 | } |
192 | |
193 | } // namespace sexp |
194 | |
195 | /* EOF */ |
196 | |