Big YAML parser cleanup

This commit is contained in:
Eryn Wells 2014-07-15 17:27:27 -07:00
parent 687de91a81
commit d20e4154fe
13 changed files with 409 additions and 207 deletions

View file

@ -5,12 +5,16 @@
Import('env')
objs = []
subdirs = [
# TODO: Put subdirectories here.
'yaml',
]
for d in subdirs:
env.SConscript(env.Dir(d).File('SConscript'), {'env': env})
dir_objs = env.SConscript(env.Dir(d).File('SConscript'), {'env': env})
print dir_objs
objs.extend(dir_objs)
files = [
@ -26,11 +30,10 @@ files = [
'writer_png.cc',
]
objs = []
for f in files:
objs.append(env.Object(f))
lib = env.Library('charles', files)
lib = env.Library('charles', objs)
prog = env.Program('charles', ['charles.cc'], LIBS=[lib, 'png', 'yaml'])
env.Alias('charles', prog)

View file

@ -15,228 +15,47 @@
#include "reader_yaml.hh"
struct Parser;
typedef std::stack<Parser *> ParserStack;
#include "yaml/parsers.hh"
#include "yaml/scene_parser.hh"
struct Parser
{
Parser(Scene& scene,
ParserStack& parsers)
: mScene(scene),
mParsers(parsers)
{ }
virtual
~Parser()
{ }
virtual void
handle_event(yaml_event_t& event)
{
/* TODO: Shouldn't ever get here. */
abort();
}
bool
done()
const
{
return mDone;
}
protected:
Scene& mScene;
ParserStack &mParsers;
bool mDone;
};
struct SceneParser
#if 0
struct ObjectParser
: public Parser
{
SceneParser(Scene& scene, ParserStack& parsers)
ObjectParser(Scene& scene, ParserStack& parsers)
: Parser(scene, parsers),
mSection(SceneParser::NoSection),
mDimension(SceneParser::NoDimension)
mSection(NoSection)
{
printf("SceneParser\n");
printf("ObjectParser\n");
}
~SceneParser()
~ObjectParser()
{
printf("~SceneParser\n");
printf("~ObjectParser\n");
}
void
handle_event(yaml_event_t& event)
{
switch (mSection) {
case NoSection:
handle_toplevel_event(event);
break;
case CameraSection:
handle_camera_event(event);
case TypeSection:
break;
case DimensionsSection:
handle_dimensions_event(event);
break;
case ObjectsSection:
handle_objects_event(event);
break;
default:
/* TODO: WHAT. Fail gracefully. */
abort();
case OriginSection:
break;
}
}
void
handle_toplevel_event(yaml_event_t& event)
{
static const std::string CAMERA = "camera";
static const std::string DIMENSIONS = "dimensions";
static const std::string OBJECTS = "objects";
if (event.type == YAML_MAPPING_END_EVENT) {
mDone = true;
return;
}
if (event.type != YAML_SCALAR_EVENT) {
/* TODO: Invalid event type for top-level Scene. Fail. */
abort();
}
std::string key = (char *)event.data.scalar.value;
if (key == CAMERA) {
mSection = SceneParser::CameraSection;
}
else if (key == DIMENSIONS) {
mSection = SceneParser::DimensionsSection;
}
else if (key == OBJECTS) {
mSection = SceneParser::ObjectsSection;
}
else {
/* TODO: Invalid key. Fail. */
abort();
}
}
void
handle_camera_event(yaml_event_t& event)
{ }
void
handle_dimensions_event(yaml_event_t& event)
{
int dim;
switch (mDimension) {
case NoDimension:
switch (event.type) {
case YAML_SEQUENCE_START_EVENT:
printf(" start dimensions\n");
mDimension = SceneParser::WidthDimension;
break;
default:
/* TODO: Fail gracefully. */
abort();
}
break;
case WidthDimension:
switch (event.type) {
case YAML_SCALAR_EVENT:
printf(" width = %s\n", event.data.scalar.value);
sscanf((char *)event.data.scalar.value, "%d", &dim);
mScene.set_width(dim);
mDimension = SceneParser::HeightDimension;
break;
default:
/* TODO: Fail gracefully. */
abort();
}
break;
case HeightDimension:
if (event.type == YAML_SCALAR_EVENT) {
printf(" height = %s\n", event.data.scalar.value);
sscanf((char *)event.data.scalar.value, "%d", &dim);
mScene.set_height(dim);
mDimension = SceneParser::DoneDimension;
}
else {
/* TODO: Fail gracefully. */
abort();
}
break;
case DoneDimension:
if (event.type == YAML_SEQUENCE_END_EVENT) {
printf(" end dimensions\n");
mSection = NoSection;
}
else {
/* TODO: Fail gracefully. */
abort();
}
break;
}
}
void
handle_objects_event(yaml_event_t& event)
{ }
private:
enum {
NoSection,
CameraSection,
DimensionsSection,
ObjectsSection,
TypeSection,
OriginSection,
} mSection;
enum {
NoDimension,
HeightDimension,
WidthDimension,
DoneDimension
} mDimension;
};
struct DocumentParser
: public Parser
{
DocumentParser(Scene& scene,
ParserStack& parsers)
: Parser(scene, parsers)
{
printf("DocumentParser\n");
}
~DocumentParser()
{
printf("~DocumentParser\n");
}
void
handle_event(yaml_event_t& event)
{
switch (event.type) {
case YAML_DOCUMENT_END_EVENT:
mDone = true;
break;
case YAML_MAPPING_START_EVENT:
mParsers.push(new SceneParser(mScene, mParsers));
break;
default:
/* TODO: Fail gracefully. */
abort();
break;
}
}
};
#endif
ssize_t
@ -255,7 +74,7 @@ YAMLReader::read_file(const std::string& filename)
printf("Reading file: %s\n", filename.c_str());
yaml_parser_set_input_file(&parser, yaml_infile);
ParserStack parsers;
yaml::ParserStack parsers;
bool success = true;
bool done = false;
yaml_event_t event;
@ -280,16 +99,22 @@ YAMLReader::read_file(const std::string& filename)
case YAML_DOCUMENT_START_EVENT:
printf("YAML_DOCUMENT_START_EVENT\n");
parsers.push(new DocumentParser(mScene, parsers));
break;
case YAML_DOCUMENT_END_EVENT:
printf("YAML_DOCUMENT_END_EVENT\n");
break;
case YAML_MAPPING_START_EVENT:
parsers.push(new yaml::SceneParser(mScene, parsers));
break;
default:
if (parsers.top()->done()) {
delete parsers.top();
parsers.pop();
}
if (!parsers.empty()) {
parsers.top()->handle_event(event);
parsers.top()->HandleEvent(event);
if (parsers.top()->GetDone()) {
delete parsers.top();
parsers.pop();
}
}
#if 0

18
src/yaml/SConscript Normal file
View file

@ -0,0 +1,18 @@
# SConscript
# vim: set ft=python:
# Eryn Wells <eryn@erynwells.me>
Import('env')
files = [
'parsers.cc',
'scene_parser.cc',
]
objs = []
for f in files:
objs.append(env.Object(f))
print objs
Return('objs')

View file

View file

View file

View file

72
src/yaml/parsers.cc Normal file
View file

@ -0,0 +1,72 @@
/* parsers.cc
* vim: set tw=80:
* Eryn Wells <eryn@erynwells.me>
*/
/**
* YAML parser superclasses.
*/
#include <cassert>
#include "yaml.h"
#include "parsers.hh"
namespace yaml {
Parser::Parser(Scene& scene,
ParserStack& parsers)
: mScene(scene),
mParsers(parsers)
{ }
Parser::~Parser()
{ }
#pragma clang diagnostic push
#pragma clang diagnostic ignored "-Wunused-parameter"
void
Parser::HandleEvent(yaml_event_t& event)
{
/* Shouldn't ever get here. */
assert(false);
}
#pragma clang diagnostic pop
void
Parser::SetDone(bool done)
{
mDone = done;
}
bool
Parser::GetDone()
const
{
return mDone;
}
Scene&
Parser::GetScene()
const
{
return mScene;
}
ParserStack&
Parser::GetParsers()
const
{
return mParsers;
}
} /* namespace yaml */

99
src/yaml/parsers.hh Normal file
View file

@ -0,0 +1,99 @@
/* parsers.hh
* vim: set tw=80:
* Eryn Wells <eryn@erynwells.me>
*/
/**
* Some top-level YAML parser objects.
*/
#ifndef __YAML_PARSERS_HH__
#define __YAML_PARSERS_HH__
#include <functional>
#include <stack>
#include "yaml.h"
#include "scene.h"
namespace yaml {
struct Parser;
typedef std::stack<Parser*> ParserStack;
/**
* A Parser handles parsing a chunk of YAML, updating its mScene member as
* necessary.
*/
struct Parser
{
/** Constructor */
Parser(Scene& scene, ParserStack& parsers);
/** Destructor */
virtual ~Parser();
/**
* Called by the parser event loop to handle a libyaml parser event.
*
* @param [in] event A libyaml parser event object
*/
virtual void HandleEvent(yaml_event_t& event);
/** Set the done flag. */
void SetDone(bool done);
/**
* Returns true if the parser is done parsing.
*
* @returns `true` if done, `false` if not
*/
bool GetDone() const;
protected:
Scene& GetScene() const;
ParserStack& GetParsers() const;
private:
/** The Scene being described by the YAML this parser is parsing. */
Scene& mScene;
/** The stack of parsers. */
ParserStack& mParsers;
/** `true` if the parser is done parsing */
bool mDone;
};
/**
* UtilityParsers handle small reusable bits of YAML and their constructors take
* a C++11 lambda, which will be called back with the result of the parsed data.
*/
template<typename CallbackType>
struct UtilityParser
: public Parser
{
typedef std::function<CallbackType> CallbackFunction;
UtilityParser(Scene& scene,
ParserStack& parsers,
CallbackFunction callback)
: Parser(scene, parsers),
mCallback(callback)
{ }
virtual
~UtilityParser()
{ }
private:
CallbackFunction mCallback;
};
} /* namespace yaml */
#endif /* __YAML_PARSERS_HH__ */

140
src/yaml/scene_parser.cc Normal file
View file

@ -0,0 +1,140 @@
/* scene_parser.cc
* vim: set tw=80:
* Eryn Wells <eryn@erynwells.me>
*/
/**
* A SceneParser parses a YAML Scene object.
*/
#include <cassert>
#include <string>
#include "scene_parser.hh"
namespace yaml {
SceneParser::SceneParser(Scene& scene,
ParserStack& parsers)
: Parser(scene, parsers),
mSection(SceneParser::NoSection),
mDimension(SceneParser::NoDimension)
{ }
SceneParser::~SceneParser()
{ }
void
SceneParser::HandleEvent(yaml_event_t& event)
{
switch (mSection) {
case NoSection:
HandleTopLevelEvent(event);
break;
case CameraSection:
break;
case DimensionsSection:
HandleDimensionsEvent(event);
break;
case ObjectsSection:
break;
default:
/* TODO: WHAT. Fail gracefully. */
assert(false);
break;
}
}
void
SceneParser::HandleTopLevelEvent(yaml_event_t& event)
{
static const std::string CAMERA = "camera";
static const std::string DIMENSIONS = "dimensions";
static const std::string OBJECTS = "objects";
if (event.type == YAML_MAPPING_END_EVENT) {
SetDone(true);
return;
}
if (event.type != YAML_SCALAR_EVENT) {
/* TODO: Invalid event type for top-level Scene. Fail. */
abort();
}
std::string key = (char *)event.data.scalar.value;
if (key == CAMERA) {
mSection = SceneParser::CameraSection;
}
else if (key == DIMENSIONS) {
mSection = SceneParser::DimensionsSection;
}
else if (key == OBJECTS) {
mSection = SceneParser::ObjectsSection;
}
else {
/* TODO: Invalid key. Fail. */
abort();
}
}
void
SceneParser::HandleDimensionsEvent(yaml_event_t& event)
{
int dim;
switch (mDimension) {
case NoDimension:
switch (event.type) {
case YAML_SEQUENCE_START_EVENT:
printf(" start dimensions\n");
mDimension = SceneParser::WidthDimension;
break;
default:
/* TODO: Fail gracefully. */
abort();
}
break;
case WidthDimension:
switch (event.type) {
case YAML_SCALAR_EVENT:
printf(" width = %s\n", event.data.scalar.value);
sscanf((char *)event.data.scalar.value, "%d", &dim);
GetScene().set_width(dim);
mDimension = SceneParser::HeightDimension;
break;
default:
/* TODO: Fail gracefully. */
abort();
}
break;
case HeightDimension:
if (event.type == YAML_SCALAR_EVENT) {
printf(" height = %s\n", event.data.scalar.value);
sscanf((char *)event.data.scalar.value, "%d", &dim);
GetScene().set_height(dim);
mDimension = SceneParser::DoneDimension;
}
else {
/* TODO: Fail gracefully. */
abort();
}
break;
case DoneDimension:
if (event.type == YAML_SEQUENCE_END_EVENT) {
printf(" end dimensions\n");
mSection = NoSection;
}
else {
/* TODO: Fail gracefully. */
abort();
}
break;
}
}
} /* namespace yaml */

45
src/yaml/scene_parser.hh Normal file
View file

@ -0,0 +1,45 @@
/* scene_parser.hh
* vim: set tw=80:
* Eryn Wells <eryn@erynwells.me>
*/
/**
* A SceneParser parses a YAML Scene object.
*/
#ifndef __YAML_SCENE_PARSER_HH__
#define __YAML_SCENE_PARSER_HH__
#include "parsers.hh"
namespace yaml {
struct SceneParser
: public Parser
{
SceneParser(Scene& scene, ParserStack& parsers);
~SceneParser();
void HandleEvent(yaml_event_t& event);
void HandleTopLevelEvent(yaml_event_t& event);
void HandleDimensionsEvent(yaml_event_t& event);
private:
enum {
NoSection,
CameraSection,
DimensionsSection,
ObjectsSection,
} mSection;
enum {
NoDimension,
HeightDimension,
WidthDimension,
DoneDimension
} mDimension;
};
} /* namespace yaml */
#endif /* __YAML_SCENE_PARSER_HH__ */

View file

View file