From 505042fcda16151f5ace243c243d34af3efcf677 Mon Sep 17 00:00:00 2001 From: Mikko Rasa Date: Mon, 17 Sep 2007 17:09:56 +0000 Subject: [PATCH] Add Readme.txt and some other documentation --- Readme.txt | 84 +++++++++++++++++++++++++++++++++++++++++ source/binarydict.h | 3 ++ source/binaryparser.cpp | 4 +- source/binaryparser.h | 3 ++ source/binarywriter.cpp | 4 +- source/binarywriter.h | 3 ++ source/loader.h | 19 +++++++--- source/parser.h | 25 +++++++++--- source/parsermode.h | 3 ++ source/writer.h | 21 +++++++++-- 10 files changed, 151 insertions(+), 18 deletions(-) create mode 100644 Readme.txt diff --git a/Readme.txt b/Readme.txt new file mode 100644 index 0000000..2c03cf2 --- /dev/null +++ b/Readme.txt @@ -0,0 +1,84 @@ +libmspdatafile - structured datafile library +Copyright © 2006-2007 Mikko Rasa, Mikkosoft Productions +Version 0.1 readme + + +Libmspdatafile is a library for reading and writing structured data files. It +supports both a human-readable text format and a more compact binary format. +The text-based format is designed to be compact yet clean, avoiding much of the +redundancy of XML. + +Libmspdatafile is distributed under the terms of the GNU Lesser Public License. +Full text of the license can be found in the file License.txt. + + +*** Structure + +The basic building block of a datafile is a statement. A statement has a +keyword and zero or more arguments. It may also have zero or more substate- +ments. + +The interface is heavily object-oriented and typically one statement in a file +represents one object in the program's memory. + +The library supports five basic data types: integers, floats, strings, booleans +and enums. Data types are strictly enforced - the only allowed conversion is +from float to integer. + +The correct argument types for a statement is determined from the function or +variable used to load it. This means that semantical validation can only be +done by the program that actually uses the file. A generic tool can only +perform syntactic validation. + + +*** Basic usage + +Loading data from files is achieved through Loader classes. Such a class must +be derived from the DataFile::Loader class. In the constructor, a series of +calls to the various overloads of the add() function is executed, telling the +loader what to do. The two basic actions are calling a function of the loader +with the statement's arguments, or assigning the arguments to variables of the +loaded object. + +There is a load() function in namespace scope that allows loading a whole file +into an object. + +It is also possible to call the Parser::parse function directly and obtain a +raw Statement. However, this is rarely useful. + + +*** Syntax + +The syntax of the text format vaguely resembles C. Statements are terminated +with a semicolon and substatements are enclosed between burly braces. The sub- +statement block comes after all arguments and the semicolon comes after it. An +empty substatement block is allowed and equal to an absent block. + +Integers can be written in decimal, octal or hexadecimal notation. A minus +sign can be used in any base for negative numbers, as well as an optional plus +sign for positive numbers. + +Floats must be written in decimal and they must contain a decimal point. An +exponent may come after the mantissa, separated by the character e. Minus and +plus signs are allowed in both exponent and mantissa. + +Strings are enclosed in double quotes. Backslash can be used to escape a +literal double quote or backslash. + +Booleans are either true or false. + +Enumeration values are represented as symbolic identifiers. They may contain +alphaumeric characters and underscores and must begin with a letter or an +underscore. + + +*** Binary format + +The binary format is not intended to be manipulated by anything else than +libmspdatafile. A detailed description is not available at this time. + +The tool provided with the library can be used to convert between the two +formats. + + +*** $Id$ diff --git a/source/binarydict.h b/source/binarydict.h index 3b19561..9309b4f 100644 --- a/source/binarydict.h +++ b/source/binarydict.h @@ -13,6 +13,9 @@ Distributed under the LGPL namespace Msp { namespace DataFile { +/** +Stores statement information for binary files. +*/ struct DictEntry { std::string keyword; diff --git a/source/binaryparser.cpp b/source/binaryparser.cpp index 298770a..6aed5b1 100644 --- a/source/binaryparser.cpp +++ b/source/binaryparser.cpp @@ -19,7 +19,7 @@ BinaryParser::BinaryParser(Input &i, const string &s): ParserMode(i, s), first(true) { - dict[1]=DictEntry("__kw", "iss"); + dict[1]=DictEntry("__st", "iss"); dict[2]=DictEntry("__enum", "is"); } @@ -28,7 +28,7 @@ Statement BinaryParser::parse() while(1) { Statement st=parse_statement(); - if(st.keyword=="__kw") + if(st.keyword=="__st") { if(st.args.size()!=3) throw TypeError(src+": Keyword definition must have three arguments"); diff --git a/source/binaryparser.h b/source/binaryparser.h index 560703c..f1d51b2 100644 --- a/source/binaryparser.h +++ b/source/binaryparser.h @@ -15,6 +15,9 @@ Distributed under the LGPL namespace Msp { namespace DataFile { +/** +Parses data in binary format. +*/ class BinaryParser: public ParserMode { private: diff --git a/source/binarywriter.cpp b/source/binarywriter.cpp index e89def3..95526bb 100644 --- a/source/binarywriter.cpp +++ b/source/binarywriter.cpp @@ -18,7 +18,7 @@ BinaryWriter::BinaryWriter(ostream &o): next_st_id(3), next_enum_id(1) { - dict[DictEntry("__kw", "iss")]=1; + dict[DictEntry("__st", "iss")]=1; dict[DictEntry("__enum", "is")]=1; } @@ -72,7 +72,7 @@ void BinaryWriter::collect_keywords(const Statement &st) if(!dict.count(de)) { Statement kst; - kst.keyword="__kw"; + kst.keyword="__st"; kst.args.push_back(next_st_id); kst.args.push_back(de.keyword); kst.args.push_back(de.args); diff --git a/source/binarywriter.h b/source/binarywriter.h index cf8f9fc..691ed70 100644 --- a/source/binarywriter.h +++ b/source/binarywriter.h @@ -15,6 +15,9 @@ Distributed under the LGPL namespace Msp { namespace DataFile { +/** +Writes data in binary format. +*/ class BinaryWriter: public WriterMode { private: diff --git a/source/loader.h b/source/loader.h index 7d5d8d9..9c09336 100644 --- a/source/loader.h +++ b/source/loader.h @@ -189,11 +189,11 @@ private: /** -Base class for data loaders. To enable objects of a certain class to be loaded -from datafiles, create a public Loader class in it, derived from this class. -Typically the Loader class contains a reference to the object being loaded. If -you want to load data members of the object directly, the Loader class must -have a member function get_object() returning that reference. +Base class for data loaders. To give loading capabilities to a class, create a +public Loader class in it, derived from this class. Typically a loader object +contains a reference to the loaded object. To make use of loading directly +into data members, the Loader class must have a get_object() member function, +returning that reference. */ class Loader { @@ -214,6 +214,9 @@ public: protected: Loader(): cur_st(0) { } + /** + Adds a keyword that is loaded with a zero-argument function. + */ template void add(const std::string &k, void (L::*func)()) { actions.insert(typename ActionMap::value_type(k, new LoaderFunc0(func))); } @@ -234,6 +237,9 @@ protected: void add(const std::string &k, void (L::*func)(A0, A1, A2, A3)) { actions.insert(typename ActionMap::value_type(k, new LoaderFunc4(func))); } + /** + Adds a keyword that is loaded into a variable of the loaded object. + */ template void add(const std::string &k, T0 L::*p0) { actions.insert(typename ActionMap::value_type(k, new LoadValue1(p0))); } @@ -242,6 +248,9 @@ protected: void add(const std::string &k, T0 L::*p0, T1 L::*p1) { actions.insert(typename ActionMap::value_type(k, new LoadValue2(p0, p1))); } + /** + Adds a keyword that is recognized but ignored. + */ void add(const std::string &k) { actions.insert(ActionMap::value_type(k, 0)); } diff --git a/source/parser.h b/source/parser.h index 5bec123..c830c3c 100644 --- a/source/parser.h +++ b/source/parser.h @@ -19,19 +19,32 @@ class ParserMode; class Statement; struct Token; +/** +Frontend for loading datafiles. Handles switching between text and binary +formats. A Parser evaluates into a boolean value indicating whether more +statements may be read. +*/ class Parser { -public: - Parser(std::istream &, const std::string &); - ~Parser(); - - Statement parse(); - operator bool() const { return in; } private: Input in; std::string src; bool good; ParserMode *mode; + +public: + Parser(std::istream &i, const std::string &s); + ~Parser(); + + /** + Reads a statement from the input. If the end of input was reached, an empty + invalid statement will be returned. If an error occurs, the parser will be + marked as bad and no more statements may be read, even if the exception was + caught. + */ + Statement parse(); + + operator bool() const { return good && in; } }; } // namespace DataFile diff --git a/source/parsermode.h b/source/parsermode.h index 824525d..ae40756 100644 --- a/source/parsermode.h +++ b/source/parsermode.h @@ -15,6 +15,9 @@ namespace DataFile { class Input; +/** +Base class for parse modes. +*/ class ParserMode { protected: diff --git a/source/writer.h b/source/writer.h index 756e19a..698bade 100644 --- a/source/writer.h +++ b/source/writer.h @@ -18,6 +18,9 @@ namespace DataFile { class Statement; class WriterMode; +/** +Frontend for writing data. +*/ class Writer { private: @@ -26,9 +29,21 @@ private: bool binary; public: - Writer(std::ostream &); - void write(const Statement &); - void set_binary(bool); + Writer(std::ostream &o); + + /** + Writes a statement to the output. This function always writes a complete + statement, so it's not possible to add substatements later. + */ + void write(const Statement &st); + + /** + Sets binary or text mode. While it is possible to enter and exit binary + mode multiple times, doing so produces sub-optimal output. + + @param b true for binary mode, false for text + */ + void set_binary(bool b); }; } // namespace DataFile -- 2.45.2