chelper: *fix enum type converting, if used as function return type* improve expression converting* improve enumeration value assignment* implement writting unions* fixes type name and variable name selection (to avoid pascal names conflicts)* fix function converting with single void* parameter

* c-parsing fixes* IDE lock for multiple ctrl+b presses



git-svn-id: https://svn.code.sf.net/p/lazarus-ccr/svn@1272 8e941d3f-bd1b-0410-a28a-d453659cc2b4
This commit is contained in:
skalogryz
2010-08-09 20:29:26 +00:00
parent 2f5829eff6
commit ab0048814a
4 changed files with 196 additions and 65 deletions

View File

@ -80,6 +80,7 @@ var
p : TPoint;
cfg : TConvertSettings;
begin
if ParamCount=0 then Exit;
inps := TStringList.Create;
outs := TStringList.Create;

View File

@ -266,10 +266,16 @@ type
{ TExpression }
TExpPart = record
Token : AnsiString;
TokenType : TTokenType;
end;
TExpression = class(TEntity)
function DoParse(AParser: TTextParser): Boolean; override;
public
Text : AnsiString;
Tokens : array of TExpPart;
Count : Integer;
procedure PushToken(const AToken: AnsiString; ATokenType: TTokenType);
end;
procedure ErrorExpect(Parser: TTextParser; const Expect: AnsiString);
@ -1531,21 +1537,31 @@ end;
function isEndOfExpr(const t: AnsiString; CommaIsEnd: Boolean): Boolean;
begin
Result:=(t=']') or (t=';') or (t=')') or (CommaIsEnd and (t=','));
Result:=(t=']') or (t=';') or (t=')') or (CommaIsEnd and (t=',')) or (t='}');
end;
function ParseCExpr(Parser: TTextParser; CommaIsEnd: Boolean=False): TExpression;
var
x : TExpression;
lvl : Integer;
begin
if isEndOfExpr(Parser.Token, CommaIsEnd) then
Result:=nil
else begin
lvl:=0;
x := TExpression.Create(Parser.Index);
while not isEndOfExpr(Parser.Token, CommaIsEnd) do begin
x.Text:=x.Text+Parser.Token;
Parser.NextToken;
repeat
if (Parser.Token='(') or (Parser.Token='[') then
inc(lvl)
else begin
if (lvl=0) and isEndOfExpr(Parser.Token, CommaIsEnd) then
Break
else if (Parser.Token=')') or (Parser.Token=']') then
dec(lvl)
end;
x.PushToken(Parser.Token, Parser.TokenType);
until not Parser.NextToken;
Result:=x;
end;
end;
@ -1557,6 +1573,18 @@ begin
Result:=False;
end;
procedure TExpression.PushToken(const AToken:AnsiString; ATokenType: TTokenType);
begin
if Count=length(Tokens) then begin
if Count=0 then SetLength(Tokens, 2)
else SetLength(Tokens, Count*2);
end;
Tokens[Count].Token:=AToken;
Tokens[Count].TokenType:=ATokenType;
inc(Count);
end;
procedure ParseFuncParams(Parser: TTextParser; FuncName: TNamePart);
var
prmtype : TEntity;
@ -1777,13 +1805,8 @@ begin
AParser.NextToken;
end;
if AParser.Token<>'{' then begin
ErrorExpect(AParser, '{');
Exit;
end;
if AParser.Token='{' then begin
AParser.NextToken;
try
repeat
v:=TVarFuncEntity.Create(AParser.TokenPos);
if not ParseNames(AParser, v.RetType, v.Names) then begin
@ -1800,10 +1823,8 @@ begin
until (AParser.Token='}');
ConsumeToken(AParser, '}');
Result:=st;
finally
if not Assigned(Result) then st.Free;
end;
Result:=st;
end;
function ParseUnion(AParser:TTextParser):TUnionType;
@ -1907,8 +1928,8 @@ begin
en.AddItem(nm, x, ofs);
if AParser.Token=',' then AParser.NextToken;
end;
end;
AParser.NextToken;
end;
Result:=en;
finally
if not Assigned(Result) then en.Free;

View File

@ -60,6 +60,23 @@ type
// X - column (starting from 1);
function ConvertCode(const t: AnsiString; var endPoint: TPoint; cfg: TConvertSettings = nil): AnsiString;
// converts C-expression to Pascal expression, replace symbols with pascal equvialents.
// WARN: * the function doesn't handle macroses (treats them as identifiers)
// * it doesn't recognizes typecasting
// * it doesn't recognize the correct order of operations.
function PasExp(x: TExpression): AnsiString;
// returns true, if x is single number expression. V is the value of the number
function isNumberExp(x: TExpression; var v: Int64): Boolean;
// returns array limit base on x expression.
// if expression is a single number (N), then evaluates the N-1 number and returns it as string
// if expression is complex, returns pascal expression exp-1.
// i.e. int a[10] -> a: array [0..9] of Integer;
// int a[10*2] -> a: array [0..10*2-1] of Integer;
// int a[MAXCONST] -> a: array [0..MAXCONST-1] of Integer;
function PasArrayLimit(x: TExpression): AnsiString;
implementation
type
@ -108,15 +125,16 @@ type
procedure DeclarePasType(TypeEntity: TEntity; const PasTypeName: AnsiString);
procedure DeclareFuncType(const PasTypeName, RetTypeName: AnsiString; const params: array of TFuncParam);
procedure WriteLnCommentForOffset(AOffset: Integer);
procedure WriteLnCommentForOffset(AOffset: Integer; NeedOffset: Boolean=True);
function NextCommentBefore(AOffset: Integer): Integer;
procedure WriteLnCommentsBeforeOffset(AOffset: Integer);
procedure WriteFuncDecl(const FnName, PasRetType: Ansistring; const params : array of TFuncParam);
procedure WriteFuncOrVar(cent: TVarFuncEntity; StartVar: Boolean); // todo: deprecate!
procedure WriteFuncOrVar(cent: TVarFuncEntity; StartVar, WriteComment: Boolean); // todo: deprecate!
procedure WriteTypeDef(tp: TTypeDef);
procedure WriteEnum(en: TEnumType);
procedure WriteEnumAsConst(en: TEnumType);
procedure WriteUnion(st: TUnionType);
procedure WriteStruct(st: TStructType);
procedure WriteCommentToPas(cent: TComment);
procedure WriteExp(x: TExpression);
@ -289,12 +307,35 @@ begin
FillChar(Result[1], AstCount, '*');
end;
function isNumberExp(x: TExpression; var v: Int64): Boolean;
var
err : Integer;
begin
Result:=Assigned(x) and (x.count=1);
if Result then begin
Val(x.Tokens[0].Token, v, err);
Result:=err=0;
end;
end;
function PasArrayLimit(x: TExpression): AnsiString;
var
i : Int64;
begin
if isNumberExp(x, i) then
Result:=IntToStr(i-1)
else
Result:=PasExp(x) + '-1';
end;
procedure WriteArray(arr: TNamePart; wr: TCodeWriter);
var
i : Integer;
begin
wr.W('array ');
for i := 0 to length(arr.arrayexp) - 1 do wr.W('[0..' + arr.arrayexp[i].Text + '-1]');
for i := 0 to length(arr.arrayexp) - 1 do wr.W('[0..' + PasArrayLimit(arr.arrayexp[i])+']');
wr.W(' of ');
end;
@ -446,7 +487,7 @@ end;
procedure TCodeConvertor.WriteExp(x:TExpression);
begin
wr.W('0 {todo writeexp}');
wr.W(PasExp(x));
end;
function CtoPasSymbol(const t: AnsiString): AnsiString;
@ -474,7 +515,6 @@ var
begin
if cent.SubsText<>'' then begin
SetPasSection(wr, 'const');
//wr.Wln(cfg.GetUniqueName(cent._Name) + ' = ' + Trim(cent.SubsText)+';');
p:=CreateCParser(cent.SubsText, false);
s:='';
while p.NextToken do begin
@ -544,14 +584,14 @@ begin
WriteFuncDecl('', RetTypeName, params);
end;
procedure TCodeConvertor.WriteLnCommentForOffset(AOffset:Integer);
procedure TCodeConvertor.WriteLnCommentForOffset(AOffset:Integer; NeedOffset: Boolean);
var
cmt : TComment;
begin
cmt:=FindCommentForLine( Breaker.LineNumber(AOffset));
if Assigned(cmt) then begin
LastOffset:=cmt.Offset;
wr.W(' ');
if NeedOffset then wr.W(' ');
WriteCommentToPas(cmt);
end else
wr.Wln;
@ -579,7 +619,7 @@ var
begin
i:=NextCommentBefore(AOffset);
while i>=0 do begin
WriteLnCommentForOffset(i);
WriteLnCommentForOffset(i, False);
i:=NextCommentBefore(AOffset);
end;
end;
@ -680,7 +720,9 @@ begin
if Result then Exit;
Result:=length(params)=1;
if Result then
Result:=(params[0].prmtype is TSimpleType) and (TSimpleType(params[0].prmtype).Name='void');
Result:=(params[0].prmtype is TSimpleType) and
(TSimpleType(params[0].prmtype).Name='void') and
(params[0].name=nil);
end;
procedure TCodeConvertor.WriteFuncDecl(const FnName, PasRetType: Ansistring; const params : array of TFuncParam);
@ -720,7 +762,7 @@ begin
if cfg.FuncDeclPostfix<>'' then wr.W('; '+cfg.FuncDeclPostfix);
end;
procedure TCodeConvertor.WriteFuncOrVar(cent: TVarFuncEntity; StartVar: Boolean);
procedure TCodeConvertor.WriteFuncOrVar(cent: TVarFuncEntity; StartVar, WriteComment: Boolean);
var
i, j : integer;
Name : TNamePart;
@ -736,12 +778,14 @@ begin
wr.Wln(' bad declaration synax!');
Exit;
end;
id:=name.Id;
id:=cfg.GetUniqueName(name.Id);
n:=name.owner;
if not Assigned(n) then begin
PushWriter;
rt:=GetPasTypeName(cent.RetType, Name);
PopWriter;
if StartVar then SetPasSection(wr, 'var');
wr.W(id + ' : ' + GetPasTypeName(cent.RetType, Name))
wr.W(id + ' : ' + rt);
end else if (n.Kind=nk_Func) then begin
SetPasSection(wr, '');
rt:=GetPasTypeName(cent.RetType, n.owner);
@ -752,9 +796,9 @@ begin
wr.W(id + ' : ');
ref:=n;
n:=n.owner;
if not Assigned(n) then
wr.W( GetPasTypeName(cent.RetType, ref) )
else
if not Assigned(n) then begin
wr.W( GetPasTypeName(cent.RetType, ref) );
end else
case n.Kind of
nk_Array: begin
for i:=1 to ref.RefCount do wr.W('^');
@ -777,7 +821,7 @@ begin
end;
wr.W(';');
WriteLnCommentForOffset(cent.Offset)
if WriteComment then WriteLnCommentForOffset(cent.Offset)
end;
end;
@ -787,15 +831,14 @@ begin
Breaker:=TLineBreaker.Create;
Breaker.SetText(ParsedText);
if cent is TVarFuncEntity then
WriteFuncOrVar(cent as TVarFuncEntity, True)
else if cent is TTypeDef then
if cent is TVarFuncEntity then begin
WriteFuncOrVar(cent as TVarFuncEntity, True, True)
end else if cent is TTypeDef then
WriteTypeDef(cent as TTypeDef)
else if cent is TStructType then
DeclarePasType(cent as TStructType, TStructType(cent).Name)
else if cent is TEnumType then
DeclarePasType(cent as TEnumType, TEnumType(cent).Name)
else if cent is TComment then
else if (cent is TStructType) or (cent is TEnumType) or (cent is TUnionType) then begin
DeclarePasType(cent, GetCDeclTypeName(cent));
wr.Wln(';');
end else if cent is TComment then
WriteCommentToPas(cent as TComment)
else if cent is TCPrepDefine then
WritePreprocessor(cent as TCPrepDefine)
@ -869,7 +912,7 @@ begin
//todo: bit fields support
for i:=0 to length(st.fields)-1 do begin
WriteLnCommentsBeforeOffset(st.fields[i].v.Offset);
WriteFuncOrVar(st.fields[i].v, False);
WriteFuncOrVar(st.fields[i].v, False, True);
end;
wr.DecIdent;
wr.W('end');
@ -916,26 +959,60 @@ end;
procedure TCodeConvertor.WriteEnumAsConst(en:TEnumType);
var
i : Integer;
v : Int64;
last : AnsiString;
useval : Boolean;
begin
if length(en.items)>0 then begin
PushWriter;
WriteLnCommentsBeforeOffset(en.Offset);
SetPasSection(wr, 'const');
v:=0;
last:='';
useval:=True;
for i:=0 to length(en.items)-1 do begin
WriteLnCommentsBeforeOffset(en.items[i].Offset);
wr.W(en.items[i].Name + ' = ');
if Assigned(en.items[i].Value) then
WriteExp(en.items[i].Value)
else
wr.W(IntToStr(i));
if Assigned(en.items[i].Value) then begin
WriteExp(en.items[i].Value);
useval:=isNumberExp(en.items[i].Value, v);
end else begin
if useval
then wr.W(IntToStr(v))
else wr.W(last+' + 1');
end;
wr.W(';');
WriteLnCommentForOffset(en.items[i].Offset);
inc(v);
last:=en.Items[i].Name;
end;
PopWriter;
end;
wr.W('Integer');
end;
procedure TCodeConvertor.WriteUnion(st:TUnionType);
var
i : Integer;
begin
if cfg.RecordsArePacked then wr.W('packed ');
wr.WLn('record');
wr.Wln('case Integer of');
wr.IncIdent;
for i:=0 to length(st.fields)-1 do begin
WriteLnCommentsBeforeOffset(st.fields[i].v.Offset);
wr.w(IntToStr(i)+':(');
WriteFuncOrVar(st.fields[i].v, False, False);
wr.W(');');
WriteLnCommentForOffset(st.fields[i].v.Offset);
end;
wr.DecIdent;
wr.w('end');
end;
function TCodeConvertor.NextAuxTypeName(const Prefix:AnsiString):AnsiString;
begin
if Prefix='' then Result:='AuxType'+IntToStr(AuxTypeCounter)
@ -949,8 +1026,12 @@ begin
wr.W(PasTypeName + ' = ');
if TypeEntity is TStructType then
WriteStruct(TStructType(TypeEntity))
else if TypeEntity is TEnumType then
else if TypeEntity is TEnumType then begin
WriteEnum(TEnumType(TypeEntity))
end else if TypeEntity is TUnionType then begin
WriteUnion(TUnionType(TypeEntity))
end else if TypeEntity is TSimpleType then
wr.W( cfg.GetTypeName(TSimpleType(TypeEntity).Name))
else begin
{SetPasSection(wr, 'type');
wr.W(PasTypeName + ' = ');}
@ -1163,8 +1244,10 @@ begin
CtoPasTypes.Values['void'] := '';
CtoPasTypes.Values['void*'] := 'Pointer';
CtoPasTypes.Values['void**'] := 'PPointer';
CtoPasTypes.Values['char'] := 'Char';
CtoPasTypes.Values['char*'] := 'PChar';
CtoPasTypes.Values['char**'] := 'PPChar';
CtoPasTypes.Values['signed char'] := 'SmallInt';
CtoPasTypes.Values['long'] := 'Longword';
CtoPasTypes.Values['long*'] := 'PLongword';
CtoPasTypes.Values['long long'] := 'Int64';
@ -1173,6 +1256,7 @@ begin
CtoPasTypes.Values['unsigned long long*'] := 'PQWord';
CtoPasTypes.Values['short'] := 'SmallInt';
CtoPasTypes.Values['short*'] := 'PSmallInt';
CtoPasTypes.Values['unsigned'] := 'LongWord';
CtoPasTypes.Values['unsigned short'] := 'Word';
CtoPasTypes.Values['unsigned short*'] := 'PWord';
CtoPasTypes.Values['unsigned char'] := 'Byte';
@ -1209,5 +1293,20 @@ begin
end;
end;
function PasExp(x: TExpression): AnsiString;
var
i : Integer;
begin
Result:='';
for i:=0 to x.Count-1 do begin
if x.Tokens[i].TokenType=tt_Symbol then
Result:=Result+CtoPasSymbol(x.Tokens[i].Token)+' '
else
Result:=Result+x.Tokens[i].Token+' ';
end;
Result:=Copy(Result, 1, length(Result)-1);
end;
end.

View File

@ -144,6 +144,9 @@ begin
txt:='';
end;
var
parsing : Boolean = False;
procedure TryParse;
var
editor : TSourceEditorInterface;
@ -153,7 +156,11 @@ var
p : TPoint;
st : TPoint;
begin
if parsing then Exit;
if not Assigned(SourceEditorManagerIntf) or not Assigned(SourceEditorManagerIntf.ActiveEditor) then Exit;
parsing:=True;
try
editor:=SourceEditorManagerIntf.ActiveEditor;
if Assigned(CtoPasConfig) then CtoPasConfig.UIToSettings;
@ -174,6 +181,9 @@ begin
if Assigned(CtoPasConfig) then
CtoPasConfig.SettingsToUI;
end;
finally
parsing:=False;
end;
end;
procedure OnCtoPasClick(Sender: TObject);