Ruco
Ruco generates the boilerplate code for Coco/R. It has a very simple DSL that generates C++ code and the ATG file.
Installation
Add this line to your application's Gemfile:
gem 'ruco-cpp'
And then execute:
$ bundle
Or install it yourself as:
$ gem install ruco-cpp
Usage
A very simple ruco file looks like this:
# mygrammar.ruco
token "Type", :pascal_case # There is a token named Type and has PascalCase
token "Name", :camel_case # There is a token named Name and has camelCase
token "Integer", :integer # There is a token named Integer and is an integer
grammar "Statement" do # This is equivalent to a production in Coco/R
one Type
one Name
end
grammar "Format" do
one group { # Group things together using the group method
one "format"
one "{"
many Statement # One or more Statements
one "}"
}
end
maybemany Format # Zero or more Formats
Code Generation
Generate the code by doing:
$ ruco mygrammar.ruco MyGrammar
This will write the following files in the current directory:
-
MyGrammar.atg
- the grammar for coco/R -
Parser.cpp
- parser code generated by coco/R -
Scanner.cpp
- scanner code generated by coco/R -
parse_MyGrammar.cpp
- code for parsing MyGrammar picojson.hpp
-
MyGrammar.hpp
- data structures for MyGrammar Parser.h
Scanner.h
parse_MyGrammar.hpp
-
Makefile
- creates one if it does not find one in the current directory. This is a simple Makefile that builds all files in the current directory
Using the generated code
It is up to use the functions in parse_MyGrammar.hpp
. There are two functions:
namespace MyGrammar
{
/**
* Parses a source file into the data structure of MyGrammar
*/
MyGrammarPtr Parse(std::string sourceFile);
/**
* Transforms the data structure of MyGrammar to an abstract syntax tree in JSON format
*/
picojson::value Jsonify(MyGrammarPtr parseResult);
}
Simply call Parse()
on a source file that follows your grammar and it will return a std::shared_ptr
containing the AST. If you wish to see or process the AST with another tool, you can export it by calling Jsonify()
on the parse result.
The following example main.cpp
takes a file called test.lang
and outputs the AST of the file in JSON format to the console.
#include "parse_MyGrammar.hpp"
int main()
{
auto s = MyGrammar::Parse("test.lang");
auto json = MyGrammar::Jsonify(s);
std::wcout << json.serialize() << std::endl;
return EXIT_SUCCESS;
}
Building the code
As shown above ruco will generate a Makefile for you. However the code will not compile unless you have a main()
function. You need to write this code yourself.
Feel free to ignore the Makefile if you wish to use the code generated as a library instead.
Reference
Ruco files are made of statements that define elements of your language.
-
token
- A string of characters that meet a particular criteria -
variation
- A set of grammars or tokens that can appear in the same place (are variations of an element) -
grammar
- A production that contains a sub-set of your language
Within each grammar you need to declare elements of your language. The file itself is a grammar.
-
group
- a set of elements that come one after another -
either
- a set of elements that can appear in the same place -
one
- one of this element -
many
- one or more of this element -
maybe
- zero or one of this element -
maybemany
- zero or more of this element
More details are shown below:
token
A token takes a string and a type of token it is. Tokens available are:
:camelcase
:pascalcase
:integer
:string
Example:
token "VariableName", :camelcase
variation
A variation is an element that is the base production of another set of elements.
Example:
grammar "IntegerLiteral" do
one Number
end
grammar "MemberName" do
one MemberIdentifier
end
variation "Expression", MemberName, IntegerLiteral
grammar
A grammar declares a subset of the language.
Example:
grammar "ArrayDef" do
one "["
one Expression
one "]"
end
Getting Started
Here is a simple tutorial to get you started using ruco!
First of all, make a new directory and enter it.
mkdir tutorial
cd tutorial
Then, make a Gemfile and specify that you want to use ruco-cpp
source "https://rubygems.org"
gem "ruco-cpp"
Install ruco-cpp this way
bundle
Now let us make a simple grammar that can parse an addition operation like 1+1
In order to do so, we need to specify that there is a number, followed by a plus sign, followed by a number.
We then need to create a new file lets call it example.ruco
and write the following in it:
token "NumberLiteral", :number
grammar "Binary" do
one NumberLiteral
one "+"
one NumberLiteral
end
one Binary
Also we will need a test case. So let us make a file called test.example
with the following:
5 + 6
Excellent. Now in the command line, we run ruco like so:
bundle exec ruco example.ruco
This will produce all the files needed to run this example, and generates an API to access the AST.
For now, let us simply compile it:
make
After this, simply run the test application that was created like this:
./example_parse
You should see some JSON in the output. The following is pretty printed, but you should receive a similar output anyway.
{
"_col": 1,
"_line": 1,
"_type": "Example",
"binary": {
"_col": 1,
"_line": 1,
"_type": "Binary",
"numberliterals": [
{
"_col": 1,
"_line": 1,
"_token": "5",
"_type": "NumberLiteral"
},
{
"_col": 3,
"_line": 1,
"_token": "6",
"_type": "NumberLiteral"
}
]
}
}
This is the AST of the test file test.example
we created earlier. Now you can make use of this AST to do whatever processing you want for your compiler!
Development
After checking out the repo, run bin/setup
to install dependencies. Then, run rake rspec
to run the tests. You can also run bin/console
for an interactive prompt that will allow you to experiment.
To install this gem onto your local machine, run bundle exec rake install
. To release a new version, update the version number in version.rb
, and then run bundle exec rake release
, which will create a git tag for the version, push git commits and tags, and push the .gem
file to rubygems.org.
Contributing
Bug reports and pull requests are welcome on GitHub at https://github.com/davidsiaw/ruco. This project is intended to be a safe, welcoming space for collaboration, and contributors are expected to adhere to the Contributor Covenant code of conduct.
License
The gem is available as open source under the terms of the MIT License.