Lecc and Yecc - trying to take some plain text and turn it into a model

I am trying to take some plain text and turn it into a model.
More specifically take a chordpro file and turn it into a struct.

I thought I could maybe use lecc and yecc to do this:

For example,

  @songexample """
  {title:Take It Easy}
  {st:Eagles}

  Well I'm a [G]runnin' down the road try'n to loosen my load

  I've got seven women [D]on my [C]mind

  """

And turn it into something like this:


%{
      title: "Take it Easy",
      by: "Eagles",
      chords: ["G"],
      lines: [
        %{
          line: [
            %{
              linetype: "lyric",
              content: "Well I'm a"
            },
            %{
              linetype: "chord",
              content: "C"
            }
          ]
        }
      ]
    }

OR...

    %{
      "title" => "Take It Easy",
      "by" => "Eagles",
      "chords" => [
        %{
          "name" => "A"
        }
      ],
      "lines" => [
        %{
          "line" => [
            %{
              "type" => "lyric",
              "content" => "Well I'm a"
            },
            %{
              "type" => "chord",
              "content" => "[G]"
            },

perhaps.

It struck me that perhaps a I could use lecc and yecc.

So I have this:

Definitions.

START_CURLY     = {
END_CURLY       = }
DIRECTIVE_SEP   = :
CHORD           = \[[a-zA-Z\s,.'\-+_#0-9]+\]
TEXT            = [a-zA-Z\s,.'\-+_#]*
WHITESPACE      = [\t\n\r]+

Rules.

{START_CURLY}   : {token, {start_directive, TokenLine}}.
{DIRECTIVE_SEP} : {token, {directive_sep, TokenLine}}.
{END_CURLY}     : {token, {end_directive, TokenLine}}.
{CHORD}         : {token, {chord, TokenLine, TokenChars}}.
{TEXT}          : {token, {text, TokenLine, TokenChars}}.
{WHITESPACE}    : skip_token.

Erlang code.

Which produces this:

[
  {:start_directive, 1},
  {:text, 1, ~c"title"},
  {:directive_sep, 1},
  {:text, 1, ~c"Take It Easy"},
  {:end_directive, 1},
  {:start_directive, 2},
  {:text, 2, ~c"st"},
  {:directive_sep, 2},
  {:text, 2, ~c"Eagles"},
  {:end_directive, 2},
  {:text, 4, ~c"Well I'm a "},
  {:chord, 4, ~c"[G]"},
  {:text, 4, ~c"runnin' down the road try'n to loosen my load"},
  {:text, 6, ~c"I've got seven women "},
  {:chord, 6, ~c"[D]"},
  {:text, 6, ~c"on my "},
  {:chord, 6, ~c"[C]"},
  {:text, 6, ~c"mind"}
]

Which seems reasonable…
and the yecc parser

Nonterminals
    song
    lines
    line
    elements
    element
    directive.

Terminals
    start_directive
    end_directive
    directive_sep
    chord
    text.

Rootsymbol song.

song -> lines : {song, '$1'}.

lines -> line : '$1'.
% lines -> line lines : ['$1'|'$2'].

line -> elements : {properties, '$1'}.

elements -> element : ['$1'].
elements -> element elements : ['$1'|'$2'].

element -> chord : {chord, unwrap('$1')}.
element -> text : {text, unwrap('$1')}.
element -> directive : '$1'.

directive -> start_directive text directive_sep text end_directive : {list_to_atom(unwrap('$2')), unwrap('$4')}.

Erlang code.

unwrap({_, _, Content}) -> Content.

Which is not quite there…

{:ok,
 {:song,
  {:properties,
   [
     title: ~c"Take It Easy",
     st: ~c"Eagles",
     text: ~c"Well I'm a ",
     chord: ~c"[G]",
     text: ~c"runnin' down the road try'n to loosen my load",
     text: ~c"I've got seven women ",
     chord: ~c"[D]",
     text: ~c"on my ",
     chord: ~c"[C]",
     text: ~c"mind"
   ]}}}

I think I have the xrl file more or less understood.

But I have been struggling with with the yrl part where I have arrived at it through fumbling and intuition and a little AI but I haven’t really figured out how to get to

%{
      title: "Take it Easy",
      by: "Eagles",
      chords: ["G"],
      lines: [
        %{
          line: [
            %{
              linetype: "lyric",
              content: "Well I'm a"
            },
            %{
              linetype: "chord",
              content: "C"
            }
          ]
        }
      ]
    }

I am not quite understanding how the yecc part reads the tokens and how the left part and right part work :confused:

Have you seen this post before? Using Leex and Yecc in Elixir

I haven’t used Leex and Yecc myself yet, but when I was doing some research I found this to be an extremely useful resource.

2 Likes

That is extremely helpful, I haven’t seen that, best explanation for me so far!

Thank you

1 Like