Skip to content

Instantly share code, notes, and snippets.

@ityonemo
Last active February 20, 2020 06:40
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save ityonemo/c1366f28cfd71978d25f080f0694e5af to your computer and use it in GitHub Desktop.
Save ityonemo/c1366f28cfd71978d25f080f0694e5af to your computer and use it in GitHub Desktop.
with parser combinators
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