Ignore:
Timestamp:
Feb 11, 2017, 12:47:38 PM (8 years ago)
Author:
chronos
Message:
  • Modified: Better expression parsing.
  • Added: Executor function call context for storing local variables.
File:
1 edited

Legend:

Unmodified
Added
Removed
  • branches/interpreter/Parser3.pas

    r99 r100  
    1414
    1515type
    16   TTokenType = (ttNormal, ttSpecialSymbol, ttString, ttConstant);
     16  TTokenType = (ttNormal, ttSpecialSymbol, ttString, ttConstant, ttNumber, ttChar);
    1717
    1818var
     
    2222
    2323  MainProgram: PProgramCode;
     24  FunctionContext: PFunction;
    2425
    2526function ParseIfThen(IfThenElse: PIfThenElse): Boolean; forward;
     
    2728function ParseExecution(Execution: PExecution): Boolean; forward;
    2829function ParseBeginEnd(BeginEnd: PBeginEnd): Boolean; forward;
    29 function ParseGetValue(GetValue: PGetValue): Boolean; forward;
     30function ParseGetValue(GetValue: PGetValue; NoExpression: Boolean = False): Boolean; forward;
    3031
    3132
     
    3334begin
    3435  Result := (C = ' ') or (C = #13) or (C = #10) or (C = #9);
     36end;
     37
     38function IsDigit(C: Char): Boolean;
     39begin
     40  Result := (C >= '0') and (C <= '9');
    3541end;
    3642
     
    7278end;
    7379
     80function StrToInt(S: string): Integer;
     81var
     82  I: Integer;
     83  N: Integer;
     84begin
     85  Result := 0;
     86  N := 1;
     87  I := Length(S);
     88  while I >= 1 do begin
     89    Result := Result + (Ord(S[I]) - Ord('0')) * N;
     90    N := N * 10;
     91    I := I - 1;
     92  end;
     93end;
     94
    7495function ReadNext: string;
    7596var
    7697  C: Char;
    77   IsString: Boolean;
    7898begin
    7999  Result := '';
    80   IsString := False;
    81100  LastTokenType := ttNormal;
    82101  repeat
    83102    C := ReadChar;
    84     if IsString then begin
     103    if LastTokenType = ttString then begin
    85104      if C = '''' then begin
     105        Break;
     106      end else Result := Result + C;
     107    end else
     108    if LastTokenType = ttNumber then begin
     109      if not IsDigit(C) then begin
     110        if Result[1] = '#' then begin
     111          Result := Chr(StrToInt(Copy(Result, 2, Length(Result))));
     112          LastTokenType := ttChar;
     113        end;
     114        InputTextPos := InputTextPos - 1;
    86115        Break;
    87116      end else Result := Result + C;
     
    108137        end;
    109138      end else
     139      if C = '#' then begin
     140        Result := Result + '#';
     141        LastTokenType := ttNumber;
     142      end else
    110143      if C = '''' then begin
    111144        LastTokenType := ttString;
    112         IsString := True;
    113145      end else begin
    114146        Result := Result + C;
     
    157189  OldPos := InputTextPos;
    158190  Next := ReadNext;
    159   Variable := MainProgram^.Variables.GetByName(Next);
     191  if FunctionContext = nil then
     192    Variable := MainProgram^.Variables.GetByName(Next)
     193    else Variable := FunctionContext^.Variables.GetByName(Next);
    160194  if Variable <> nil then begin
    161195    Result := True;
     
    182216end;
    183217
     218function GetOperatorType(Name: string): TOperator;
     219var
     220  I: Integer;
     221begin
     222  I := 0;
     223  while (I < Length(OperatorString)) and (OperatorString[TOperator(I)] <> Name) do Inc(I);
     224  if I < Length(OperatorString) then Result := TOperator(I)
     225    else Result := opNone;
     226end;
     227
     228function ParseOperator(out ExpOperator: TOperator): Boolean;
     229var
     230  OldPos: Integer;
     231  OperatorName: string;
     232begin
     233  OldPos := InputTextPos;
     234  OperatorName := ReadNext;
     235  ExpOperator := GetOperatorType(OperatorName);
     236  if ExpOperator <> opNone then begin
     237    Result := True;
     238
     239  end else begin
     240    InputTextPos := OldPos;
     241    Result := False;
     242  end;
     243end;
     244
     245function ParseValue(Value: PConstant): Boolean;
     246var
     247  OldPos: Integer;
     248  Text: string;
     249begin
     250  Result := True;
     251  OldPos := InputTextPos;
     252  Text := ReadNext;
     253  if LastTokenType = ttString then begin
     254    Value.DataType := MainProgram.Types.GetByName('string');
     255    Value.ValueString := Text;
     256  end else
     257  if LastTokenType = ttChar then begin
     258    Value.DataType := MainProgram.Types.GetByName('Char');
     259    Value.ValueChar := Text[1];
     260  end else
     261  if LastTokenType = ttNumber then begin
     262    Value.DataType := MainProgram.Types.GetByName('Integer');
     263    //Value.ValueInteger := StrToInt(Text);
     264  end else begin
     265    Result := False;
     266    InputTextPos := OldPos;
     267  end;
     268end;
     269
     270procedure DeleteExpressionItem(Expression: PExpression; Index: Integer);
     271var
     272  I: Integer;
     273begin
     274  I := Index;
     275  while (I + 1) < Length(Expression^.Items) do begin
     276    Expression^.Items[I] := Expression^.Items[I + 1];
     277    I := I + 1;
     278  end;
     279  SetLength(Expression^.Items, Length(Expression^.Items) - 1);
     280end;
     281
    184282function ParseExpression(Expression: PExpression): Boolean;
    185283var
    186   Next: string;
    187   OldPos: Integer;
    188   R: Boolean;
    189284  GetValue: TGetValue;
    190   Execution: TExecution;
    191   Variable: PVariable;
     285  ExpOperator: TOperator;
    192286  SubExpression: TExpression;
     287  I: Integer;
     288  II: Integer;
    193289begin
    194290  Result := True;
    195   if CheckNext('not') then begin
    196     Expect('not');
    197   end;
    198   if CheckNext('(') then begin
    199     Expect('(');
    200     if ParseGetValue(@GetValue) then begin
     291  repeat
     292    if CheckNext('(') then begin
     293      Expect('(');
     294      if ParseExpression(@SubExpression) then begin
     295        SetLength(Expression^.Items, Length(Expression^.Items) + 1);
     296        Expression^.Items[Length(Expression^.Items) - 1] := SubExpression;
     297      end;
     298      Expect(')');
     299    end else
     300    if ParseOperator(ExpOperator) then begin
    201301      SetLength(Expression^.Items, Length(Expression^.Items) + 1);
    202       Expression^.Items[Length(Expression^.Items) - 1] := GetValue;
     302      Expression^.Items[Length(Expression^.Items) - 1].NodeType := ntOperator;
     303      Expression^.Items[Length(Expression^.Items) - 1].OperatorType := ExpOperator;
     304    end else
     305    if ParseGetValue(@GetValue, True) then begin
     306      SetLength(Expression^.Items, Length(Expression^.Items) + 1);
     307      Expression^.Items[Length(Expression^.Items) - 1].NodeType := ntValue;
     308      Expression^.Items[Length(Expression^.Items) - 1].Value := GetValue;
     309    end else begin
     310      Result:= True;
     311      Break;
    203312    end;
    204     Expect(')');
    205   end else
    206   if ParseVariable(Variable) then begin
    207     OldPos := InputTextPos;
    208     Next := ReadNext;
    209     if IsOperator(Next) then begin
    210       Next := ReadNext;
    211       //if IsVariable(Next) then begin
    212 
    213       //end else ShowError('Expected variable');
    214     end else InputTextPos := OldPos;
    215   end else
    216   if LastTokenType = ttString then begin
    217     ReadNext
    218   end else
    219   if ParseExecution(@Execution) then begin
    220   end else
    221   ShowError('Expected variable but found ' + ReadNext);
    222 
    223   OldPos := InputTextPos;
    224   Next := ReadNext;
    225   if IsLogicOperator(Next) or IsOperator(Next) then begin
    226     R := ParseExpression(@SubExpression);
    227   end else InputTextPos := OldPos;
    228 end;
    229 
    230 function ParseGetValue(GetValue: PGetValue): Boolean;
     313  until False;
     314
     315  if Length(Expression^.Items) > 0 then begin
     316    // Build expression tree using operator precedence
     317    for II := 0 to Length(OperatorPrecedence) - 1 do begin
     318      I := 1;
     319      while (I < Length(Expression^.Items) - 1) do begin
     320        if (TExpression(Expression^.Items[I]).NodeType = ntOperator) and
     321          not TExpression(Expression^.Items[I]).Associated and
     322          (TExpression(Expression^.Items[I]).OperatorType = OperatorPrecedence[II]) then
     323        begin
     324          if Expression^.Items[I].OperatorType = opNot then begin
     325            Expression^.Items[I].Associated := True;
     326            SetLength(Expression^.Items[I].Items, 1);
     327            Expression^.Items[I].Items[0] := Expression^.Items[I + 1];
     328            DeleteExpressionItem(Expression, I + 1);
     329          end else begin
     330            Expression^.Items[I].Associated := True;
     331            SetLength(Expression^.Items[I].Items, 2);
     332            Expression^.Items[I].Items[1] := Expression^.Items[I - 1];
     333            Expression^.Items[I].Items[0] := Expression^.Items[I + 1];
     334            DeleteExpressionItem(Expression, I + 1);
     335            DeleteExpressionItem(Expression, I - 1);
     336          end;
     337        end else Inc(I);
     338      end;
     339    end;
     340  end;
     341end;
     342
     343procedure AssignExpression(ExpDst, ExpSrc: PExpression);
     344var
     345  I: Integer;
     346begin
     347  ExpDst^.OperatorType := ExpSrc^.OperatorType;
     348  ExpDst^.NodeType := ExpSrc^.NodeType;
     349  ExpDst^.Associated := ExpSrc^.Associated;
     350  ExpDst^.Value := ExpSrc^.Value;
     351  SetLength(ExpDst^.Items, 1); //Length(ExpSrc^.Items));
     352  for I := 0 to Length(ExpDst^.Items) - 1 do
     353    ExpDst^.Items[I] := ExpSrc^.Items[I];
     354end;
     355
     356function ParseGetValue(GetValue: PGetValue; NoExpression: Boolean = False): Boolean;
    231357var
    232358  Variable: PVariable;
     
    234360  FunctionCall: TExecution;
    235361  Expression: TExpression;
    236 begin
     362  Value: TConstant;
     363begin
     364  Result := True;
     365  if not NoExpression and ParseExpression(@Expression) then begin
     366    GetValue^.ReadType := rtExpression;
     367    GetValue^.Expression := GetMem(SizeOf(TExpression));
     368    FillChar(GetValue^.Expression^, SizeOf(TExpression), 0);
     369    GetValue^.Expression^ := Expression;
     370    //AssignExpression(GetValue^.Expression, @Expression);
     371  end else
    237372  if ParseVariable(Variable) then begin
     373    GetValue^.ReadType := rtVariable;
    238374    GetValue^.Variable := Variable;
    239     GetValue^.ReadType := rtVariable;
    240375  end else
    241376  if ParseConstant(Constant) then begin
     377    GetValue^.ReadType := rtConstant;
    242378    GetValue^.Constant := Constant;
    243     GetValue^.ReadType := rtConstant;
     379  end else
     380  if ParseValue(@Value) then begin
     381    GetValue^.ReadType := rtValue;
     382    GetValue^.Value := Value;
    244383  end else
    245384  if ParseExecution(@FunctionCall) then begin
    246     GetValue^.FunctionCall := GetMem(SizeOf(TExecution));
     385    GetValue^.ReadType := rtFunctionCall;
     386    GetValue^.FunctionCall := GetMem(SizeOf(TFunctionCall));
     387    FillChar(GetValue^.FunctionCall^, SizeOf(TFunctionCall), 0);
    247388    GetValue^.FunctionCall^ := FunctionCall;
    248     GetValue^.ReadType := rtFunctionCall;
    249   end else
    250   if ParseExpression(@Expression) then begin
    251     GetValue^.Expression := GetMem(SizeOf(TExpression));
    252     GetValue^.Expression^ := Expression;
    253     GetValue^.ReadType := rtExpression;
    254   end else
    255     ShowError('Expected value');
    256 end;
    257 
    258 function ParseAssignment: Boolean;
     389  end else
     390    Result := False;
     391end;
     392
     393function ParseAssignment(Assignment: PAssignment): Boolean;
    259394var
    260395  Variable: PVariable;
    261   Assignment: TAssignment;
    262396begin
    263397  if ParseVariable(Variable) then begin
    264398    Result := True;
    265     Assignment.Destination := Variable;
     399    Assignment^.Destination := Variable;
    266400    Expect(':=');
    267     ParseGetValue(@Assignment.Source);
     401    ParseGetValue(@Assignment^.Source);
    268402  end else begin
    269403    Result := False;
     
    283417  Func := MainProgram.Functions.GetByName(Next);
    284418  if Func <> nil then begin
     419    Execution^.Func := Func;
    285420    SetLength(Execution^.Parameters.Items, Length(Func^.Parameters.Items));
    286421    if Length(Func^.Parameters.Items) > 0 then begin
     
    311446  if ParseBeginEnd(@BeginEnd) then begin
    312447    Command^.BeginEnd := GetMem(SizeOf(TBeginEnd));
     448    FillChar(Command^.BeginEnd^, SizeOf(TBeginEnd), 0);
    313449    Command^.BeginEnd^ := BeginEnd;
    314450    Command^.CmdType := ctBeginEnd;
    315451  end else
    316   if ParseAssignment then begin
     452  if ParseAssignment(@Assignment) then begin
    317453    Command^.Assignment := GetMem(SizeOf(TAssignment));
     454    FillChar(Command^.Assignment^, SizeOf(TAssignment), 0);
    318455    Command^.Assignment^ := Assignment;
    319456    Command^.CmdType := ctAssignment;
     
    321458  if ParseExecution(@Execution) then begin
    322459    Command^.Execution := GetMem(SizeOf(TExecution));
     460    FillChar(Command^.Execution^, SizeOf(TExecution), 0);
    323461    Command^.Execution^ := Execution;
    324462    Command^.CmdType := ctExecution;
     
    326464  if ParseIfThen(@IfThenElse) then begin
    327465    Command^.IfThenElse := GetMem(SizeOf(TIfThenElse));
     466    FillChar(Command^.IfThenElse^, SizeOf(TIfThenElse), 0);
    328467    Command^.IfThenElse^ := IfThenElse;
    329468    Command^.CmdType := ctIfThenElse;
     
    331470  if ParseWhileDo(@WhileDo) then begin
    332471    Command^.WhileDo := GetMem(SizeOf(TWhileDo));
     472    FillChar(Command^.WhileDo^, SizeOf(TWhileDo), 0);
    333473    Command^.WhileDo^ := WhileDo;
    334474    Command^.CmdType := ctWhileDo;
     
    341481    Result := True;
    342482    Expect('if');
    343     ParseExpression(@IfThenElse.Condition);
     483    ParseGetValue(@IfThenElse.Condition);
    344484    Expect('then');
    345485    ParseCommand(@IfThenElse^.DoThen);
     
    356496    Result := True;
    357497    Expect('while');
    358     ParseExpression(@WhileDo.Condition);
     498    ParseGetValue(@WhileDo.Condition);
    359499    Expect('do');
    360500    ParseCommand(@WhileDo^.Command);
     
    391531begin
    392532  if CheckNext('(') then begin
     533    Result := True;
    393534    Expect('(');
    394535    ParamName := ReadNext;
     
    398539    if ParamType <> nil then begin
    399540      Params^.Add(FunctionParameterCreate(ParamName, ParamType));
     541      FunctionContext^.Variables.Add(VariableCreate(ParamName, ParamType));
    400542    end else ShowError('Unknown parameter type ' + ParamTypeName);
    401543    Expect(')');
    402   end;
     544  end else Result := False;
    403545end;
    404546
     
    424566        VarType := MainProgram^.Types.GetByName(VarTypeName);
    425567        if VarType <> nil then begin
    426           MainProgram^.Variables.Add(VariableCreate(VarName, VarType));
     568          if FunctionContext = nil then
     569            MainProgram^.Variables.Add(VariableCreate(VarName, VarType))
     570            else FunctionContext^.Variables.Add(VariableCreate(VarName, VarType));
    427571        end else ShowError('Unknown variable type ' + VarTypeName);
    428572        Expect(';');
     
    435579var
    436580  ReturnType: string;
     581  DataType: PType;
    437582begin
    438583  if CheckNext('function') then begin
    439584    Result := True;
    440585    Expect('function');
     586    FunctionContext := Func;
    441587    Func^.Name := ReadNext;
    442588    ParseParams(@Func^.Parameters);
    443589    Expect(':');
    444590    ReturnType := ReadNext;
     591    DataType := MainProgram.Types.GetByName(ReturnType);
     592    if DataType <> nil then Func^.ReturnType := DataType
     593      else ShowError('Unknown type ' + ReturnType);
    445594    Expect(';');
     595    Func^.Variables.Add(VariableCreate('Result', Func^.ReturnType));
    446596    if ParseVariableSection then begin
    447597    end;
    448598    ParseBeginEnd(@Func^.BeginEnd);
     599    FunctionContext := nil;
    449600    Expect(';');
    450601  end else Result := False;
     
    456607    Result := True;
    457608    Expect('procedure');
     609    FunctionContext := Func;
    458610    Func^.Name := ReadNext;
    459611    ParseParams(@Func^.Parameters);
     
    462614    end;
    463615    ParseBeginEnd(@Func^.BeginEnd);
     616    FunctionContext := nil;
    464617    Expect(';');
    465618  end else Result := False;
     
    491644
    492645  SetLength(ProgramCode^.Variables.Items, 0);
    493   ProgramCode^.Variables.Add(VariableCreate('Result', TypeString));
    494   ProgramCode^.Variables.Add(VariableCreate('C', TypeChar));
    495   ProgramCode^.Variables.Add(VariableCreate('Text', TypeString));
    496646
    497647  SetLength(ProgramCode^.Functions.Items, 0);
     
    527677  repeat
    528678    SetLength(NewFunc.Parameters.Items, 0);
     679    SetLength(NewFunc.Variables.Items, 0);
    529680    if ParseFunction(@NewFunc) then begin
    530681      ProgramCode.Functions.Add(NewFunc);
     
    534685    end else Break;
    535686  until False;
     687  FunctionContext := nil;
    536688  ParseBeginEnd(@ProgramCode.BeginEnd);
    537689  Expect('.');
Note: See TracChangeset for help on using the changeset viewer.