⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 dws2compiler.pas

📁 script language
💻 PAS
📖 第 1 页 / 共 5 页
字号:
  i: Integer;
begin

  if not IsType then
  begin
    // Find Symbol for Functionname
    if not FTok.TestName then
      FMsgs.AddCompilerStop(FTok.HotPos, CPE_NameExpected);
    Name := FTok.GetToken.FString;
    funcPos := FTok.HotPos;
    FTok.KillToken;

    sym := FProg.Table.FindSymbol(Name);

    // Open context for procedure declaration. Closed in ReadProcBody.
    if coContextMap in FCompilerOptions then
      FProg.ContextMap.OpenContext(funcPos, sym);
  end
  else begin
    sym := nil;
    Name := '';
  end;

  // Name is the name of class -> Method
  if sym is TClassSymbol then
  begin
    // Store reference to class in dictionary
    if coSymbolDictionary in FCompilerOptions then
      FProg.SymbolDictionary.Add(sym, funcPos);
    Result := ReadMethodImpl(TClassSymbol(sym), FuncKind, IsClassMethod);
  end
  else
  begin
    // Read normal procedure/function declaration
    if IsClassMethod or (FuncKind = fkConstructor) or (FuncKind = fkDestructor) then
      FMsgs.AddCompilerStop(FTok.HotPos, CPE_ImplClassNameExpected);

    if (sym is TFuncSymbol) and TFuncSymbol(sym).IsForwarded then
      // There was already a (forward) declaration
      forwardedSym := TFuncSymbol(sym)
    else
      forwardedSym := nil;

    if not Assigned(forwardedSym) then
      CheckName(Name);

    if IsType then
      Result := TFuncSymbol.Create('', FuncKind, -1)
    else
      Result := TFuncSymbol.Create(Name, FuncKind,
        FProg.Stack.NextLevel(FProg.Level));
    try
      ReadParams(Result, forwardedSym=nil);  // Don't add params to dictionary when function is forwarded. It is already declared.

      if FuncKind = fkFunction then
      begin
        if not FTok.TestDelete(ttCOLON) then
          FMsgs.AddCompilerStop(FTok.HotPos, CPE_FunctionTypeExpected);
        Result.Typ := ReadType('');
      end;

      if not IsType then
      begin
        if Assigned(forwardedSym) then
          CompareFuncSymbols(forwardedSym, Result, True);

        // forward declarations
        if not Assigned(forwardedSym) then
        begin
          if FTok.Test(ttSEMI) then
          begin
            FTok.KillToken; // SEMI
            if FTok.Test(ttFORWARD) then
            begin
              Result.IsForwarded := True;
              FTok.TestDelete(ttFORWARD);
            end;
          end;
        end
        else if not FTok.TestDelete(ttSEMI) then
          FMsgs.AddCompilerStop(FTok.HotPos, CPE_SemiExpected);


        if Assigned(forwardedSym) then
        begin
          // Get forwarded position in script. If compiled without symbols it will just return from empty list (could optimize here to prevent the push/pop of call stack
          forwardedSymPos := FProg.SymbolDictionary.FindSymbolUsage(forwardedSym, suDeclaration);  // may be nil
          // Adapt dictionary entry to reflect that it was a forward
          // If the record is in the SymbolDictionary (disabled dictionary would leave pointer nil)
          if Assigned(forwardedSymPos) then
            forwardedSymPos.SymbolUsages := [suForward];  // update old postion to reflect that the type was forwarded

          Result.Free;
          Result := forwardedSym;
          Result.IsForwarded := False;
        end
        else
          FProg.Table.AddSymbol(Result);
      end
      else if FTok.TestDelete(ttOF) then
      begin
        if not FTok.TestDelete(ttOBJECT) then
          FMsgs.AddCompilerStop(FTok.HotPos, CPE_ObjectExpected);
        methSym := TMethodSymbol.Create('',FuncKind, FProg.TypObject,-1);
        methSym.Typ := Result.Typ;
        for i := 0 to Result.Params.Count - 1 do
          methSym.Params.AddSymbol(Result.Params[i]);
        Result.Params.Clear;
        Result.Free;
        Result := methSym;
      end;

      // Procedure is both Declared and Implemented here
      if coSymbolDictionary in FCompilerOptions then
        FProg.SymbolDictionary.Add(Result, funcPos, [suDeclaration, suImplementation]);
    except
      // Remove reference to symbol (gets freed)
      if coSymbolDictionary in FCompilerOptions then
        FProg.SymbolDictionary.Remove(Result);
      Result.Free;
      raise;
    end;
  end;
end;

function Tdws2Compiler.ReadMethodDecl(ClassSym: TClassSymbol; FuncKind: TFuncKind;
  IsClassMethod: Boolean): TMethodSymbol;

  function ParamsCheck(newMeth, oldMeth: TMethodSymbol): Boolean;
  var
    x: Integer;
  begin
    Result := False;
    if newMeth.Params.Count = oldMeth.Params.Count then
    begin
      for x := 0 to newMeth.Params.Count - 1 do
        if not newMeth.Params[x].Typ.IsCompatible(oldMeth.Params[x].Typ) then
          exit;
      Result := True;
    end;
  end;
var
  Name: string;
  meth: TSymbol;
  IsReintroduced: Boolean;
  methPos: TScriptPos;
begin
  // Find Symbol for Functionname
  if not FTok.TestName then
    FMsgs.AddCompilerStop(FTok.HotPos, CPE_NameExpected);
  Name := FTok.GetToken.FString;
  FTok.KillToken;

  methPos := FTok.HotPos;

  // Check if name is already used
  meth := ClassSym.Members.FindSymbol(Name);
  if meth is TFieldSymbol then
    FMsgs.AddCompilerStop(FTok.HotPos, Format(CPE_FieldRedefined, [Name]))
  else if meth is TPropertySymbol then
    FMsgs.AddCompilerStop(FTok.HotPos, Format(CPE_PropertyRedefined, [Name]))
  else if meth is TMethodSymbol then
  begin
    if TMethodSymbol(meth).ClassSymbol = ClassSym then
      FMsgs.AddCompilerStop(FTok.HotPos, Format(CPE_MethodRedefined, [Name]));
  end;

  // Read declaration of method implementation
  if IsClassMethod then
    Result := TMethodSymbol.Create(Name, FuncKind, ClassSym.ClassOf)
  else
    Result := TMethodSymbol.Create(Name, FuncKind, ClassSym);

  try
    if meth is TMethodSymbol then
    begin
      Result.SetOverlap(TMethodSymbol(meth));
      IsReintroduced := TMethodSymbol(meth).IsVirtual;
    end
    else
      IsReintroduced := False;

    ReadParams(Result);

    if FuncKind = fkFunction then
    begin
      if not FTok.TestDelete(ttCOLON) then
        FMsgs.AddCompilerStop(methPos, CPE_FunctionTypeExpected);
      Result.Typ := ReadType('');
    end
    else if FuncKind = fkConstructor then
      Result.Typ := ClassSym;

    if not FTok.TestDelete(ttSEMI) then
      FMsgs.AddCompilerStop(methPos, CPE_SemiExpected);

    if FTok.Test(ttVIRTUAL) or FTok.Test(ttOVERRIDE) or FTok.Test(ttREINTRODUCE) then
    begin
      if FTok.TestDelete(ttVIRTUAL) then
      begin
        TMethodSymbol(Result).IsVirtual := True;
        if FTok.Test(ttSEMI) and FTok.NextTest(ttABSTRACT) then
        begin
          FTok.KillToken;
          FTok.TestDelete(ttABSTRACT);
          TMethodSymbol(Result).IsAbstract := True;
        end;
      end
      else if FTok.TestDelete(ttOVERRIDE) then
      begin
        if not Assigned(meth) or not (meth is TMethodSymbol) then
          FMsgs.AddCompilerStop(methPos, Format(CPE_CantOverrideNotInherited, [Name]))
        else if not TMethodSymbol(meth).IsVirtual then
          FMsgs.AddCompilerStop(methPos, Format(CPE_CantOverrideNotVirtual, [Name]))
        else
        begin
          if not ParamsCheck(TMethodSymbol(Result), TMethodSymbol(meth)) then
            FMsgs.AddCompilerStop(FTok.HotPos, CPE_CantOverrideWrongParameterList);
          TMethodSymbol(Result).SetOverride(TMethodSymbol(meth));
          IsReintroduced := False;
        end;
      end
      else if FTok.TestDelete(ttREINTRODUCE) then
      begin
        if not IsReintroduced then
          FMsgs.AddCompilerStop(methPos, Format(CPE_CantReintroduce, [Name]));
        IsReintroduced := False;
      end;

      if not FTok.TestDelete(ttSEMI) then
        FMsgs.AddCompilerStop(FTok.HotPos, CPE_SemiExpected);
    end;

    if IsReintroduced then
      FMsgs.AddCompilerWarning(methPos, Format(CPE_ReintroduceWarning, [Name]));

    // Added as last step. OnExcept, won't need to be freed.
    if coSymbolDictionary in FCompilerOptions then
      FProg.SymbolDictionary.Add(Result, methPos, [suDeclaration]);
  except
    Result.Free;
    raise;
  end;
end;

function Tdws2Compiler.ReadMethodImpl(ClassSym: TClassSymbol;
  FuncKind: TFuncKind; IsClassMethod: Boolean): TMethodSymbol;
var
  methName: string;
  meth: TSymbol;
  methPos: TScriptPos;
begin
  if not (FTok.TestDelete(ttDOT) and FTok.TestName) then
    FMsgs.AddCompilerStop(FTok.HotPos, CPE_NameExpected);

  methName := FTok.GetToken.FString;
  methPos := FTok.HotPos;
  FTok.KillToken;
  FTok.Test(ttBLEFT);

  meth := ClassSym.Members.FindSymbol(methName);

  if not (meth is TMethodSymbol) then
    FMsgs.AddCompilerStop(methPos, CPE_ImplNotAMethod);

  if TMethodSymbol(meth).ClassSymbol <> ClassSym then
    FMsgs.AddCompilerStop(methPos, Format(CPE_ImplInvalidClass, [methName,
      ClassName]));

  if TMethodSymbol(meth).IsAbstract then
    FMsgs.AddCompilerError(methPos, Format(CPE_ImplAbstract, [ClassName, methName]));

  if TMethodSymbol(meth).IsClassMethod and not IsClassMethod then
    FMsgs.AddCompilerStop(methPos, CPE_ImplClassExpected)
  else if not TMethodSymbol(meth).IsClassMethod and IsClassMethod then
    FMsgs.AddCompilerStop(methPos, CPE_ImplNotClassExpected);

  Result := TMethodSymbol.Create(methName, FuncKind, ClassSym);
  try
    if not FTok.TestDelete(ttSEMI) then
    begin
      ReadParams(Result, False);  // Don't store these params to Dictionary. They will become invalid when the method is freed.

      if FuncKind = fkFunction then
      begin
        if not FTok.TestDelete(ttCOLON) then
          FMsgs.AddCompilerStop(FTok.HotPos, CPE_FunctionTypeExpected);
        Result.Typ := ReadType('');
      end;

      if not FTok.TestDelete(ttSEMI) then
        FMsgs.AddCompilerStop(FTok.HotPos, CPE_SemiExpected);

      CompareFuncSymbols(TMethodSymbol(meth), Result, True);
    end
    else
      CompareFuncSymbols(TMethodSymbol(meth), Result, False);
  finally
    Result.Free;
    Result := TMethodSymbol(meth);
    if coSymbolDictionary in FCompilerOptions then
      FProg.SymbolDictionary.Add(Result, methPos, [suImplementation]);
  end;
end;

procedure Tdws2Compiler.ReadProcBody(Proc: TFuncSymbol);
var
  x: Integer;
  oldprog: TProgram;
  stmt: TExpr;
  names: TStringList;
  typ: TSymbol;
  dataSym: TDataSymbol;
  initData: TData;
  pos: TScriptPos;
  posArray: TScriptPosArray;
begin
  // Stop if declaration was forwarded or external
  if (TFuncSymbol(Proc).IsForwarded) then
  begin
    // Closed context of procedure (was only a forward)
    if coContextMap in FCompilerOptions then
      FProg.ContextMap.CloseContext(FTok.HotPos);
    Exit;
  end;

  // Open context of full procedure body (may include a 'var' section)
  if coContextMap in FCompilerOptions then
    FProg.ContextMap.OpenContext(FTok.CurrentPos, Proc);   // attach to symbol that it belongs to (perhaps a class)

  try
    // Funktion Body
    oldprog := FProg;
    FProg := TProcedure.Create(FProg);
    try
      TProcedure(FProg).AssignTo(Proc);
      // Set the current context's LocalTable to be the table of the new procedure
      if coContextMap in FCompilerOptions then
        FProg.ContextMap.Current.LocalTable := FProg.Table;

      // Read local variable declarations
      if FTok.TestDelete(ttVAR) then
      begin
        names := TStringList.Create;
        try
          // Read names of local variable
          repeat
            // Track Procedure local variables positions
            if coSymbolDictionary in FCompilerOptions then
              ReadNameList(names, posArray)
            else
              ReadNameList(names);
            if not FTok.TestDelete(ttCOLON) then
              FMsgs.AddCompilerStop(FTok.HotPos, CPE_ColonExpected);

            // Read type of local variables
            pos := FTok.HotPos;
            typ := ReadType('');
            for x := 0 to names.Count - 1 do
            begin
              CheckName(names[x]);
              dataSym := TDataSymbol.Create(names[x], typ);
              FProg.Table.AddSymbol(dataSym);
              // Add local proc variable declarations
              if coSymbolDictionary in FCompilerOptions then
                FProg.SymbolDictionary.Add(dataSym, posArray[x], [suDeclaration]);

              // Initialize with default value
              initData := nil;
              SetLength(initData, typ.Size);
              dataSym.initData(initData, 0);

              TBlockExpr(FProg.InitExpr).AddStatement(
                TAssignDataExpr.Create(FProg, pos,
                GetVarExpr(dataSym),
                TConstExpr.Create(FProg, pos, typ, initData)))
            end;

            if not FTok.TestDelete(ttSEMI) then
              FMsgs.AddCompilerStop(FTok.HotPos, CPE_SemiExpected);

          until FTok.Test(ttBEGIN);
        finally
          names.Free;
        end;
      end;

      if coContextMap in FCompilerOptions then

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -