For this skeleton lexer:
// ExampleLexer.lexer:
tokens ExampleTokens
{
(ID, "identifier"), (WHILE, "'while'"), (LPAREN, "'('"), (RPAREN, "')'"), (SEMICOLON, "';'")
}
keywords ExampleKeywords
{
("while", WHILE)
}
expressions
{
ws = "[\n\r\t ]";
newline = "\r\n|\n|\r";
linecomment = "//[^\n\r]*{newline}";
blockcomment = "/\*([^*]|\*[^/])*\*/";
comment = "{linecomment}|{blockcomment}";
separators = "({ws}|{comment})+";
id = "{idstart}{idcont}*";
}
lexer ExampleLexer
{
"{separators}" {}
"{id}" { int kw = GetKeywordToken(token.match); if (kw == INVALID_TOKEN) return ID; else return kw; }
"\(" { return LPAREN; }
"\)" { return RPAREN; }
";" { return SEMICOLON; }
}
...and this skeleton AST:
// ExampleAST.hpp:
#ifndef EXAMPLEAST_HPP
#define EXAMPLEAST_HPP
#include <string>
class Node
{
// ...
};
class WhileStatementNode : public Node
{
public:
WhileStatementNode(Node* cond_, Node* stmt_);
// ...
};
class EmptyStatementNode : public Node
{
// ...
};
class IdentifierNode : public Node
{
public:
IdentifierNode(const std::u32string& str_);
};
class SymbolTable
{
// ...
};
#endif // EXAMPLEAST_HPP
... and this skeleton parser:
[hpp]#include <ExampleAST.hpp>
[cpp]#include <ExampleLexer.hpp>
[cpp]#include <ExampleTokens.hpp>
#include <boost/filesystem.hpp>
using namespace ExampleTokens;
using namespace boost::filesystem;
parser ExampleParser
{
uselexer ExampleLexer;
Statement(SymbolTable* symbolTable) : Node*
::= WhileStatement(symbolTable):whileStatement{ return whileStatement; }
| EmptyStatement:emptyStatement{ return emptyStatement; }
;
WhileStatement(SymbolTable* symbolTable) : Node*
::= WHILE LPAREN Expression:cond RPAREN Statement(symbolTable):stmt{ return new WhileStatementNode(cond, stmt); }
;
EmptyStatement : Node*
::= SEMICOLON{ return new EmptyStatementNode(); }
;
Expression : Node*
::= ID{ soulng::lexer::Token token = lexer.GetToken(pos); return new IdentifierNode(token.match.ToString()); }
// ....
;
}
The spg tool generates the following header file:
// ExampleParser.hpp:
#ifndef EXAMPLEPARSER_HPP
#define EXAMPLEPARSER_HPP
#include <ExampleAST.hpp>
#include <soulng/lexer/Token.hpp>
#include <soulng/parser/Match.hpp>
#include <soulng/parser/Value.hpp>
// this file has been automatically generated from 'D:/work/soulng-project/doc/topics/syntax/ast/ExampleParser.parser' using soulng parser generator spg version 1.0.0
class ExampleLexer;
struct ExampleParser
{
static soulng::parser::Match Statement(ExampleLexer& lexer, SymbolTable* symbolTable);
static soulng::parser::Match WhileStatement(ExampleLexer& lexer, SymbolTable* symbolTable);
static soulng::parser::Match EmptyStatement(ExampleLexer& lexer);
static soulng::parser::Match Expression(ExampleLexer& lexer);
};
#endif // EXAMPLEPARSER_HPP
And the following source file:
// ExampleParser.cpp:
#include "ExampleParser.hpp"
#include <soulng/util/Unicode.hpp>
#include <ExampleLexer.hpp>
#include <ExampleTokens.hpp>
#include <boost/filesystem.hpp>
// this file has been automatically generated from 'D:/work/soulng-project/doc/topics/syntax/ast/ExampleParser.parser' using soulng parser generator spg version 1.0.0
using namespace soulng::unicode;
using namespace ExampleTokens;
using namespace boost::filesystem;
soulng::parser::Match ExampleParser::Statement(ExampleLexer& lexer, SymbolTable* symbolTable)
{
std::unique_ptr<Node> whileStatement;
std::unique_ptr<Node> emptyStatement;
soulng::parser::Match match(false);
soulng::parser::Match* parentMatch0 = &match;
{
int save = lexer.GetPos();
soulng::parser::Match match(false);
soulng::parser::Match* parentMatch1 = &match;
{
int pos = lexer.GetPos();
soulng::parser::Match match = ExampleParser::WhileStatement(lexer, symbolTable);
whileStatement.reset(static_cast<Node*>(match.value));
if (match.hit)
{
return soulng::parser::Match(true, whileStatement.release());
}
*parentMatch1 = match;
}
*parentMatch0 = match;
if (!match.hit)
{
soulng::parser::Match match(false);
soulng::parser::Match* parentMatch2 = &match;
lexer.SetPos(save);
{
soulng::parser::Match match(false);
soulng::parser::Match* parentMatch3 = &match;
{
int pos = lexer.GetPos();
soulng::parser::Match match = ExampleParser::EmptyStatement(lexer);
emptyStatement.reset(static_cast<Node*>(match.value));
if (match.hit)
{
return soulng::parser::Match(true, emptyStatement.release());
}
*parentMatch3 = match;
}
*parentMatch2 = match;
}
*parentMatch0 = match;
}
}
return match;
}
soulng::parser::Match ExampleParser::WhileStatement(ExampleLexer& lexer, SymbolTable* symbolTable)
{
std::unique_ptr<Node> cond;
std::unique_ptr<Node> stmt;
soulng::parser::Match match(false);
soulng::parser::Match* parentMatch0 = &match;
{
soulng::parser::Match match(false);
soulng::parser::Match* parentMatch1 = &match;
{
soulng::parser::Match match(false);
soulng::parser::Match* parentMatch2 = &match;
{
soulng::parser::Match match(false);
soulng::parser::Match* parentMatch3 = &match;
{
soulng::parser::Match match(false);
if (*lexer == WHILE)
{
++lexer;
match.hit = true;
}
*parentMatch3 = match;
}
if (match.hit)
{
soulng::parser::Match match(false);
soulng::parser::Match* parentMatch4 = &match;
{
soulng::parser::Match match(false);
if (*lexer == LPAREN)
{
++lexer;
match.hit = true;
}
*parentMatch4 = match;
}
*parentMatch3 = match;
}
*parentMatch2 = match;
}
if (match.hit)
{
soulng::parser::Match match(false);
soulng::parser::Match* parentMatch5 = &match;
{
soulng::parser::Match match = ExampleParser::Expression(lexer);
cond.reset(static_cast<Node*>(match.value));
*parentMatch5 = match;
}
*parentMatch2 = match;
}
*parentMatch1 = match;
}
if (match.hit)
{
soulng::parser::Match match(false);
soulng::parser::Match* parentMatch6 = &match;
{
soulng::parser::Match match(false);
if (*lexer == RPAREN)
{
++lexer;
match.hit = true;
}
*parentMatch6 = match;
}
*parentMatch1 = match;
}
*parentMatch0 = match;
}
if (match.hit)
{
soulng::parser::Match match(false);
soulng::parser::Match* parentMatch7 = &match;
{
soulng::parser::Match match(false);
soulng::parser::Match* parentMatch8 = &match;
{
int pos = lexer.GetPos();
soulng::parser::Match match = ExampleParser::Statement(lexer, symbolTable);
stmt.reset(static_cast<Node*>(match.value));
if (match.hit)
{
return soulng::parser::Match(true, new WhileStatementNode(cond.release(), stmt.release()));
}
*parentMatch8 = match;
}
*parentMatch7 = match;
}
*parentMatch0 = match;
}
return match;
}
soulng::parser::Match ExampleParser::EmptyStatement(ExampleLexer& lexer)
{
soulng::parser::Match match(false);
soulng::parser::Match* parentMatch0 = &match;
{
int pos = lexer.GetPos();
soulng::parser::Match match(false);
if (*lexer == SEMICOLON)
{
++lexer;
match.hit = true;
}
if (match.hit)
{
return soulng::parser::Match(true, new EmptyStatementNode);
}
*parentMatch0 = match;
}
return match;
}
soulng::parser::Match ExampleParser::Expression(ExampleLexer& lexer)
{
soulng::parser::Match match(false);
soulng::parser::Match* parentMatch0 = &match;
{
int pos = lexer.GetPos();
soulng::parser::Match match(false);
if (*lexer == ID)
{
++lexer;
match.hit = true;
}
if (match.hit)
{
soulng::lexer::Token token = lexer.GetToken(pos);
return soulng::parser::Match(true, new IdentifierNode(token.match.ToString()));
}
*parentMatch0 = match;
}
return match;
}