204 lines
6.8 KiB
C++
204 lines
6.8 KiB
C++
/*
|
|
* Parsodus - A language agnostic parser generator
|
|
* Copyright © 2016-2017 Thomas Avé, Robin Jadoul, Kobe Wullaert
|
|
*
|
|
* Permission is hereby granted, free of charge, to any person obtaining
|
|
* a copy of this software and associated documentation files (the "Software"),
|
|
* to deal in the Software without restriction, including without limitation
|
|
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
|
|
* and/or sell copies of the Software, and to permit persons to whom the
|
|
* Software is furnished to do so, subject to the following conditions:
|
|
*
|
|
* The above copyright notice and this permission notice shall be included
|
|
* in all copies or substantial portions of the Software.
|
|
*
|
|
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
|
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
|
|
* OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
|
|
* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
|
|
* DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
|
|
* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE
|
|
* OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
|
*/
|
|
|
|
#include "parser.h"
|
|
#include <algorithm>
|
|
#include <cassert>
|
|
#include <codecvt>
|
|
#include <deque>
|
|
#include <locale>
|
|
#include <sstream>
|
|
|
|
#include <iostream>
|
|
|
|
namespace {
|
|
double readNumber(std::string in) {
|
|
std::istringstream iss(in);
|
|
double d;
|
|
iss >> d;
|
|
return d;
|
|
}
|
|
|
|
std::string readString(std::string in) {
|
|
std::string result;
|
|
for (std::size_t i = 1; i < in.length() - 1; i++) {
|
|
if (in[i] == '\\' && in[i + 1] != 'u') {
|
|
char c = 0;
|
|
switch (in[i + 1]) {
|
|
case '"':
|
|
case '\\':
|
|
case '/':
|
|
c = in[i + 1];
|
|
break;
|
|
case 'b':
|
|
c = '\b';
|
|
break;
|
|
case 'f':
|
|
c = '\f';
|
|
break;
|
|
case 'n':
|
|
c = '\n';
|
|
break;
|
|
case 'r':
|
|
c = '\r';
|
|
break;
|
|
case 't':
|
|
c = '\t';
|
|
break;
|
|
default:
|
|
break;
|
|
}
|
|
result.push_back(c);
|
|
i++;
|
|
} else if (in[i] == '\\'){
|
|
char16_t unicode_value;
|
|
std::wstring_convert<std::codecvt_utf8<char16_t>, char16_t > utf8converter;
|
|
unicode_value = 0;
|
|
for (int j = 0; j < 4; j++, i++) {
|
|
char hex = in[i + 2];
|
|
unicode_value *= 16;
|
|
if (hex >= '0' && hex <= '9')
|
|
unicode_value += hex - '0';
|
|
else if (hex >= 'A' && hex <= '9')
|
|
unicode_value += hex - 'A' + 10;
|
|
else
|
|
unicode_value += hex - 'a' + 10;
|
|
}
|
|
result.append(utf8converter.to_bytes(unicode_value));
|
|
i++;
|
|
} else {
|
|
if (iscntrl(in[i])) {
|
|
throw SyntaxError("Control character inside string");
|
|
}
|
|
result.push_back(in[i]);
|
|
}
|
|
}
|
|
return result;
|
|
}
|
|
}
|
|
|
|
namespace json {
|
|
|
|
Parser::Parser(JSONLexer lex) : JSONParser<JSON>(), m_lex(lex)
|
|
{}
|
|
|
|
Parser::Token Parser::lex() {
|
|
try {
|
|
JSONLexer::Token orig = m_lex.nextToken();
|
|
JSONParser_Symbol s;
|
|
switch (orig.type) {
|
|
case JSONLexer::COLON:
|
|
s = JSONParser_Symbol::T_COLON;
|
|
break;
|
|
case JSONLexer::COMMA:
|
|
s = JSONParser_Symbol::T_COMMA;
|
|
break;
|
|
case JSONLexer::LBRACE:
|
|
s = JSONParser_Symbol::T_LBRACE;
|
|
break;
|
|
case JSONLexer::RBRACE:
|
|
s = JSONParser_Symbol::T_RBRACE;
|
|
break;
|
|
case JSONLexer::LBRACKET:
|
|
s = JSONParser_Symbol::T_LBRACKET;
|
|
break;
|
|
case JSONLexer::RBRACKET:
|
|
s = JSONParser_Symbol::T_RBRACKET;
|
|
break;
|
|
case JSONLexer::STRING:
|
|
return Token{JSONParser_Symbol::T_STRING, JSON::string(readString(orig.content))};
|
|
case JSONLexer::NUMBER:
|
|
return Token{JSONParser_Symbol::T_NUMBER, JSON::num(readNumber(orig.content))};
|
|
case JSONLexer::TTRUE:
|
|
return Token{JSONParser_Symbol::T_TTRUE, JSON::boolean(true)};
|
|
case JSONLexer::TFALSE:
|
|
return Token{JSONParser_Symbol::T_TFALSE, JSON::boolean(false)};
|
|
case JSONLexer::TNULL:
|
|
return Token{JSONParser_Symbol::T_TNULL, JSON::null()};
|
|
default:
|
|
//impossible
|
|
break;
|
|
}
|
|
return Token{s, JSON()};
|
|
}
|
|
catch (JSONLexer::NoMoreTokens) {
|
|
return Token{JSONParser_Symbol::T_EOF, JSON()};
|
|
}
|
|
}
|
|
|
|
JSON Parser::reduce_0(std::deque<Token> subparts) {
|
|
return std::move(subparts[0].value);
|
|
}
|
|
JSON Parser::reduce_1(std::deque<Token> subparts) {
|
|
return std::move(subparts[0].value);
|
|
}
|
|
JSON Parser::reduce_2(std::deque<Token> subparts) {
|
|
return std::move(subparts[0].value);
|
|
}
|
|
JSON Parser::reduce_3(std::deque<Token> subparts) {
|
|
return std::move(subparts[0].value);
|
|
}
|
|
JSON Parser::reduce_4(std::deque<Token> subparts) {
|
|
return std::move(subparts[0].value);
|
|
}
|
|
JSON Parser::reduce_5(std::deque<Token> subparts) {
|
|
return std::move(subparts[0].value);
|
|
}
|
|
JSON Parser::reduce_6(std::deque<Token> subparts) {
|
|
return std::move(subparts[0].value);
|
|
}
|
|
JSON Parser::reduce_7(std::deque<Token> subparts) {
|
|
return std::move(subparts[1].value);
|
|
}
|
|
JSON Parser::reduce_8(std::deque<Token>) {
|
|
return JSON::object();
|
|
}
|
|
JSON Parser::reduce_9(std::deque<Token> subparts) {
|
|
JSON obj = JSON::object();
|
|
obj[std::move(subparts[0].value)] = std::move(subparts[2].value);
|
|
return obj;
|
|
}
|
|
JSON Parser::reduce_10(std::deque<Token> subparts) {
|
|
JSON obj = std::move(subparts[4].value);
|
|
obj[std::move(subparts[0].value)] = std::move(subparts[2].value);
|
|
return obj;
|
|
}
|
|
JSON Parser::reduce_11(std::deque<Token> subparts) {
|
|
return std::move(subparts[1].value);
|
|
}
|
|
JSON Parser::reduce_12(std::deque<Token>) {
|
|
return JSON::array();
|
|
}
|
|
JSON Parser::reduce_13(std::deque<Token> subparts) {
|
|
JSON arr = JSON::array();
|
|
arr.push_front(std::move(subparts[0].value));
|
|
return arr;
|
|
}
|
|
JSON Parser::reduce_14(std::deque<Token> subparts) {
|
|
JSON arr = std::move(subparts[2].value);
|
|
arr.push_front(std::move(subparts[0].value));
|
|
return arr;
|
|
}
|
|
|
|
}
|