Skip to content

Instantly share code, notes, and snippets.

@siburu
Created February 12, 2011 15:10
Show Gist options
  • Save siburu/823812 to your computer and use it in GitHub Desktop.
Save siburu/823812 to your computer and use it in GitHub Desktop.
-module(parse).
-export([parse/1]).
% parse("((1+2)*3)") => {mul,{add,{num,1},{num,2}},{num,3}}
parse(Str) ->
{Parsed, []} = parse_addsub(nil, nil, skip_space(Str)),
Parsed.
parse_addsub(Left, Op, Str) ->
{Term, Rest} = parse_muldiv(nil, nil, Str),
NewLeft = case Left of
nil -> Term;
_ -> {Op, Left, Term}
end,
case Rest of
[] -> {NewLeft, []};
[$)|_] -> {NewLeft, Rest};
[$+|NewStr] -> parse_addsub(NewLeft, add, NewStr);
[$-|NewStr] -> parse_addsub(NewLeft, sub, NewStr)
end.
parse_muldiv(Left, Op, Str) ->
{Term, Rest} = pop(Str),
NewLeft = case Left of
nil -> Term;
_ -> {Op, Left, Term}
end,
case Rest of
[] -> {NewLeft, []};
[$)|_] -> {NewLeft, Rest};
[$+|_] -> {NewLeft, Rest};
[$-|_] -> {NewLeft, Rest};
[$*|NewStr] -> parse_muldiv(NewLeft, mul, NewStr);
[$/|NewStr] -> parse_muldiv(NewLeft, dvd, NewStr)
end.
pop(Str) ->
[Head|Rest] = skip_space(Str),
case Head of
$~ ->
{Term, AfterTerm} = pop(Rest),
{{minus, Term}, AfterTerm};
$( ->
{Par, [$)|AfterPar]} = parse_addsub(nil, nil, Rest),
{Par, skip_space(AfterPar)};
N when (N >= $0) and (N =< $9) ->
{Num, AfterNum} = pop_num([Head|Rest]),
{{num, Num}, skip_space(AfterNum)}
end.
skip_space([$ |Rest]) -> skip_space(Rest);
skip_space(Str) -> Str.
pop_num(Str) ->
pop_num(Str, 0).
pop_num([N|Rest], Num) when (N >= $0) and (N =< $9) ->
pop_num(Rest, Num * 10 + (N - $0));
pop_num(Str, Num) -> {Num, Str}.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment