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