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
27namespace sexp {
28
29Value
30Parser::from_string(std::string const& str, bool use_arrays)
31{
32 std::istringstream is(str);
33 return from_stream(is);
34}
35
36Value
37Parser::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
49std::vector<Value>
50Parser::from_string_many(std::string const& str, bool use_arrays)
51{
52 std::istringstream is(str);
53 return from_stream_many(is);
54}
55
56std::vector<Value>
57Parser::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
64Parser::Parser(Lexer& lexer) :
65 m_lexer(lexer),
66 m_token(m_lexer.get_next_token())
67{
68}
69
70Parser::~Parser()
71{
72}
73
74void
75Parser::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
83std::vector<Value>
84Parser::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
94Value
95Parser::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