Today I published a toy project, that I worked on in the last couple of weeks. It is an LR Parser generator. I normally use yecc in my projects for parsing. It works ok, but I am not happy with usability. Besides that it seems to have issues with special (utf-8) characters. I also tried other libraries (like xpet), but struggling to use them for my purpose (probably my fault understanding the concepts). I created an LR parser years ago in c# and always dreamed of redoing it in elixir.
The parser is defined using a DSL:
use ExLR
lr skip_whitespaces: true do
S <- S + "+" + :integer = fn ([a, _, b]) -> a + b end
S <- :integer = fn ([a]) -> a end
end
It provides a parse function that can be used like
# parse("3+4")
{:ok, 7}
It contains a scanner, but it can also be called with a list of symbols (using a different scanner). Each symbol is a tuple of 3 containing the symbol, the data and the position:
parse([{:integer, 3, {0, 0}}, {"+", nil, {0, 1}}, {:integer, 4, {0, 2}}, {:"$", nil, {0, 3}}])
The scanner is initialised by going through the rules. It accepts:
- Strings
- :integer
- :text
- :quoted_text
- :ws
Special terminals can also be defined:
terminal :zip_code, chars: ?0..?9, min: 4, max: 5
lr skip_whitespaces: true do
Address <- Zip + City = fn [zip, city] -> %{zip: zip, city: city} end
Zip <- :zip_code
City <- :text
end
You can find the repository here: GitHub - mlankenau/exlr
I put a couple of examples in the test folder. I think they are a good reference.
I hope it is adding some values for other devs and highly appreciate any feedback.
Happy easter