-
-
Save ityonemo/c1366f28cfd71978d25f080f0694e5af to your computer and use it in GitHub Desktop.
with parser combinators
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
defmodule CalcParsec do | |
import NimbleParsec | |
@from_string %{"one" => 1, "two" => 2, "three" => 3, "four" => 4, | |
"five" => 5, "six" => 6, "seven" => 7, "eight" => 8, "nine" => 9, | |
"ten" => 10} | |
@num_strs Map.keys(@from_string) | |
number_list = @num_strs |> Enum.map(&string/1) | |
whitespace = string("\s") | |
operator = choice(Enum.map(~w(plus minus), &string/1)) | |
defcombinatorp :number, choice([ | |
string("minus") |> ignore(whitespace) |> parsec(:number) | | |
number_list]) | |
|> post_traverse(:eval_number) | |
defcombinatorp :term, | |
choice([ | |
parsec(:number) |> ignore(whitespace) |> string("times") |> ignore(whitespace) |> parsec(:term), | |
parsec(:number)]) | |
|> post_traverse(:eval_term) | |
defparsec :expr, | |
choice([ | |
parsec(:term) |> ignore(whitespace) |> concat(operator) |> ignore(whitespace) |> parsec(:expr), | |
parsec(:term)]) | |
|> post_traverse(:eval_expr) | |
defp eval_number(_rest, lst, _, _, _), do: {[eval_number(lst)], %{}} | |
defp eval_number([val | rest]) when val in @num_strs, do: @from_string[val] * eval_number(rest) | |
defp eval_number(["minus" | rest]), do: -1 * eval_number(rest) | |
defp eval_number([val | rest]), do: val * eval_number(rest) | |
defp eval_number([]), do: 1 | |
defp eval_term(_rest, lst, _, _, _), do: {[eval_term(lst)], %{}} | |
defp eval_term([number]), do: number | |
defp eval_term([number, "times" | rest]), do: number * eval_term(rest) | |
defp eval_expr(_rest, lst, _, _, _), do: {[eval_expr(lst)], %{}} | |
defp eval_expr([number]), do: number | |
defp eval_expr([number, "plus" | rest]), do: number + eval_expr(rest) | |
defp eval_expr([number, "minus" | rest]), do: -number + eval_expr(rest) | |
def calc(""), do: 0 | |
def calc(str) do | |
{:ok, [v], _, _, _, _} = expr(str) | |
v | |
end | |
end |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment