Reputation: 7015
I'm creating a Propositional Logic Theorem Prover in Erlang, but I'm unable to get my head around parsing a list to a tree.
tokenise([]) -> [];
tokenise([$( | T]) -> [{bracket, left}| tokenise(T)];
tokenise([$) | T]) -> [{bracket, right}| tokenise(T)];
tokenise([$& | T]) -> [{logicAnd} | tokenise(T)];
tokenise([$| | T]) -> [{logicOr} | tokenise(T)];
tokenise([$! | T]) -> [{logicNot} | tokenise(T)];
tokenise([X | T]) -> [{prop, X} | tokenise(T)].
Input: (A!B)
Current output:
[{bracket,left},
{prop,65},
{logicNot},
{prop,66},
{bracket,right}]
Output needed:
[ logicNot { A, B } ]
Any help would be appreciated.
Upvotes: 1
Views: 1484
Reputation: 16577
It looks like you are creating your own logic language via scanning and parsing. Have you looked at leex and yecc in the Erlang standard library to do this for you? (A good tutorial can be found here)
Using leex, you can write a scanner in the file test_scanner.xrl
as follows:
Definitions.
W = [a-zA-Z0-1]
S = [\s\t\n\r\f\v\d]
Rules.
{W}+ : {token, {prop, TokenChars, TokenLine}}.
\( : {token, {'(', TokenLine}}.
\) : {token, {')', TokenLine}}.
\! : {token, {'!', TokenLine}}.
{S}+ : skip_token.
Erlang code.
Compile it:
$ erlc test_scanner.xrl # This produces an normal Erlang file
$ erlc test_scanner.erl # This compiles the actual beam file
Use it:
1> l(test_scanner).
{module,test_scanner}
2> {ok, Tokens, _EndLine} = test_scanner:string("(a ! b) ! c").
{ok,[{'(',1},
{prop,"a",1},
{'!',1},
{prop,"b",1},
{')',1},
{'!',1},
{prop,"c",1}],
1}
Using yecc, you can write a parser in the file test_parser.yrl
as follows:
Terminals prop '!' '(' ')'.
Nonterminals expr.
Rootsymbol expr.
Left 100 '!'.
expr -> '(' expr ')' : '$2'.
expr -> expr '!' expr : {logicNot, '$1', '$3'}.
expr -> prop : prop('$1').
Erlang code.
prop({prop, Name, _Line}) -> Name.
Compile it:
$ erlc test_parser.yrl # This produces an normal Erlang file
$ erlc test_parser.erl # This compiles the actual beam file
Use it:
3> test_parser:parse(Tokens).
{ok,{logicNot,{logicNot,"a","b"},"c"}}
This gives you a simple binary tree structure based on tuples:
{logicNot,
{logicNot,
"a",
"b"},
"c"}}
Upvotes: 4
Reputation: 2173
Your output is what I would call syntactic analysis. You have transformed your input into a normalized, tree form which produced a syntactically correct expression in your language.
Next take that output and recursively walk it constructing the target output.
By the way, I would suggest that you change you operators to be a 2-tuple of {Op, operator} - {Op, logicNot}, for example. I think you will find it easier to write the next phase if you do.
So as a hint (this code is NOT good),
do([]) ->
"";
do({prop,C}) ->
[C];
do([{bracket,left} | Tl]) ->
lists:append(["[ ", do(Tl),"] "]);
do([A, {logicNot}|Tl]) ->
lists:append(["logicNot { ", do(A), ",", do(Tl), " }"]);
do([{prop, C}, {bracket, right}]) ->
[C].
Basically, you are going to write a a recursive method, p, that maps things like [{ A Op B}] to [Op {p(A), p(B)}]...
Upvotes: 1
Reputation: 20014
You currently have a lexer recognizing tokens, but you lack a parser that recognizes valid sequences of tokens and reduces them based on grammar rules. I suggest you look into using leex
to construct your lexer and yecc
to construct your parser.
Upvotes: 2