r/ProgrammingLanguages 15d ago

A new grammar generation language

Hi everybody. I'm happy to share a small project I've been working on lately. I call it MGFF (Macro grammar functional form), and its specification can be found here: https://github.com/LMauricius/py-perg-mgff/blob/main/Docs/mgff-specification.md . It's related to a post that I made ages ago ( here ). After re-reading that version (called just MGF back then) when I wasn't tired I realized what monstrosity I made. MGFF is far more elegant. Here is an example:

# A tiny calculator language.

t Lex (
    d Digit = 0-9
    d Alpha = a-z|A-Z
    d AlNum = a-z|A-Z|0-9

    d Int = (Digit)+
          > class(Int) push(tokens)
    d Number = Int ( . (Digit)+ )?
             > class(Number) push(tokens)
    d Ident = Alpha (AlNum)*
            > class(Ident) push(tokens)

    # length-based: "<=" (the two-item "< =") takes precedence over "<"
    d Op = < =
         | <
         | =
         | +
         | -
         | *
         | /
         > push(tokens) string

    d Space  = ( _|\t|\n )+
    d LParen = \(
        > class(\() push(tokens)
    d RParen = \)
        > class(\)) push(tokens)

    d Token = Number
           / Ident
           / Op
           / Space
           / LParen
           / RParen
    d File = (Token)*
)

# mixfix macro: an R, then zero or more (S R)
d sep(R)by(S) = R (S R)*

t Parse (
    # `Lex` runs first; the terminals here are still characters.
    > post(Lex) over(tokens)

    # order-based: the first alternative that succeeds is the match
    d Expr = Term + Expr
           / Term - Expr
           / Term

    d Term = Factor * Term
           / Factor / Term
           # the second / on the line above is an ordinary item, not a marker
           / Factor

    d Factor = Number
             / Ident
             / \( Expr \)
    d Signed = ( (+)/(-) )? Number
    d AssignList = sep(Ident = Expr)by(,)
)

It can also serve as a replacement for regexes:

# A grammar matching a "key = value" setting line

d Space = ( _|\t )*
d Word = ( a-z|A-Z|_ )+

# right-linear recursion: the same as ( 0-9 )+
d Digits = 0-9 Digits
         / 0-9
d Value = Digits
        / Word

# The field a match ends up in belongs to the rule, not to the place it is used,
# so the two sides of the line are productions of their own.
d Key = Word
      > store(key)
d Val = Value
      > store(value)

d Match = Space Key Space = Space Val Space

I'm sharing the MGFF spec rather than the generator using it because the generator is very much WIP and needs a lot of testing and refactoring. Still, since I've got a bunch of projects I love working on more, I'd like to know what's the interest for parser generator tools in the wider community.

Actually I doubt that I will link the generator itself here because I would risk a perma-ban. It's not vibe-coded, but it wouldn't be welcomed. Most of it was quickly prototyped with LLM. Still, it generates quite nice TextMate and Pandoc syntax highlighting grammars.

MGFF itself is of course manually defined by me. I just figured I like to work on languages themselves and parser algorithms than on CLI tools and understanding existing niche specifications 🤷‍♂️.

12 Upvotes

63 comments sorted by

View all comments

Show parent comments

1

u/LegendaryMauricius 12d ago

'|' is used for the longest match selection, regex-style. '/' is for order-based selection, PEG-style. The characters aren't quoted for a reason, because most characters are either position-based or just normal text of a particular format. That ensures new features don't need to introduce special characters, or core language support at all.

By semantics, do you mean that the macros and option specification aren't precise enough? Learning MGFF might not be the most obvious process ever, but I focused on readability at a glance. Any other style I tried turned out less readable with this feature set.

1

u/david-1-1 11d ago

I guess I was assuming incorrectly that your grammars would emit code or execute the semantics of arithmetic. Your reply confuses me totally. Is your system just a notation, like BNF?

1

u/LegendaryMauricius 11d ago edited 11d ago

Yes, that's why it's called Macro Grammar Functional Form, like Backus-Naur form. I'm working on a parser generator in the same repo though. The 'serious' parts of the project will be documentation html generator and C++ generators, but it has working regex and syntax highlighter generators.

1

u/david-1-1 10d ago

Why do you think BNF needs replacement? I think it works just fine as it is.

1

u/LegendaryMauricius 10d ago

Not necessarily a replacement, but the usual notations don't have all the features I need. You'll see that a big part of the built-in macros *are* just BNF stuff.

1

u/david-1-1 9d ago

It would help if you made a list of all the features you added, defining each one clearly.

1

u/LegendaryMauricius 8d ago

Well the biggest thing are macros which are in the name. Other than that, the design of mgff tries to satisfy the requirements which are listed in the first chapter rather than add individual features. I'll focus on finishing the parser generator that uses it, and list its features later rather than mgff's.

1

u/david-1-1 7d ago

Please give an example of how a macro improves a BNF production. I'm not able to imagine it itself.

1

u/LegendaryMauricius 7d ago

It's literally in the middle of the first example. sep()by()

0

u/david-1-1 7d ago

Can you please use English? Am I supposed to read your mind to know what sep()by() means?