From 458210f5131994fc2ddb7c04ca19c879ebc031a7 Mon Sep 17 00:00:00 2001 From: Shadowfacts Date: Fri, 6 Dec 2019 16:40:25 -0500 Subject: [PATCH] Intcode assembler: start expression evaluation --- lib/intcode/expression_evaluator.ex | 93 +++++++++++++++++++++++++++++ 1 file changed, 93 insertions(+) create mode 100644 lib/intcode/expression_evaluator.ex diff --git a/lib/intcode/expression_evaluator.ex b/lib/intcode/expression_evaluator.ex new file mode 100644 index 0000000..5077425 --- /dev/null +++ b/lib/intcode/expression_evaluator.ex @@ -0,0 +1,93 @@ +defmodule ExpressionEvaluator do + def eval(expr, vars) do + expr + |> String.to_charlist() + |> tokenize() + |> run(vars) + + # |> parse() + + # |> run(vars) + end + + @digits ?0..?9 + @alpha ?a..?z + @operators [?+, ?-, ?*] + + def do_tokenize([first | _] = str) when first in @digits do + {digits, rest} = Enum.split_while(str, &(&1 in @digits)) + num = digits |> to_string() |> String.to_integer() + {{:number, num}, rest} + end + + def do_tokenize([?( | rest]) do + {:lparen, rest} + end + + def do_tokenize([?) | rest]) do + {:rparen, rest} + end + + def do_tokenize([op | rest]) when op in @operators do + atom = [op] |> to_string() |> String.to_atom() + {{:operator, atom}, rest} + end + + def do_tokenize([first | _] = str) when first in @alpha do + {var, rest} = Enum.split_while(str, &(&1 in @alpha)) + {{:variable, var}, rest} + end + + def tokenize([]), do: [] + + def tokenize(str) do + {token, rest} = + str + |> Enum.drop_while(&(&1 == ?\s)) + |> do_tokenize() + + [token | tokenize(rest)] + end + + # def to_rpn([{:number, _} = num | rest]) do + # [num | to_rpn(rest)] + # end + # + # def to_rpn([{:operator, _} = op | rest]) do + # [op | to_rpn(rest)] + # end + # + # def to_rpn + + # def parse(tokens) do + # {expr, rest} = do_parse(tokens) + # [expr | + # end + + def run([:lparen | _] = tokens, vars) do + paren_tokens = + tokens + |> Enum.drop(1) + |> Enum.reduce_while({1, []}, fn token, {count, paren_tokens} -> + count = + case token do + :lparen -> count + 1 + :rparen -> count - 1 + _ -> count + end + + if count == 0 do + {:halt, Enum.reverse(paren_tokens)} + else + {:cont, {count, [token | paren_tokens]}} + end + end) + + # paren_expr = run(paren_tokens) + rest_tokens = Enum.drop(tokens, length(paren_tokens)) + + paren_res = run(paren_tokens, vars) + + run([{:number, paren_res} | rest_tokens]) + end +end