📄 cncodeformater.pas
字号:
// 如果是label,那么ALabel里头已经放入label了,所以不需要LoadBookmark了
if IsLabel then
begin
// Match(Scaner.Token);
CodeGen.UnLockOutput;
CodeGen.Write(ALabel); // 写入 label,再写剩下的关键字前的空格
if CnPascalCodeForRule.SpaceBeforeASM - LabelLen <= 0 then // Label 太长就换行
begin
// Writeln;
CodeGen.Write(Space(CnPascalCodeForRule.SpaceBeforeASM));
end
else
CodeGen.Write(Space(CnPascalCodeForRule.SpaceBeforeASM - LabelLen));
Scaner.NextToken; // 跳过 label 的冒号
InstrucLen := Length(Scaner.TokenString); // 记住应该是的汇编指令关键字的长度
end
else
begin
Scaner.LoadBookmark(Bookmark);
FLastToken := OldLastToken;
CodeGen.UnLockOutput;
Match(Scaner.Token, CnPascalCodeForRule.SpaceBeforeASM);
AfterKeyword := True;
end;
end
else
begin
CodeGen.ClearOutputLock;
if AfterKeyword and not (Scaner.Token in [tokCRLF, tokSemicolon]) then // 第一字后面必须有空格
begin
if InstrucLen >= CnPascalCodeForRule.SpaceTabASMKeyword then
CodeGen.Write(' ')
else
CodeGen.Write(Space(CnPascalCodeForRule.SpaceTabASMKeyword - InstrucLen));
end;
if Scaner.Token <> tokCRLF then
begin
if AfterKeyword then // 手工写入ASM关键字后面的内容,不用 Pascal 的空格规则
begin
CodeGen.Write(Scaner.TokenString);
FLastToken := Scaner.Token;
Scaner.NextToken;
AfterKeyword := False;
end
else if IsLabel then // 如果前一个是 label,则这个是第一个 Keyword
begin
CodeGen.Write(Scaner.TokenString);
FLastToken := Scaner.Token;
Scaner.NextToken;
IsLabel := False;
AfterKeyword := True;
end
else
begin
if Scaner.Token = tokColon then
Match(Scaner.Token, 0, 0, True)
else if Scaner.Token in (AddOPTokens + MulOPTokens) then
Match(Scaner.Token, 1, 1) // 二元运算符前后各空一格
else
Match(Scaner.Token);
AfterKeyword := False;
end;
end;
end;
//if not OnlyKeyword then
NewLine := False;
if (T = tokSemicolon) or (Scaner.Token = tokCRLF) or
((Scaner.Token = tokKeywordEnd) and (FLastToken <> tokAtSign)) then
begin
Writeln;
NewLine := True;
while Scaner.Token in [tokBlank, tokCRLF] do
Scaner.NextToken;
end;
end;
finally
Scaner.ASMMode := False;
if Scaner.Token in [tokBlank, tokCRLF] then
Scaner.NextToken;
CnPascalCodeForRule.KeywordStyle := OldKeywordStyle; // 恢复 KeywordStyle
Match(tokKeywordEnd, PreSpaceCount);
end;
end;
{ TCnTypeSectionFormater }
{ ArrayConstant -> '(' TypedConstant/','... ')' }
procedure TCnTypeSectionFormater.FormatArrayConstant(PreSpaceCount: Byte);
begin
Match(tokLB);
FormatTypedConstant(PreSpaceCount);
// if Scaner.Token = tokLB then // 数组的括号可能嵌套
// FormatArrayConstant(PreSpaceCount)
// else
while Scaner.Token = tokComma do
begin
Match(Scaner.Token);
FormatTypedConstant(PreSpaceCount);
// if Scaner.Token = tokLB then // 数组的括号可能嵌套
// FormatArrayConstant(PreSpaceCount)
// else
end;
Match(tokRB);
end;
{ ArrayType -> ARRAY ['[' OrdinalType/','... ']'] OF Type }
procedure TCnTypeSectionFormater.FormatArrayType(PreSpaceCount: Byte);
begin
Match(tokKeywordArray);
if Scaner.Token = tokSLB then
begin
Match(tokSLB);
FormatOrdinalType;
while Scaner.Token = tokComma do
begin
Match(Scaner.Token);
FormatOrdinalType;
end;
Match(tokSRB);
end;
Match(tokkeywordOf);
FormatType(PreSpaceCount);
end;
{ ClassFieldList -> (ClassVisibility ObjFieldList)/';'... }
procedure TCnTypeSectionFormater.FormatClassFieldList(PreSpaceCount: Byte);
begin
FormatClassVisibility(PreSpaceCount);
FormatObjFieldList(PreSpaceCount);
Match(tokSemicolon);
while (Scaner.Token in ClassVisibilityTokens) or (Scaner.Token = tokSymbol) do
begin
if Scaner.Token in ClassVisibilityTokens then
FormatClassVisibility(PreSpaceCount);
FormatObjFieldList(PreSpaceCount);
Match(tokSemicolon);
end;
end;
{ ClassHeritage -> '(' IdentList ')' }
procedure TCnTypeSectionFormater.FormatClassHeritage(PreSpaceCount: Byte);
begin
Match(tokLB);
FormatTypeParamIdentList(); // 加入泛型的支持
Match(tokRB);
end;
{ ClassMethodList -> (ClassVisibility MethodList)/';'... }
procedure TCnTypeSectionFormater.FormatClassMethodList(PreSpaceCount: Byte);
begin
FormatClassVisibility(PreSpaceCount);
FormatMethodList(PreSpaceCount);
while Scaner.Token = tokSemicolon do
begin
FormatClassVisibility(PreSpaceCount);
FormatMethodList(PreSpaceCount);
end;
end;
{ ClassPropertyList -> (ClassVisibility PropertyList ';')... }
procedure TCnTypeSectionFormater.FormatClassPropertyList(PreSpaceCount: Byte);
begin
FormatClassVisibility(PreSpaceCount);
FormatPropertyList(PreSpaceCount);
if Scaner.Token = tokSemicolon then
Match(tokSemicolon);
{ TODO: Need Scaner forward look future }
while (Scaner.Token in ClassVisibilityTokens) or (Scaner.Token = tokKeywordProperty) do
begin
if Scaner.Token in ClassVisibilityTokens then
FormatClassVisibility(PreSpaceCount);
Writeln;
FormatPropertyList(PreSpaceCount);
if Scaner.Token = tokSemicolon then
Match(tokSemicolon);
end;
end;
{ ClassRefType -> CLASS OF TypeId }
procedure TCnTypeSectionFormater.FormatClassRefType(PreSpaceCount: Byte);
begin
Match(tokkeywordClass);
Match(tokKeywordOf);
{ TypeId -> [UnitId '.'] <type-identifier> }
Match(tokSymbol);
if Scaner.Token = tokDot then
begin
Match(Scaner.Token);
Match(tokSymbol);
end;
end;
{
ClassType -> CLASS [ClassHeritage]
[ClassFieldList]
[ClassMethodList]
[ClassPropertyList]
END
}
{
TODO: This grammer has something wrong...need to be fixed.
My current FIXED grammer:
ClassType -> CLASS (OF Ident) | ClassBody
ClassBody -> [ClassHeritage] [ClassMemberList END]
ClassMemberList -> ([ClassVisibility] [ClassMember ';']) ...
ClassMember -> ClassField | ClassMethod | ClassProperty
Here is some note in JCF:
=============Cut Here=============
ClassType -> CLASS [ClassHeritage]
[ClassFieldList]
[ClassMethodList]
[ClassPropertyList]
END
This is not right - these can repeat
My own take on this is as follows:
class -> ident '=' 'class' [Classheritage] classbody 'end'
classbody -> clasdeclarations (ClassVisibility clasdeclarations) ...
ClassVisibility -> 'private' | 'protected' | 'public' | 'published' | 'automated'
classdeclarations -> (procheader|fnheader|constructor|destructor|vars|property|) [';'] ...
can also be a forward declaration, e.g.
TFred = class;
or a class ref type
TFoo = class of TBar;
=============Cut End==============
}
procedure TCnTypeSectionFormater.FormatClassType(PreSpaceCount: Byte);
begin
Match(tokKeywordClass);
case Scaner.Token of
tokKeywordOF: // like TFoo = class of TBar;
begin
Match(tokKeywordOF);
FormatIdent;
Exit;
end;
tokSemiColon: Exit; // class declare forward, like TFoo = class;
else
FormatClassBody(PreSpaceCount);
end;
{
while Scaner.Token <> tokKeywordEnd do
begin
// skip ClassVisibilityTokens ( private public ... )
Scaner.SaveBookmark;
while (Scaner.Token in ClassVisibilityTokens + [tokKeywordEnd, tokEOF]) do
begin
Scaner.NextToken;
end;
Token := Scaner.Token;
Scaner.LoadBookmark;
if Token = tokKeywordProperty then
FormatClassPropertyList(Tab(PreSpaceCount))
else if Token in MethodListTokens then
FormatMethodList(Tab(PreSpaceCount))
else
FormatClassFieldList(Tab(PreSpaceCount));
end;
Match(tokKeywordEnd);
}
end;
{ ClassVisibility -> [PUBLIC | PROTECTED | PRIVATE | PUBLISHED] }
procedure TCnTypeSectionFormater.FormatClassVisibility(PreSpaceCount: Byte);
begin
if Scaner.Token = tokKeywordStrict then
begin
Match(Scaner.Token, PreSpaceCount);
if Scaner.Token in ClassVisibilityTokens then
begin
Match(Scaner.Token);
Writeln;
end;
end
else if Scaner.Token in ClassVisibilityTokens then
begin
Match(Scaner.Token, PreSpaceCount);
Writeln;
end;
end;
{ ConstructorHeading -> CONSTRUCTOR Ident [FormalParameters] }
procedure TCnTypeSectionFormater.FormatConstructorHeading(PreSpaceCount: Byte);
begin
Match(tokKeywordConstructor, PreSpaceCount);
FormatMethodName;
if Scaner.Token = tokLB then
FormatFormalParameters;
end;
{ ContainsClause -> CONTAINS IdentList... ';' }
procedure TCnTypeSectionFormater.FormatContainsClause(PreSpaceCount: Byte);
begin
if Scaner.TokenSymbolIs('CONTAINS') then
begin
Match(Scaner.Token, 0, 1);
FormatIdentList;
Match(tokSemicolon);
end;
end;
{ DestructorHeading -> DESTRUCTOR Ident [FormalParameters] }
procedure TCnTypeSectionFormater.FormatDestructorHeading(PreSpaceCount: Byte);
begin
Match(tokKeywordDestructor, PreSpaceCount);
FormatMethodName;
if Scaner.Token = tokLB then
FormatFormalParameters;
end;
{
Directive -> CDECL
-> REGISTER
-> DYNAMIC
-> VIRTUAL
-> EXPORT
-> EXTERNAL
-> FAR
-> FORWARD
-> MESSAGE
-> OVERRIDE
-> OVERLOAD
-> PASCAL
-> REINTRODUCE
-> SAFECALL
-> STDCALL
注:Directive 分两种,一是上面说的大多在函数过程声明后的,可能需要分号分隔
一种是类型或其他声明后的,platform library 等,无需分号分隔的。
}
procedure TCnTypeSectionFormater.FormatDirective(PreSpaceCount: Byte;
IgnoreFirst: Boolean);
begin
if Scaner.Token in DirectiveTokens then
begin
// deal with the Directive use like this
// function MessageBox(...): Integer; stdcall; external 'user32.dll' name 'MessageBoxA';
{
while not (Scaner.Token in [tokSemicolon] + KeywordTokens) do
begin
CodeGen.Write(FormatString(Scaner.TokenString, CnCodeForRule.KeywordStyle), 1);
FLastToken := Scaner.Token;
Scaner.NextToken;
end;
}
if Scaner.Token in [ // 这些是后面可以加参数的
tokDirectiveDispID,
tokDirectiveExternal,
tokDirectiveMESSAGE,
tokComplexName,
tokComplexImplements,
tokComplexStored,
tokComplexRead,
tokComplexWrite,
tokComplexIndex
] then
begin
if not IgnoreFirst then
CodeGen.Write(' '); // 关键字空格分隔
CodeGen.Write(FormatString(Scaner.TokenString, CnPascalCodeForRule.KeywordStyle));
FLastToken := Scaner.Token;
Scaner.NextToken;
if not (Scaner.Token in DirectiveTokens) then // 加个后续的表达式
begin
if Scaner.Token in [tokString, tokWString, tokLB, tokPlus, tokMinus] then
CodeGen.Write(' '); // 后续表达式空格分隔
FormatConstExpr;
end;
// Match(Scaner.Token);
end
else
begin
if not IgnoreFirst then
CodeGen.Write(' '); // 关键字空格分隔
CodeGen.Write(FormatString(Scaner.TokenString, CnPascalCodeForRule.KeywordStyle));
FLastToken := Scaner.Token;
Scaner.NextToken;
end;
end
else
Error('error Directive ' + Scaner.TokenString);
end;
{
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -