feat: 针对C的代码生成 (#50)

Co-authored-by: Lan_G <2911328695@qq.com>
Reviewed-on: PostGuard/Canon#50
This commit is contained in:
2024-04-21 22:24:35 +08:00
parent 4353fb0c01
commit 3a584751dc
36 changed files with 906 additions and 31 deletions

View File

@@ -1,4 +1,6 @@
using Canon.Core.Enums;
using Canon.Core.CodeGenerators;
using Canon.Core.Enums;
using Canon.Core.LexicalParser;
namespace Canon.Core.SyntaxNodes;
@@ -10,4 +12,22 @@ public class AddOperator : NonTerminatedSyntaxNode
{
return new AddOperator { Children = children };
}
public override void GenerateCCode(CCodeBuilder builder)
{
var operatorType = Children[0].Convert<TerminatedSyntaxNode>().Token.
Convert<OperatorSemanticToken>().OperatorType;
if (operatorType == OperatorType.Plus)
{
builder.AddString(" +");
}
else if (operatorType == OperatorType.Minus)
{
builder.AddString(" -");
}
else
{
builder.AddString(" ||");
}
}
}

View File

@@ -1,4 +1,7 @@
using Canon.Core.Enums;
using Canon.Core.CodeGenerators;
using Canon.Core.Enums;
using Canon.Core.LexicalParser;
using Canon.Core.SemanticParser;
namespace Canon.Core.SyntaxNodes;
@@ -10,4 +13,50 @@ public class BasicType : NonTerminatedSyntaxNode
{
return new BasicType { Children = children };
}
public override void GenerateCCode(CCodeBuilder builder)
{
var keywordType = Children[0].Convert<TerminatedSyntaxNode>().Token
.Convert<KeywordSemanticToken>().KeywordType;
switch (keywordType)
{
case KeywordType.Integer:
builder.AddString(" int");
break;
case KeywordType.Real:
builder.AddString(" double");
break;
case KeywordType.Boolean:
builder.AddString(" bool");
break;
case KeywordType.Character:
builder.AddString(" char");
break;
}
}
/// <summary>
///尝试获取Pascal的基本类型
/// </summary>
/// <returns></returns>
public PascalType TryGetPascalType()
{
var keywordType = Children[0].Convert<TerminatedSyntaxNode>().Token
.Convert<KeywordSemanticToken>().KeywordType;
switch (keywordType)
{
case KeywordType.Integer:
return PascalBasicType.Integer;
case KeywordType.Real:
return PascalBasicType.Real;
case KeywordType.Boolean:
return PascalBasicType.Boolean;
case KeywordType.Character:
return PascalBasicType.Character;
}
return PascalBasicType.Void;
}
}

View File

@@ -1,4 +1,5 @@
using Canon.Core.Enums;
using Canon.Core.CodeGenerators;
using Canon.Core.Enums;
namespace Canon.Core.SyntaxNodes;
@@ -12,4 +13,16 @@ public class CompoundStatement : NonTerminatedSyntaxNode
{
return new CompoundStatement { Children = children };
}
public override void GenerateCCode(CCodeBuilder builder)
{
foreach (var statement in Statements.Reverse())
{
if (statement.Children.Count > 0)
{
statement.GenerateCCode(builder);
builder.AddString(";");
}
}
}
}

View File

@@ -1,4 +1,5 @@
using Canon.Core.Enums;
using Canon.Core.CodeGenerators;
using Canon.Core.Enums;
using Canon.Core.LexicalParser;
namespace Canon.Core.SyntaxNodes;
@@ -40,4 +41,38 @@ public class ConstDeclarations : NonTerminatedSyntaxNode
}
}
}
public override void GenerateCCode(CCodeBuilder builder)
{
foreach (var pair in ConstValues.Reverse())
{
builder.AddString(" const");
//获取常量类型
var token = pair.Item2.Children[0].Convert<TerminatedSyntaxNode>().Token;
var tokenType = token.TokenType;
if (tokenType == SemanticTokenType.Number)
{
if (token.Convert<NumberSemanticToken>().NumberType == NumberType.Integer)
{
builder.AddString(" int ");
}
else
{
builder.AddString(" double ");
}
}
else if (tokenType == SemanticTokenType.Character)
{
builder.AddString(" char ");
}
else
{
builder.AddString(" bool ");
}
builder.AddString(pair.Item1.IdentifierName + " =");
pair.Item2.GenerateCCode(builder);
builder.AddString(";");
}
}
}

View File

@@ -1,4 +1,5 @@
using Canon.Core.Enums;
using Canon.Core.CodeGenerators;
using Canon.Core.Enums;
namespace Canon.Core.SyntaxNodes;
@@ -10,4 +11,24 @@ public class ConstValue : NonTerminatedSyntaxNode
{
return new ConstValue { Children = children };
}
public override void GenerateCCode(CCodeBuilder builder)
{
//获取常量值
var token = Children[0].Convert<TerminatedSyntaxNode>().Token;
//constValue -> 'letter'
if (token.TokenType == SemanticTokenType.Character)
{
builder.AddString(" '" + token.LiteralValue + "'");
}
else
{
builder.AddString(" ");
// constValue -> +num | -num | num
foreach (var c in Children)
{
builder.AddString(c.Convert<TerminatedSyntaxNode>().Token.LiteralValue);
}
}
}
}

View File

@@ -1,4 +1,5 @@
using Canon.Core.Enums;
using Canon.Core.CodeGenerators;
using Canon.Core.Enums;
namespace Canon.Core.SyntaxNodes;
@@ -10,4 +11,14 @@ public class ElsePart : NonTerminatedSyntaxNode
{
return new ElsePart { Children = children };
}
public override void GenerateCCode(CCodeBuilder builder)
{
if (Children.Count > 0)
{
builder.AddString(" else{");
Children[1].GenerateCCode(builder);
builder.AddString(" }");
}
}
}

View File

@@ -1,4 +1,5 @@
using Canon.Core.Enums;
using Canon.Core.CodeGenerators;
using Canon.Core.Enums;
namespace Canon.Core.SyntaxNodes;
@@ -10,4 +11,12 @@ public class Expression : NonTerminatedSyntaxNode
{
return new Expression { Children = children };
}
public override void GenerateCCode(CCodeBuilder builder)
{
foreach (var child in Children)
{
child.GenerateCCode(builder);
}
}
}

View File

@@ -1,4 +1,5 @@
using Canon.Core.Enums;
using Canon.Core.CodeGenerators;
using Canon.Core.Enums;
namespace Canon.Core.SyntaxNodes;
@@ -51,4 +52,22 @@ public class ExpressionList : NonTerminatedSyntaxNode
}
}
}
public override void GenerateCCode(CCodeBuilder builder)
{
//用逗号分隔输出的expression
using var enumerator = Expressions.GetEnumerator();
if (enumerator.MoveNext())
{
enumerator.Current.GenerateCCode(builder);
}
while (enumerator.MoveNext())
{
builder.AddString(", ");
enumerator.Current.GenerateCCode(builder);
}
}
}

View File

@@ -1,4 +1,6 @@
using Canon.Core.Enums;
using Canon.Core.CodeGenerators;
using Canon.Core.Enums;
using Canon.Core.LexicalParser;
namespace Canon.Core.SyntaxNodes;
@@ -10,4 +12,56 @@ public class Factor : NonTerminatedSyntaxNode
{
return new Factor { Children = children };
}
public override void GenerateCCode(CCodeBuilder builder)
{
if (Children.Count == 1)
{
//factor -> num
if (Children[0].IsTerminated)
{
var token = Children[0].Convert<TerminatedSyntaxNode>().Token;
if (token.TokenType == SemanticTokenType.Number)
{
builder.AddString(" " + token.LiteralValue);
}
}
// factor -> variable
else
{
Children[0].GenerateCCode(builder);
}
}
//factor -> ( expression )
else if (Children.Count == 3)
{
builder.AddString(" (");
Children[1].GenerateCCode(builder);
builder.AddString(")");
}
//factor -> id ( expression )
else if (Children.Count == 4)
{
builder.AddString(" " + Children[0].Convert<TerminatedSyntaxNode>().Token.
Convert<IdentifierSemanticToken>().IdentifierName);
builder.AddString("(");
Children[2].GenerateCCode(builder);
builder.AddString(")");
}
else
{ //factor -> not factor
builder.AddString(" (");
if (Children[0].Convert<TerminatedSyntaxNode>().Token.TokenType == SemanticTokenType.Keyword)
{
builder.AddString("!");
}
else
{
builder.AddString("-");
}
Children[1].GenerateCCode(builder);
builder.AddString(")");
}
}
}

View File

@@ -1,4 +1,5 @@
using Canon.Core.Enums;
using Canon.Core.CodeGenerators;
using Canon.Core.Enums;
using Canon.Core.LexicalParser;
namespace Canon.Core.SyntaxNodes;
@@ -55,4 +56,20 @@ public class IdentifierList : NonTerminatedSyntaxNode
}
}
}
public override void GenerateCCode(CCodeBuilder builder)
{
//用逗号分隔输出的expression
using var enumerator = Identifiers.Reverse().GetEnumerator();
if (enumerator.MoveNext())
{
builder.AddString(" " + enumerator.Current.IdentifierName);
}
while (enumerator.MoveNext())
{
builder.AddString(", " + enumerator.Current.IdentifierName);
}
}
}

View File

@@ -1,4 +1,6 @@
using Canon.Core.Enums;
using Canon.Core.CodeGenerators;
using Canon.Core.Enums;
using Canon.Core.SemanticParser;
namespace Canon.Core.SyntaxNodes;
@@ -48,4 +50,5 @@ public class IdentifierVarPart : NonTerminatedSyntaxNode
return new IdentifierVarPart { Children = children, Exist = exist };
}
}

View File

@@ -1,4 +1,6 @@
using Canon.Core.Enums;
using Canon.Core.CodeGenerators;
using Canon.Core.Enums;
using Canon.Core.LexicalParser;
namespace Canon.Core.SyntaxNodes;
@@ -10,4 +12,39 @@ public class MultiplyOperator : NonTerminatedSyntaxNode
{
return new MultiplyOperator { Children = children };
}
public override void GenerateCCode(CCodeBuilder builder)
{
var token = Children[0].Convert<TerminatedSyntaxNode>().Token;
if (token.TokenType == SemanticTokenType.Operator)
{
var operatorType = token.Convert<OperatorSemanticToken>().OperatorType;
if (operatorType == OperatorType.Multiply)
{
builder.AddString(" *");
}
else if (operatorType == OperatorType.Divide)
{
//实数除法需要将操作数强转为float
builder.AddString(" /(double)");
}
}
else
{
var keywordType = token.Convert<KeywordSemanticToken>().KeywordType;
if (keywordType == KeywordType.And)
{
builder.AddString(" &&");
}
else if (keywordType == KeywordType.Mod)
{
builder.AddString(" %");
}
else
{
builder.AddString(" /");
}
}
}
}

View File

@@ -1,4 +1,5 @@
using Canon.Core.Enums;
using Canon.Core.CodeGenerators;
using Canon.Core.Enums;
using Canon.Core.LexicalParser;
namespace Canon.Core.SyntaxNodes;

View File

@@ -1,4 +1,5 @@
using Canon.Core.Enums;
using Canon.Core.CodeGenerators;
using Canon.Core.Enums;
using Canon.Core.LexicalParser;
namespace Canon.Core.SyntaxNodes;
@@ -29,4 +30,26 @@ public class ProcedureCall : NonTerminatedSyntaxNode
yield return expression;
}
}
public override void GenerateCCode(CCodeBuilder builder)
{
builder.AddString(ProcedureId.IdentifierName + "(");
//用逗号分隔输出的expression
using (var enumerator = Arguments.GetEnumerator())
{
if (enumerator.MoveNext())
{
enumerator.Current.GenerateCCode(builder);
}
while (enumerator.MoveNext())
{
builder.AddString(", ");
enumerator.Current.GenerateCCode(builder);
}
}
builder.AddString(")");
}
}

View File

@@ -1,4 +1,5 @@
using Canon.Core.Enums;
using Canon.Core.CodeGenerators;
using Canon.Core.Enums;
namespace Canon.Core.SyntaxNodes;
@@ -30,4 +31,17 @@ public class ProgramBody : NonTerminatedSyntaxNode
{
return new ProgramBody { Children = children };
}
public override void GenerateCCode(CCodeBuilder builder)
{
//全局常量,变量
ConstDeclarations.GenerateCCode(builder);
VarDeclarations.GenerateCCode(builder);
//子函数声明
SubprogramDeclarations.GenerateCCode(builder);
//main函数
builder.AddString(" int main(){");
CompoundStatement.GenerateCCode(builder);
builder.AddString(" return 0;}");
}
}

View File

@@ -24,6 +24,7 @@ public class ProgramStruct : NonTerminatedSyntaxNode
public override void GenerateCCode(CCodeBuilder builder)
{
builder.AddString("#include <PascalCoreLib.h>");
builder.AddString("#include <PascalCoreLib.h> #include <stdbool.h>");
Body.GenerateCCode(builder);
}
}

View File

@@ -1,4 +1,6 @@
using Canon.Core.Enums;
using Canon.Core.CodeGenerators;
using Canon.Core.Enums;
using Canon.Core.LexicalParser;
namespace Canon.Core.SyntaxNodes;
@@ -10,4 +12,31 @@ public class RelationOperator : NonTerminatedSyntaxNode
{
return new RelationOperator { Children = children };
}
public override void GenerateCCode(CCodeBuilder builder)
{
var operatorType = Children[0].Convert<TerminatedSyntaxNode>().Token.
Convert<OperatorSemanticToken>().OperatorType;
switch (operatorType)
{
case OperatorType.Equal:
builder.AddString(" ==");
break;
case OperatorType.Greater:
builder.AddString(" >");
break;
case OperatorType.Less:
builder.AddString(" <");
break;
case OperatorType.GreaterEqual:
builder.AddString(" >=");
break;
case OperatorType.LessEqual:
builder.AddString(" <=");
break;
case OperatorType.NotEqual:
builder.AddString(" !=");
break;
}
}
}

View File

@@ -1,4 +1,5 @@
using Canon.Core.Enums;
using Canon.Core.CodeGenerators;
using Canon.Core.Enums;
namespace Canon.Core.SyntaxNodes;
@@ -10,4 +11,12 @@ public class SimpleExpression : NonTerminatedSyntaxNode
{
return new SimpleExpression { Children = children };
}
public override void GenerateCCode(CCodeBuilder builder)
{
foreach (var child in Children)
{
child.GenerateCCode(builder);
}
}
}

View File

@@ -1,4 +1,6 @@
using Canon.Core.Enums;
using Canon.Core.CodeGenerators;
using Canon.Core.Enums;
using Canon.Core.LexicalParser;
namespace Canon.Core.SyntaxNodes;
@@ -10,4 +12,47 @@ public class Statement : NonTerminatedSyntaxNode
{
return new Statement { Children = children };
}
public override void GenerateCCode(CCodeBuilder builder)
{
if (Children.Count == 0)
{
return;
}
// statement -> procedureCall | compoundStatement
if (Children.Count == 1)
{
Children[0].GenerateCCode(builder);
}
//statement -> variable assign expression
else if (Children.Count == 3)
{
Children[0].GenerateCCode(builder);
builder.AddString(" =");
Children[2].GenerateCCode(builder);
}
//if expression then statement else_part
else if (Children.Count == 5)
{
builder.AddString(" if(");
Children[1].GenerateCCode(builder);
builder.AddString("){");
Children[3].GenerateCCode(builder);
builder.AddString("; }");
Children[4].GenerateCCode(builder);
}
//for id assign expression to expression do statement
else
{
string idName = Children[1].Convert<TerminatedSyntaxNode>().Token.Convert<IdentifierSemanticToken>()
.IdentifierName;
builder.AddString(" for(" + idName + " =");
Children[3].GenerateCCode(builder);
builder.AddString("; " + idName + " <=");
Children[5].GenerateCCode(builder);
builder.AddString("; " + idName + "++){");
Children[7].GenerateCCode(builder);
builder.AddString("; }");
}
}
}

View File

@@ -1,4 +1,5 @@
using Canon.Core.Enums;
using Canon.Core.CodeGenerators;
using Canon.Core.Enums;
namespace Canon.Core.SyntaxNodes;
@@ -48,4 +49,16 @@ public class StatementList : NonTerminatedSyntaxNode
}
}
}
public override void GenerateCCode(CCodeBuilder builder)
{
foreach (var statement in Statements.Reverse())
{
if (statement.Children.Count > 0)
{
statement.GenerateCCode(builder);
builder.AddString(";");
}
}
}
}

View File

@@ -1,4 +1,5 @@
using Canon.Core.Enums;
using Canon.Core.CodeGenerators;
using Canon.Core.Enums;
namespace Canon.Core.SyntaxNodes;
@@ -20,4 +21,14 @@ public class Subprogram : NonTerminatedSyntaxNode
{
return new Subprogram { Children = children };
}
public override void GenerateCCode(CCodeBuilder builder)
{
//子函数头
Head.GenerateCCode(builder);
//子函数体
builder.AddString("{");
Body.GenerateCCode(builder);
builder.AddString("}");
}
}

View File

@@ -1,4 +1,5 @@
using Canon.Core.Enums;
using Canon.Core.CodeGenerators;
using Canon.Core.Enums;
namespace Canon.Core.SyntaxNodes;
@@ -25,4 +26,11 @@ public class SubprogramBody : NonTerminatedSyntaxNode
{
return new SubprogramBody() { Children = children };
}
public override void GenerateCCode(CCodeBuilder builder)
{
ConstDeclarations.GenerateCCode(builder);
VarDeclarations.GenerateCCode(builder);
CompoundStatement.GenerateCCode(builder);
}
}

View File

@@ -1,4 +1,5 @@
using Canon.Core.Enums;
using Canon.Core.CodeGenerators;
using Canon.Core.Enums;
namespace Canon.Core.SyntaxNodes;
@@ -31,4 +32,12 @@ public class SubprogramDeclarations : NonTerminatedSyntaxNode
declarations = declarations.Children[0].Convert<SubprogramDeclarations>();
}
}
public override void GenerateCCode(CCodeBuilder builder)
{
foreach (var subprogram in Subprograms)
{
subprogram.GenerateCCode(builder);
}
}
}

View File

@@ -1,4 +1,5 @@
using Canon.Core.Enums;
using Canon.Core.CodeGenerators;
using Canon.Core.Enums;
using Canon.Core.LexicalParser;
namespace Canon.Core.SyntaxNodes;
@@ -42,4 +43,28 @@ public class SubprogramHead : NonTerminatedSyntaxNode
return new SubprogramHead { Children = children, IsProcedure = isProcedure };
}
public override void GenerateCCode(CCodeBuilder builder)
{
//可能要用到符号表
if (IsProcedure)
{
builder.AddString("void ");
}
else
{
//返回类型暂时未知
builder.AddString("int ");
}
builder.AddString(SubprogramName.LiteralValue);
builder.AddString("(");
foreach (var param in Parameters)
{
}
builder.AddString(")");
}
}

View File

@@ -1,4 +1,5 @@
using Canon.Core.Enums;
using Canon.Core.CodeGenerators;
using Canon.Core.Enums;
namespace Canon.Core.SyntaxNodes;
@@ -10,4 +11,12 @@ public class Term : NonTerminatedSyntaxNode
{
return new Term { Children = children };
}
public override void GenerateCCode(CCodeBuilder builder)
{
foreach (var child in Children)
{
child.GenerateCCode(builder);
}
}
}

View File

@@ -1,4 +1,5 @@
using Canon.Core.Enums;
using Canon.Core.CodeGenerators;
using Canon.Core.Enums;
namespace Canon.Core.SyntaxNodes;
@@ -10,4 +11,18 @@ public class TypeSyntaxNode : NonTerminatedSyntaxNode
{
return new TypeSyntaxNode { Children = children };
}
public override void GenerateCCode(CCodeBuilder builder)
{
//type -> basic_type
if (Children.Count == 1)
{
Children[0].GenerateCCode(builder);
}
//type -> array [ period ]of basic_type
else
{
}
}
}

View File

@@ -1,4 +1,5 @@
using Canon.Core.Enums;
using Canon.Core.CodeGenerators;
using Canon.Core.Enums;
namespace Canon.Core.SyntaxNodes;
@@ -20,4 +21,10 @@ public class ValueParameter : NonTerminatedSyntaxNode
{
return new ValueParameter { Children = children };
}
public override void GenerateCCode(CCodeBuilder builder)
{
//可能涉及符号表访问
builder.AddString("valueParam ");
}
}

View File

@@ -1,4 +1,6 @@
using Canon.Core.Enums;
using Canon.Core.CodeGenerators;
using Canon.Core.Enums;
using Canon.Core.SemanticParser;
namespace Canon.Core.SyntaxNodes;
@@ -39,4 +41,49 @@ public class VarDeclarations : NonTerminatedSyntaxNode
}
}
}
public override void GenerateCCode(CCodeBuilder builder)
{
foreach (var pair in Variables.Reverse())
{
//BasicType定义
if (pair.Item2.Children.Count == 1)
{
//输出类型
pair.Item2.GenerateCCode(builder);
//输出idList
pair.Item1.GenerateCCode(builder);
builder.AddString(";");
}
//array定义
else
{
//构造出C语言形式的数组下标定义
string arrayPeriod = "";
var ranges = pair.Item2.Children[2]
.Convert<Period>().Ranges;
PascalType pascalType = pair.Item2.Children[5].Convert<BasicType>().TryGetPascalType();
foreach (var range in ranges)
{
int low = int.Parse(range.Item1.LiteralValue);
int high = int.Parse(range.Item2.LiteralValue);
arrayPeriod = "[" + System.Convert.ToString(high-low+1) + "]" + arrayPeriod;
pascalType = new PascalArrayType(pascalType, low, high); //嵌套地构造出多维数组
}
//依次定义每一个符号
foreach (var id in pair.Item1.Identifiers.Reverse())
{
pair.Item2.Children[5].GenerateCCode(builder);
builder.AddString(" " + id.IdentifierName + arrayPeriod + ";");
//写入符号表
builder.SymbolTable.TryAddSymbol(new Symbol()
{
SymbolName = id.IdentifierName, SymbolType = pascalType, Reference = false
});
}
}
}
}
}

View File

@@ -1,4 +1,5 @@
using Canon.Core.Enums;
using Canon.Core.CodeGenerators;
using Canon.Core.Enums;
namespace Canon.Core.SyntaxNodes;
@@ -12,4 +13,9 @@ public class VarParameter : NonTerminatedSyntaxNode
{
return new VarParameter { Children = children };
}
public override void GenerateCCode(CCodeBuilder builder)
{
ValueParameter.GenerateCCode(builder);
}
}

View File

@@ -1,5 +1,7 @@
using Canon.Core.Enums;
using Canon.Core.CodeGenerators;
using Canon.Core.Enums;
using Canon.Core.LexicalParser;
using Canon.Core.SemanticParser;
namespace Canon.Core.SyntaxNodes;
@@ -17,4 +19,44 @@ public class Variable : NonTerminatedSyntaxNode
{
return new Variable { Children = children };
}
public override void GenerateCCode(CCodeBuilder builder)
{
//判断是否为引用变量
builder.SymbolTable.TryGetSymbol(Identifier.IdentifierName, out var symbol);
if (symbol is not null && symbol.Reference)
{
builder.AddString(" (*" + Identifier.IdentifierName + ")");
}
else
{
builder.AddString(" " + Identifier.IdentifierName);
}
//处理idVarPart数组下标部分
var idVarPart = Children[1].Convert<IdentifierVarPart>();
if (idVarPart.Exist)
{
PascalArrayType pascalArrayType = (PascalArrayType)symbol.SymbolType;
var positions = idVarPart.Positions;
foreach (var pos in positions.Reverse())
{
builder.AddString("[");
pos.GenerateCCode(builder);
//pascal下标减去左边界从而映射到C语言的下标
builder.AddString(" - " + System.Convert.ToString(pascalArrayType.Begin) + "]");
try
{
pascalArrayType = (PascalArrayType)pascalArrayType.ElementType;
}
catch (InvalidCastException e)
{
//do nothing
//因为最后一层嵌套类型必然不是PascalArrayType, 而是BasicType
}
}
}
}
}