This is a framework for a json Parser I put together last night.
Any comments appreciated.
- JsonLexer.l: Breaks the input into lexemes
- JsonParser.y: Understands the language syntax
- JsonParser.h: Header file to bring it all togeter
- main.cpp: Test harness so it can be tested.
- Makefile: Sinmple build script.
###Testing:
echo '{ "Plop": "Test" }' | ./test
###JsonLexer.l
%option c++
%option noyywrap
%{
#define IN_LEXER
#include "JsonParser.tab.hpp"
%}
DIGIT [0-9]
DIGIT1 [1-9]
INTNUM {DIGIT1}{DIGIT}*
FRACT "."{DIGIT}+
FLOAT ({INTNUM}|0){FRACT}?
EXP [eE][+-]?{DIGIT}+
NUMBER -?{FLOAT}{EXP}?
UNICODE \\u[A-Fa-f0-9]{4}
ESCAPECHAR \\["\\/bfnrt]
CHAR [^"\\]|{ESCAPECHAR}|{UNICODE}
STRING \"{CHAR}*\"
WHITESPACE [ \t\n]
%%
\{ {LOG("LEX({)"); return '{';}
\} {LOG("LEX(})"); return '}';}
\[ {LOG("LEX([)"); return '[';}
\] {LOG("LEX(])"); return ']';}
, {LOG("LEX(,)"); return ',';}
: {LOG("LEX(:)"); return ':';}
true {LOG("LEX(true)"); return yy::JsonParser::token::JSON_TRUE;}
false {LOG("LEX(false)"); return yy::JsonParser::token::JSON_FALSE;}
null {LOG("LEX(null)"); return yy::JsonParser::token::JSON_NULL;}
{STRING} {LOG("LEX(String)");return yy::JsonParser::token::JSON_STRING;}
{NUMBER} {LOG("LEX(Number)");return yy::JsonParser::token::JSON_NUMBER;}
{WHITESPACE} {/*IGNORE*/}
%%
###JsonParser.y
%skeleton "lalr1.cc"
%require "2.1a"
%defines
%define "parser_class_name" "JsonParser"
%{
#include "JsonParser.h"
#include <stdexcept>
%}
%parse-param {FlexLexer& lexer}
%lex-param {FlexLexer& lexer}
%token JSON_STRING
%token JSON_NUMBER
%token JSON_TRUE
%token JSON_FALSE
%token JSON_NULL
%%
JsonObject : JsonMap {LOG("JsonObject: JsonMap");}
| JsonArray {LOG("JsonObject: JsonArray");}
;
JsonMap : '{' JsonMapValueListOpt '}' {LOG("JsonMap: { JsonMapValueListOpt }");}
;
JsonMapValueListOpt : {LOG("JsonMapValueListOpt: EMPTY");}
| JsonMapValueList {LOG("JsonMapValueListOpt: JsonMapValueList");}
;
JsonMapValueList : JsonMapValue {LOG("JsonMapValueList: JsonMapValue");}
| JsonMapValueList ',' JsonMapValue {LOG("JsonMapValueList: JsonMapValueList , JsonMapValue");}
;
JsonMapValue : JSON_STRING ':' JsonValue {LOG("JsonMapValue: JSON_STRING : JsonValue");}
;
JsonArray : '[' JsonArrayValueListOpt ']' {LOG("JsonArray: [ JsonArrayValueListOpt ]");}
;
JsonArrayValueListOpt : {LOG("JsonArrayValueListOpt: EMPTY");}
| JsonArrayValueList {LOG("JsonArrayValueListOpt: JsonArrayValueList");}
;
JsonArrayValueList : JsonValue {LOG("JsonArrayValueList: JsonValue");}
| JsonArrayValueList ',' JsonValue {LOG("JsonArrayValueList: JsonArrayValueList , JsonValue");}
;
JsonValue : JsonMap {LOG("JsonValue: JsonMap");}
| JsonArray {LOG("JsonValue: JsonArray");}
| JSON_STRING {LOG("JsonValue: JSON_STRING");}
| JSON_NUMBER {LOG("JsonValue: JSON_NUMBER");}
| JSON_TRUE {LOG("JsonValue: JSON_TRUE");}
| JSON_FALSE {LOG("JsonValue: JSON_FALSE");}
| JSON_NULL {LOG("JsonValue: JSON_NULL");}
;
%%
int yylex(int*, FlexLexer& lexer)
{
return lexer.yylex();
}
void yy::JsonParser::error(yy::location const&, std::string const& msg)
{
throw std::runtime_error(msg);
}
###main.cpp
#include "JsonParser.tab.hpp"
#include
int main()
{
try
{
yyFlexLexer lexer(&std::cin, &std::cout);
yy::JsonParser parser(lexer);
std::cout << (parser.parse() == 0 ? "OK" : "FAIL") << "\n";
}
catch(std::exception const& e)
{
std::cout << "Exception: " << e.what() << "\n";
}
}
###JsonParser.h
#ifndef THORSANVIL_JSON_PARSER_H
#define THORSANVIL_JSON_PARSER_H
#ifndef IN_LEXER
#include <FlexLexer.h>
#endif
int yylex(int*, FlexLexer& lexer);
#ifdef DEBUG_LOG
#include <iostream>
#define LOG(x) std::cout << x << "\n"
#else
#define LOG(x) 0 /*Empty Statement that will be optimized out*/
#endif
#endif
##Makefile
YACC = bison
LEX = flex
CXX = g++
CXXFLAGS = -DDEBUG_LOG
TARGET = json
LEX_SRC = $(wildcard *.l)
YACC_SRC = $(wildcard *.y)
CPP_SRC = $(filter-out %.lex.cpp %.tab.cpp,$(wildcard *.cpp))
SRC = $(patsubst %.y,%.tab.cpp,$(YACC_SRC)) $(patsubst %.l,%.lex.cpp,$(LEX_SRC)) $(CPP_SRC)
OBJ = $(patsubst %.cpp,%.o,$(SRC))
all: $(OBJ)
$(CXX) -o test $(OBJ) -lFl
clean:
rm $(OBJ) $(patsubst %.y,%.tab.cpp,$(YACC_SRC)) $(patsubst %.l,%.lex.cpp,$(LEX_SRC))
$(TARGET): $(OBJ)
$(CXX) -o $* $(OBJ)
.PRECIOUS: %.tab.cpp
%.tab.cpp: %.y
$(YACC) -o $@ -d $<
.PRECIOUS: %.lex.cpp
%.lex.cpp: %.l
$(LEX) -t $< > $@