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; }