These instructions are for the Microsoft Visual Studio Community Edition and for the x64 configuration.
We have placed each parser to a separate .parser file although this is not mandatory.
Start by creating a text file with an .spg extension to the directory where you have the .parser files.
We have created a file MinilangParsers.spg and placed it in the examples/minilang directory. Here's the contents of the MinilangParsers.spg:
project MinilangParsers; source <TypeParser.parser>;
An .spg file contains a project declaration followed by a source declaration for each .parser file. Each declaration is terminated by a semicolon. A project declaration consists of the keyword project followed by the name of the project and a semicolon. A source declaration consists of the keyword source followed by a .parser file path in angle brackets and a semicolon.
Here's the current contents of the TypeParser.parser containing the type parser:
parser TypeParser { Type ::= INT | BOOL | VOID ; }
Run the following command from the directory that contains the MinilangParsers.spg:
> spg -v MinilangParsers.spg
The SoulNG parser generator spg warns that a uselexer statement is missing from the TypeParser:
C:\soulng-1.0.0\examples\minilang>spg -v MinilangParsers.spg > C:/soulng-1.0.0/examples/minilang/MinilangParsers.spg > C:/soulng-1.0.0/examples/minilang/TypeParser.parser warning: 'uselexer' statement missing from 'TypeParser' parser. ==> C:/soulng-1.0.0/examples/minilang/TypeParser.hpp ==> C:/soulng-1.0.0/examples/minilang/TypeParser.cpp
The uselexer statement is necessary to connect the parser to the corresponding lexer. The name of the lexer used is MinilangLexer, so we add a uselexer MinilangLexer; statement to the parser, and run the generator again:
parser TypeParser { uselexer MinilangLexer; Type ::= INT | BOOL | VOID ; }
> spg -v MinilangParsers.spg
C:\soulng-1.0.0\examples\minilang>spg -v MinilangParsers.spg > C:/soulng-1.0.0/examples/minilang/MinilangParsers.spg > C:/soulng-1.0.0/examples/minilang/TypeParser.parser ==> C:/soulng-1.0.0/examples/minilang/TypeParser.hpp ==> C:/soulng-1.0.0/examples/minilang/TypeParser.cpp
Now the tool does not warn about anything, and has generated some C++ source code, TypeParser.hpp and TypeParser.cpp. Add the generated TypeParser.hpp and TypeParser.cpp files to the minilang project. When trying to compile the Visual Studio compiler generates error: "use of undefined type 'MinilangLexer'". The compiler has not seen the definition of the MinilangLexer class that is used in the TypeParser.cpp. The spg tool recognizes simple #include directives and places them to the start of the generated .cpp file, so we add an include to the start of the TypeParser.parser file:
#include <minilang/MinilangLexer.hpp> parser TypeParser { uselexer MinilangLexer; Type ::= INT | BOOL | VOID ; }
Then run the generator again:
> spg -v MinilangParsers.spg
Now when trying to compile the Visual Studio compiler still generates an error: "'INT': undeclared identifier".
The lexer tokens seems to be defined in the MinilangTokens.hpp, so we add another include directive and try again:
#include <minilang/MinilangLexer.hpp> #include <minilang/MinilangTokens.hpp> parser TypeParser { uselexer MinilangLexer; Type ::= INT | BOOL | VOID ; }
Visual Studio compiler still generates an error: "'INT': undeclared identifier". Looking to the MinilangTokens.hpp reveals the problem: the tokens are inside the "MinilangTokens" namespace, but the TypeParser.cpp does not contain a using directive. The spg recognizes also simple using namespace directives, and adds them to the generated .cpp file, so we add a using directive to the TypeParser.parser:
#include <minilang/MinilangLexer.hpp> #include <minilang/MinilangTokens.hpp> using namespace MinilangTokens; parser TypeParser { uselexer MinilangLexer; Type ::= INT | BOOL | VOID ; }
Then run the generator again:
> spg -v MinilangParsers.spg
Now the code compiles and links without errors.
Here's the current content of the LiteralParser.parser containing the literal parser:
parser LiteralParser { Literal ::= BooleanLiteral:booleanLiteral | IntegerLiteral:integerLiteral ; BooleanLiteral ::= TRUE | FALSE ; IntegerLiteral ::= INTLIT ; }
We have added the same uselexer, #include and using declarations as for the type parser:
#include <minilang/MinilangLexer.hpp> #include <minilang/MinilangTokens.hpp> using namespace MinilangTokens; parser LiteralParser { uselexer MinilangLexer; Literal ::= BooleanLiteral:booleanLiteral | IntegerLiteral:integerLiteral ; BooleanLiteral ::= TRUE | FALSE ; IntegerLiteral ::= INTLIT ; }
Add the LiteralParser.parser to the MinilangParsers.spg file:
project MinilangParsers; source <LiteralParser.parser>; source <TypeParser.parser>;
Then run the spg tool:
spg -v MinilangParsers.spg
Now add the generated LiteralParser.hpp and LiteralParser.cpp to the project.
This time the compilation and linking should succeed without any errors.
Here's the changed contents of the IdentifierParser.parser:
#include <minilang/MinilangLexer.hpp> #include <minilang/MinilangTokens.hpp> using namespace MinilangTokens; parser IdentifierParser { uselexer MinilangLexer; Identifier ::= ID ; }
Add the IdentifierParser.parser to the MinilangParsers.spg file:
project MinilangParsers; source <IdentifierParser.parser>; source <LiteralParser.parser>; source <TypeParser.parser>;
Then run the spg tool:
spg -v MinilangParsers.spg
Now add the generated IdentifierParser.hpp and IdentifierParser.cpp to the project, and build the project. No errors expected.
Here's the changed contents of the ExpressionParser.parser:
#include <minilang/MinilangLexer.hpp> #include <minilang/MinilangTokens.hpp> using namespace MinilangTokens; parser ExpressionParser { uselexer MinilangLexer; using LiteralParser.Literal; using IdentifierParser.Identifier; Expression ::= EqualityExpression:expr ; PrimaryExpression ::= Literal:literal | Identifier:identifier | LPAREN Expression:expression RPAREN ; PostfixExpression ::= PrimaryExpression:primary (LPAREN ExpressionList:args? RPAREN)* ; ExpressionList ::= Expression:left (COMMA Expression:right)* ; UnaryExpression ::= UnaryOperator:op UnaryExpression:unaryExpr | PostfixExpression:postfixExpr ; UnaryOperator ::= PLUS | MINUS | NOT ; MultiplicativeExpression ::= UnaryExpression:left (MultiplicativeOperator:op UnaryExpression:right)* ; MultiplicativeOperator ::= MUL | DIV | MOD ; AdditiveExpression ::= MultiplicativeExpression:left (AdditiveOperator:op MultiplicativeExpression:right)* ; AdditiveOperator ::= PLUS | MINUS ; RelationalExpression ::= AdditiveExpression:left (RelationalOperator:op AdditiveExpression:right)* ; RelationalOperator ::= LESS | GREATER | LEQ | GEQ ; EqualityExpression ::= RelationalExpression:left (EqualityOperator:op RelationalExpression:right)* ; EqualityOperator ::= EQ | NEQ ; }
Add the ExpressionParser.parser to the MinilangParsers.spg file:
project MinilangParsers; source <ExpressionParser.parser>; source <IdentifierParser.parser>; source <LiteralParser.parser>; source <TypeParser.parser>;
Then run the spg tool:
spg -v MinilangParsers.spg
Add the generated ExpressionParser.hpp and ExpressionParser.cpp to the project, and build the project.
Add this time Visual Studio generates an error: 'LiteralParser': is not a class or namespace name. The expression parser uses the LiteralParser and the IdentifierParser, but the compiler has seen no declarations for them. We need to add the following #include declarations to the ExpressionParser.parser, run spg, and then build again:
#include <minilang/LiteralParser.hpp> #include <minilang/IdentifierParser.hpp> // ...
Now the project builds again.
Here's the changed contents of the StatementParser.parser:
#include <minilang/ExpressionParser.hpp> #include <minilang/TypeParser.hpp> #include <minilang/IdentifierParser.hpp> #include <minilang/MinilangLexer.hpp> #include <minilang/MinilangTokens.hpp> using namespace MinilangTokens; parser StatementParser { uselexer MinilangLexer; using ExpressionParser.Expression; using TypeParser.Type; using IdentifierParser.Identifier; Statement ::= IfStatement:ifS | WhileStatement:whileS | ReturnStatement:returnS | ConstructionStatement:constructionS | AssignmentStatement:assignmentS | CompoundStatement:compoundS ; IfStatement ::= IF LPAREN Expression:condition RPAREN Statement:thenS (ELSE Statement:elseS)? ; WhileStatement ::= WHILE LPAREN Expression:condition RPAREN Statement:statement ; ReturnStatement ::= RETURN Expression:returnValue? SEMICOLON ; ConstructionStatement ::= Type:type Identifier:variableName ASSIGN Expression:value SEMICOLON ; AssignmentStatement ::= Identifier:variableName ASSIGN Expression:value SEMICOLON ; CompoundStatement ::= LBRACE Statement:statement* RBRACE ; }
This time we have added the needed #includes for ExpressionParser.hpp, TypeParser.hpp and IdentifierParser.hpp.
Add the StatementParser.parser to the MinilangParsers.spg file:
project MinilangParsers; source <ExpressionParser.parser>; source <IdentifierParser.parser>; source <LiteralParser.parser>; source <StatementParser.parser>; source <TypeParser.parser>;
Run the spg tool and build. No errors expected.
spg -v MinilangParsers.spg
Here's the changed contents of the FunctionParser.parser:
#include <minilang/TypeParser.hpp> #include <minilang/IdentifierParser.hpp> #include <minilang/StatementParser.hpp> #include <minilang/MinilangLexer.hpp> #include <minilang/MinilangTokens.hpp> using namespace MinilangTokens; parser FunctionParser { uselexer MinilangLexer; using TypeParser.Type; using IdentifierParser.Identifier; using StatementParser.CompoundStatement; Function ::= Type:returnType Identifier:functionName LPAREN ParameterList:params? RPAREN CompoundStatement:functionBody ; ParameterList ::= Parameter:left (COMMA Parameter:right)* ; Parameter ::= Type:type Identifier:name ; }
A source file parser is different from the other parsers that it is expected to parse an entire file content. We call it a main parser.
A main parser is declared by including a main statement to the parser definition. A main statement consists of the keyword main followed by a semicolon.
Nothing prevents from including the main statement in every parser, so that they could be tested separately.
Here's the changed contents of the SourceFileParser.parser with a main statement:
#include <minilang/FunctionParser.hpp> #include <minilang/MinilangLexer.hpp> #include <minilang/MinilangTokens.hpp> using namespace MinilangTokens; parser SourceFileParser { uselexer MinilangLexer; main; using FunctionParser.Function; SourceFile ::= Function:function* ; }
We have added these files to the MinilangParsers.spg, run the spg tool, and built:
C:\soulng-1.0.0\examples\minilang>spg -v MinilangParsers.spg > C:/soulng-1.0.0/examples/minilang/MinilangParsers.spg > C:/soulng-1.0.0/examples/minilang/ExpressionParser.parser ==> C:/soulng-1.0.0/examples/minilang/ExpressionParser.hpp ==> C:/soulng-1.0.0/examples/minilang/ExpressionParser.cpp > C:/soulng-1.0.0/examples/minilang/FunctionParser.parser ==> C:/soulng-1.0.0/examples/minilang/FunctionParser.hpp ==> C:/soulng-1.0.0/examples/minilang/FunctionParser.cpp > C:/soulng-1.0.0/examples/minilang/IdentifierParser.parser ==> C:/soulng-1.0.0/examples/minilang/IdentifierParser.hpp ==> C:/soulng-1.0.0/examples/minilang/IdentifierParser.cpp > C:/soulng-1.0.0/examples/minilang/LiteralParser.parser ==> C:/soulng-1.0.0/examples/minilang/LiteralParser.hpp ==> C:/soulng-1.0.0/examples/minilang/LiteralParser.cpp > C:/soulng-1.0.0/examples/minilang/SourceFileParser.parser ==> C:/soulng-1.0.0/examples/minilang/SourceFileParser.hpp ==> C:/soulng-1.0.0/examples/minilang/SourceFileParser.cpp > C:/soulng-1.0.0/examples/minilang/StatementParser.parser ==> C:/soulng-1.0.0/examples/minilang/StatementParser.hpp ==> C:/soulng-1.0.0/examples/minilang/StatementParser.cpp > C:/soulng-1.0.0/examples/minilang/TypeParser.parser ==> C:/soulng-1.0.0/examples/minilang/TypeParser.hpp ==> C:/soulng-1.0.0/examples/minilang/TypeParser.cpp
Now the entire project is expected to build without errors. Next we will see how to test the generated parsers...
up: Table of contents | prev: Writing Parsers | next: Testing the Generated Parsers