anchor.diff:  precedence(<<"xor">>) -> {left, 21};
   precedence(<<"or">>) -> {left, 22};
   precedence(_) -> false.
  +
  +operator(<<"and">>,Left,Right) -> operator('and',Left,Right);
  +operator(<<"or">>,Left,Right) -> operator('or',Left,Right);
  +operator(<<"&&">>,Left,Right) -> operator('and',Left,Right);
  +operator(<<"||">>,Left,Right) -> operator('or',Left,Right);
  +operator(Op,#int{int=I1},#int{int=I2}) ->
  +    case Op of
  +        <<"+">> -> I1+I2;
  +        <<"-">> -> I1-I2;
  +        <<"*">> -> I1*I2;
  +        <<"/">> -> I1/I2;
  +        <<"%">> -> I1 rem I2;
  +        <<">">> -> I1 > I2;
  +        <<"<">> -> I1 < I2;
  +        <<"==">> -> I1 == I2
  +        %% TODO add more optimizations for float and the rest of the operators
  +    end;
  +operator(Op,Left,Right) ->
  +    #operation{type=Op, expression_left=Left, expression_right=Right}.
  +
  +solve(Expression) ->
  +    Postfix = shunting_yard(Expression, [], []),
  +    [Operation] = gen_op(Postfix, []),
  +    Operation.
  +
  +gen_op([], Stack) ->
  +    Stack;
  +gen_op([{Op,{_,_}}|Rest], [A,B|Stack]) ->
  +    gen_op(Rest, [operator(Op,A,B)|Stack]);
  +gen_op([A|Rest], Stack) ->
  +    gen_op(Rest, [A|Stack]).
  +
  +shunting_yard([], [], Postfix) ->
  +    Postfix;
  +shunting_yard([], OpS, Postfix) ->
  +    Postfix ++ OpS;
  +shunting_yard([{_,{_,_}}=Op|Rest], [], Postfix) ->
  +    shunting_yard(Rest, [Op], Postfix);
  +shunting_yard([open|Rest], OpS, Postfix) ->
  +    shunting_yard(Rest, [open|OpS], Postfix);
  +shunting_yard([close|Rest], OpS, Postfix) ->
  +    {Add, [_Drop|NewOpS]} = lists:splitwith(fun(A) -> A =/= open end, OpS),
  +    shunting_yard(Rest, NewOpS, Postfix ++ Add);
  +shunting_yard([{_,{left,P1}}=Op|Rest], [{_,{_,P2}}]=OpS, Postfix) when P1 < P2 ->
  +    shunting_yard(Rest, [Op|OpS], Postfix);
  +shunting_yard([{_,{right,P1}}=Op|Rest], [{_,{_,P2}}]=OpS, Postfix) when P1 =< P2 ->
  +    shunting_yard(Rest, [Op|OpS], Postfix);
  +shunting_yard([{_,{left,P1}}=Op|Rest], [{_,{_,P2}}]=OpS, Postfix) when P1 >= P2 ->
  +    shunting_yard(Rest, [Op], Postfix ++ OpS);
  +shunting_yard([{_,{right,P1}}=Op|Rest], [{_,{_,P2}}]=OpS, Postfix) when P1 > P2 ->
  +    shunting_yard(Rest, [Op], Postfix ++ OpS);
  +shunting_yard([{_,{_,_}}=Op|Rest], OpS, Postfix) ->
  +    shunting_yard(Rest, [Op|OpS], Postfix);
  +shunting_yard([A|Rest], OpS, Postfix) ->
  +    shunting_yard(Rest, OpS, Postfix ++ [A]).
  +
  +add_line(#eval{}=E, {_,Row,Col}) -> E#eval{line={{line,Row},{column,Col}}};
  +add_line(#print{}=P, {_,Row,Col}) -> P#print{line={{line,Row},{column,Col}}};
  +add_line(#variable{}=V, {_,R,C}) -> V#variable{line={{line,R},{column,C}}};
  +add_line(#constant{}=C, {_,R,C}) -> C#constant{line={{line,R},{column,C}}};
  +add_line(#int{}=I, {_,R,C}) -> I#int{line={{line,R},{column,C}}};
  +add_line(#text_to_process{}=T, {_,R,C}) ->
  +    T#text_to_process{line={{line,R},{column,C}}};
  +add_line(#text{}=T, {_,R,C}) -> T#text{line={{line,R},{column,C}}};
  +add_line(#if_block{}=I, {_,R,C}) -> I#if_block{line={{line,R},{column,C}}}.
  
positive.code:     st_if(Rest, add_pos(Pos,1), Parsed);
  st_if(<<SP:1/binary,Rest/binary>>, Pos, Parsed) when ?IS_NEWLINE(SP) ->
      st_if(Rest, new_line(Pos), Parsed);
  st_if(<<"(",_/binary>> = Rest0, {Level,Row,Col}, Parsed) ->
      {Rest1, Pos1, Conditions} = conditions(Rest0, add_pos({0,Row,Col},2), []),
      {Rest2, {_,Row2,Col2}, CodeBlock} = code_block(Rest1, Pos1, []),
      If = #if_block{
          conditions=Conditions,
          true_block=CodeBlock,
          line={Row,Col}
      },
      code(Rest2, {Level,Row2,Col2}, [If|Parsed]);
  st_if(<<>>, Pos, _Parsed) ->
      throw({error, {parse, Pos, incomplete_if_statement}}).
  
negative.code: -module(ephp_parser).
  -export([parse/1]).
  
  -include("ephp.hrl").
  
  