diff options
| -rw-r--r-- | example/input.txt | 2 | ||||
| -rw-r--r-- | lib/elixir_math_parser.ex | 23 | ||||
| -rw-r--r-- | src/elixir_math_parser.yrl | 8 | ||||
| -rw-r--r-- | src/elixir_math_parser_lexer.xrl | 1 |
4 files changed, 31 insertions, 3 deletions
diff --git a/example/input.txt b/example/input.txt index 7efcb9c..8cb02c5 100644 --- a/example/input.txt +++ b/example/input.txt @@ -5,3 +5,5 @@ x = 20 y = 2! z = y/2 10 + 4(z / y)(x / 4) + +x^(0-y) diff --git a/lib/elixir_math_parser.ex b/lib/elixir_math_parser.ex index 863ecd8..b5e99bd 100644 --- a/lib/elixir_math_parser.ex +++ b/lib/elixir_math_parser.ex @@ -57,9 +57,32 @@ defmodule ElixirMathParser do end end + defp reduce_to_value({:exp_op, lhs, rhs}, state) do + with {:ok, op1} <- reduce_to_value(lhs, state), + {:ok, op2} <- reduce_to_value(rhs, state) do + if Ratio.denominator(op2) == 1 do + {:ok, expo(op1, Ratio.numerator(op2), 1)} + else + {:error, "unsupported operation"} + end + end + end + + # Functions for maths + defp factor(n, acc) when n > 0, do: factor(n - 1, acc * n) defp factor(0, acc), do: acc + defp expo(value, exponent, acc) when exponent != 0 do + if exponent > 0 do + expo(value, exponent - 1, acc * value) + else + expo(value, exponent + 1, acc / value) + end + end + + defp expo(_value, 0, acc), do: acc + defp evaluate_tree([{:assign, {:var, line, lhs}, rhs} | tail], state) do with {:ok, val} <- reduce_to_value(rhs, state) do evaluate_tree(tail, Map.merge(state, %{lhs => val})) diff --git a/src/elixir_math_parser.yrl b/src/elixir_math_parser.yrl index 0808683..006c768 100644 --- a/src/elixir_math_parser.yrl +++ b/src/elixir_math_parser.yrl @@ -10,7 +10,7 @@ Terminals int var break - '+' '-' '*' '/' '!' + '+' '-' '*' '/' '!' '^' '=' '(' ')' . @@ -25,7 +25,8 @@ Left 300 '-'. Left 400 '*'. Left 400 '/'. Right 500 '!'. -Left 600 '('. +Left 600 '^'. +Left 700 '('. root -> statements : '$1'. @@ -46,8 +47,9 @@ expr -> exprs '+' exprs : {add_op, '$1', '$3'}. expr -> exprs '-' exprs : {sub_op, '$1', '$3'}. expr -> exprs '*' exprs : {mul_op, '$1', '$3'}. expr -> exprs '/' exprs : {div_op, '$1', '$3'}. -expr -> '(' exprs ')' : '$2'. expr -> expr '!' : {factor_op, '$1'}. +expr -> exprs '^' exprs : {exp_op, '$1', '$3'}. +expr -> '(' exprs ')' : '$2'. Erlang code. diff --git a/src/elixir_math_parser_lexer.xrl b/src/elixir_math_parser_lexer.xrl index 5bdcbef..c29416e 100644 --- a/src/elixir_math_parser_lexer.xrl +++ b/src/elixir_math_parser_lexer.xrl @@ -14,6 +14,7 @@ Rules. \( : {token, {'(', TokenLine}}. \) : {token, {')', TokenLine}}. ! : {token, {'!', TokenLine}}. +\^ : {token, {'^', TokenLine}}. {BREAK}+ : {token, {break, TokenLine}}. {NAME} : {token, {var, TokenLine, TokenChars}}. {INT} : {token, {int, TokenLine, TokenChars}}. |
