feat: 针对C的代码生成 (#50)
Co-authored-by: Lan_G <2911328695@qq.com> Reviewed-on: PostGuard/Canon#50
This commit is contained in:
parent
4353fb0c01
commit
3a584751dc
|
@ -1,4 +1,5 @@
|
||||||
using System.Text;
|
using System.Text;
|
||||||
|
using Canon.Core.SemanticParser;
|
||||||
|
|
||||||
namespace Canon.Core.CodeGenerators;
|
namespace Canon.Core.CodeGenerators;
|
||||||
|
|
||||||
|
@ -9,6 +10,11 @@ public class CCodeBuilder
|
||||||
{
|
{
|
||||||
private readonly StringBuilder _builder = new();
|
private readonly StringBuilder _builder = new();
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 符号表
|
||||||
|
/// </summary>
|
||||||
|
public SymbolTable SymbolTable { get; } = new();
|
||||||
|
|
||||||
public void AddString(string code)
|
public void AddString(string code)
|
||||||
{
|
{
|
||||||
_builder.Append(code);
|
_builder.Append(code);
|
||||||
|
|
|
@ -49,6 +49,16 @@ public abstract class SemanticToken : IEquatable<SemanticToken>
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public T Convert<T>() where T : SemanticToken
|
||||||
|
{
|
||||||
|
if (this is T result)
|
||||||
|
{
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
throw new InvalidOperationException("Can not convert target type0");
|
||||||
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 栈底符号单例对象
|
/// 栈底符号单例对象
|
||||||
/// </summary>
|
/// </summary>
|
||||||
|
|
|
@ -1,4 +1,6 @@
|
||||||
using Canon.Core.Enums;
|
using Canon.Core.CodeGenerators;
|
||||||
|
using Canon.Core.Enums;
|
||||||
|
using Canon.Core.LexicalParser;
|
||||||
|
|
||||||
namespace Canon.Core.SyntaxNodes;
|
namespace Canon.Core.SyntaxNodes;
|
||||||
|
|
||||||
|
@ -10,4 +12,22 @@ public class AddOperator : NonTerminatedSyntaxNode
|
||||||
{
|
{
|
||||||
return new AddOperator { Children = children };
|
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(" ||");
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -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;
|
namespace Canon.Core.SyntaxNodes;
|
||||||
|
|
||||||
|
@ -10,4 +13,50 @@ public class BasicType : NonTerminatedSyntaxNode
|
||||||
{
|
{
|
||||||
return new BasicType { Children = children };
|
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;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,4 +1,5 @@
|
||||||
using Canon.Core.Enums;
|
using Canon.Core.CodeGenerators;
|
||||||
|
using Canon.Core.Enums;
|
||||||
|
|
||||||
namespace Canon.Core.SyntaxNodes;
|
namespace Canon.Core.SyntaxNodes;
|
||||||
|
|
||||||
|
@ -12,4 +13,16 @@ public class CompoundStatement : NonTerminatedSyntaxNode
|
||||||
{
|
{
|
||||||
return new CompoundStatement { Children = children };
|
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(";");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,4 +1,5 @@
|
||||||
using Canon.Core.Enums;
|
using Canon.Core.CodeGenerators;
|
||||||
|
using Canon.Core.Enums;
|
||||||
using Canon.Core.LexicalParser;
|
using Canon.Core.LexicalParser;
|
||||||
|
|
||||||
namespace Canon.Core.SyntaxNodes;
|
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(";");
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,4 +1,5 @@
|
||||||
using Canon.Core.Enums;
|
using Canon.Core.CodeGenerators;
|
||||||
|
using Canon.Core.Enums;
|
||||||
|
|
||||||
namespace Canon.Core.SyntaxNodes;
|
namespace Canon.Core.SyntaxNodes;
|
||||||
|
|
||||||
|
@ -10,4 +11,24 @@ public class ConstValue : NonTerminatedSyntaxNode
|
||||||
{
|
{
|
||||||
return new ConstValue { Children = children };
|
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);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,4 +1,5 @@
|
||||||
using Canon.Core.Enums;
|
using Canon.Core.CodeGenerators;
|
||||||
|
using Canon.Core.Enums;
|
||||||
|
|
||||||
namespace Canon.Core.SyntaxNodes;
|
namespace Canon.Core.SyntaxNodes;
|
||||||
|
|
||||||
|
@ -10,4 +11,14 @@ public class ElsePart : NonTerminatedSyntaxNode
|
||||||
{
|
{
|
||||||
return new ElsePart { Children = children };
|
return new ElsePart { Children = children };
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public override void GenerateCCode(CCodeBuilder builder)
|
||||||
|
{
|
||||||
|
if (Children.Count > 0)
|
||||||
|
{
|
||||||
|
builder.AddString(" else{");
|
||||||
|
Children[1].GenerateCCode(builder);
|
||||||
|
builder.AddString(" }");
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,4 +1,5 @@
|
||||||
using Canon.Core.Enums;
|
using Canon.Core.CodeGenerators;
|
||||||
|
using Canon.Core.Enums;
|
||||||
|
|
||||||
namespace Canon.Core.SyntaxNodes;
|
namespace Canon.Core.SyntaxNodes;
|
||||||
|
|
||||||
|
@ -10,4 +11,12 @@ public class Expression : NonTerminatedSyntaxNode
|
||||||
{
|
{
|
||||||
return new Expression { Children = children };
|
return new Expression { Children = children };
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public override void GenerateCCode(CCodeBuilder builder)
|
||||||
|
{
|
||||||
|
foreach (var child in Children)
|
||||||
|
{
|
||||||
|
child.GenerateCCode(builder);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,4 +1,5 @@
|
||||||
using Canon.Core.Enums;
|
using Canon.Core.CodeGenerators;
|
||||||
|
using Canon.Core.Enums;
|
||||||
|
|
||||||
namespace Canon.Core.SyntaxNodes;
|
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);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,4 +1,6 @@
|
||||||
using Canon.Core.Enums;
|
using Canon.Core.CodeGenerators;
|
||||||
|
using Canon.Core.Enums;
|
||||||
|
using Canon.Core.LexicalParser;
|
||||||
|
|
||||||
namespace Canon.Core.SyntaxNodes;
|
namespace Canon.Core.SyntaxNodes;
|
||||||
|
|
||||||
|
@ -10,4 +12,56 @@ public class Factor : NonTerminatedSyntaxNode
|
||||||
{
|
{
|
||||||
return new Factor { Children = children };
|
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(")");
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,4 +1,5 @@
|
||||||
using Canon.Core.Enums;
|
using Canon.Core.CodeGenerators;
|
||||||
|
using Canon.Core.Enums;
|
||||||
using Canon.Core.LexicalParser;
|
using Canon.Core.LexicalParser;
|
||||||
|
|
||||||
namespace Canon.Core.SyntaxNodes;
|
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);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,4 +1,6 @@
|
||||||
using Canon.Core.Enums;
|
using Canon.Core.CodeGenerators;
|
||||||
|
using Canon.Core.Enums;
|
||||||
|
using Canon.Core.SemanticParser;
|
||||||
|
|
||||||
namespace Canon.Core.SyntaxNodes;
|
namespace Canon.Core.SyntaxNodes;
|
||||||
|
|
||||||
|
@ -48,4 +50,5 @@ public class IdentifierVarPart : NonTerminatedSyntaxNode
|
||||||
|
|
||||||
return new IdentifierVarPart { Children = children, Exist = exist };
|
return new IdentifierVarPart { Children = children, Exist = exist };
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,4 +1,6 @@
|
||||||
using Canon.Core.Enums;
|
using Canon.Core.CodeGenerators;
|
||||||
|
using Canon.Core.Enums;
|
||||||
|
using Canon.Core.LexicalParser;
|
||||||
|
|
||||||
namespace Canon.Core.SyntaxNodes;
|
namespace Canon.Core.SyntaxNodes;
|
||||||
|
|
||||||
|
@ -10,4 +12,39 @@ public class MultiplyOperator : NonTerminatedSyntaxNode
|
||||||
{
|
{
|
||||||
return new MultiplyOperator { Children = children };
|
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(" /");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,4 +1,5 @@
|
||||||
using Canon.Core.Enums;
|
using Canon.Core.CodeGenerators;
|
||||||
|
using Canon.Core.Enums;
|
||||||
using Canon.Core.LexicalParser;
|
using Canon.Core.LexicalParser;
|
||||||
|
|
||||||
namespace Canon.Core.SyntaxNodes;
|
namespace Canon.Core.SyntaxNodes;
|
||||||
|
|
|
@ -1,4 +1,5 @@
|
||||||
using Canon.Core.Enums;
|
using Canon.Core.CodeGenerators;
|
||||||
|
using Canon.Core.Enums;
|
||||||
using Canon.Core.LexicalParser;
|
using Canon.Core.LexicalParser;
|
||||||
|
|
||||||
namespace Canon.Core.SyntaxNodes;
|
namespace Canon.Core.SyntaxNodes;
|
||||||
|
@ -29,4 +30,26 @@ public class ProcedureCall : NonTerminatedSyntaxNode
|
||||||
yield return expression;
|
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(")");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,4 +1,5 @@
|
||||||
using Canon.Core.Enums;
|
using Canon.Core.CodeGenerators;
|
||||||
|
using Canon.Core.Enums;
|
||||||
|
|
||||||
namespace Canon.Core.SyntaxNodes;
|
namespace Canon.Core.SyntaxNodes;
|
||||||
|
|
||||||
|
@ -30,4 +31,17 @@ public class ProgramBody : NonTerminatedSyntaxNode
|
||||||
{
|
{
|
||||||
return new ProgramBody { Children = children };
|
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;}");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -24,6 +24,7 @@ public class ProgramStruct : NonTerminatedSyntaxNode
|
||||||
|
|
||||||
public override void GenerateCCode(CCodeBuilder builder)
|
public override void GenerateCCode(CCodeBuilder builder)
|
||||||
{
|
{
|
||||||
builder.AddString("#include <PascalCoreLib.h>");
|
builder.AddString("#include <PascalCoreLib.h> #include <stdbool.h>");
|
||||||
|
Body.GenerateCCode(builder);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,4 +1,6 @@
|
||||||
using Canon.Core.Enums;
|
using Canon.Core.CodeGenerators;
|
||||||
|
using Canon.Core.Enums;
|
||||||
|
using Canon.Core.LexicalParser;
|
||||||
|
|
||||||
namespace Canon.Core.SyntaxNodes;
|
namespace Canon.Core.SyntaxNodes;
|
||||||
|
|
||||||
|
@ -10,4 +12,31 @@ public class RelationOperator : NonTerminatedSyntaxNode
|
||||||
{
|
{
|
||||||
return new RelationOperator { Children = children };
|
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;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,4 +1,5 @@
|
||||||
using Canon.Core.Enums;
|
using Canon.Core.CodeGenerators;
|
||||||
|
using Canon.Core.Enums;
|
||||||
|
|
||||||
namespace Canon.Core.SyntaxNodes;
|
namespace Canon.Core.SyntaxNodes;
|
||||||
|
|
||||||
|
@ -10,4 +11,12 @@ public class SimpleExpression : NonTerminatedSyntaxNode
|
||||||
{
|
{
|
||||||
return new SimpleExpression { Children = children };
|
return new SimpleExpression { Children = children };
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public override void GenerateCCode(CCodeBuilder builder)
|
||||||
|
{
|
||||||
|
foreach (var child in Children)
|
||||||
|
{
|
||||||
|
child.GenerateCCode(builder);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,4 +1,6 @@
|
||||||
using Canon.Core.Enums;
|
using Canon.Core.CodeGenerators;
|
||||||
|
using Canon.Core.Enums;
|
||||||
|
using Canon.Core.LexicalParser;
|
||||||
|
|
||||||
namespace Canon.Core.SyntaxNodes;
|
namespace Canon.Core.SyntaxNodes;
|
||||||
|
|
||||||
|
@ -10,4 +12,47 @@ public class Statement : NonTerminatedSyntaxNode
|
||||||
{
|
{
|
||||||
return new Statement { Children = children };
|
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("; }");
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,4 +1,5 @@
|
||||||
using Canon.Core.Enums;
|
using Canon.Core.CodeGenerators;
|
||||||
|
using Canon.Core.Enums;
|
||||||
|
|
||||||
namespace Canon.Core.SyntaxNodes;
|
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(";");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,4 +1,5 @@
|
||||||
using Canon.Core.Enums;
|
using Canon.Core.CodeGenerators;
|
||||||
|
using Canon.Core.Enums;
|
||||||
|
|
||||||
namespace Canon.Core.SyntaxNodes;
|
namespace Canon.Core.SyntaxNodes;
|
||||||
|
|
||||||
|
@ -20,4 +21,14 @@ public class Subprogram : NonTerminatedSyntaxNode
|
||||||
{
|
{
|
||||||
return new Subprogram { Children = children };
|
return new Subprogram { Children = children };
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public override void GenerateCCode(CCodeBuilder builder)
|
||||||
|
{
|
||||||
|
//子函数头
|
||||||
|
Head.GenerateCCode(builder);
|
||||||
|
//子函数体
|
||||||
|
builder.AddString("{");
|
||||||
|
Body.GenerateCCode(builder);
|
||||||
|
builder.AddString("}");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,4 +1,5 @@
|
||||||
using Canon.Core.Enums;
|
using Canon.Core.CodeGenerators;
|
||||||
|
using Canon.Core.Enums;
|
||||||
|
|
||||||
namespace Canon.Core.SyntaxNodes;
|
namespace Canon.Core.SyntaxNodes;
|
||||||
|
|
||||||
|
@ -25,4 +26,11 @@ public class SubprogramBody : NonTerminatedSyntaxNode
|
||||||
{
|
{
|
||||||
return new SubprogramBody() { Children = children };
|
return new SubprogramBody() { Children = children };
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public override void GenerateCCode(CCodeBuilder builder)
|
||||||
|
{
|
||||||
|
ConstDeclarations.GenerateCCode(builder);
|
||||||
|
VarDeclarations.GenerateCCode(builder);
|
||||||
|
CompoundStatement.GenerateCCode(builder);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,4 +1,5 @@
|
||||||
using Canon.Core.Enums;
|
using Canon.Core.CodeGenerators;
|
||||||
|
using Canon.Core.Enums;
|
||||||
|
|
||||||
namespace Canon.Core.SyntaxNodes;
|
namespace Canon.Core.SyntaxNodes;
|
||||||
|
|
||||||
|
@ -31,4 +32,12 @@ public class SubprogramDeclarations : NonTerminatedSyntaxNode
|
||||||
declarations = declarations.Children[0].Convert<SubprogramDeclarations>();
|
declarations = declarations.Children[0].Convert<SubprogramDeclarations>();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public override void GenerateCCode(CCodeBuilder builder)
|
||||||
|
{
|
||||||
|
foreach (var subprogram in Subprograms)
|
||||||
|
{
|
||||||
|
subprogram.GenerateCCode(builder);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,4 +1,5 @@
|
||||||
using Canon.Core.Enums;
|
using Canon.Core.CodeGenerators;
|
||||||
|
using Canon.Core.Enums;
|
||||||
using Canon.Core.LexicalParser;
|
using Canon.Core.LexicalParser;
|
||||||
|
|
||||||
namespace Canon.Core.SyntaxNodes;
|
namespace Canon.Core.SyntaxNodes;
|
||||||
|
@ -42,4 +43,28 @@ public class SubprogramHead : NonTerminatedSyntaxNode
|
||||||
|
|
||||||
return new SubprogramHead { Children = children, IsProcedure = isProcedure };
|
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(")");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,4 +1,5 @@
|
||||||
using Canon.Core.Enums;
|
using Canon.Core.CodeGenerators;
|
||||||
|
using Canon.Core.Enums;
|
||||||
|
|
||||||
namespace Canon.Core.SyntaxNodes;
|
namespace Canon.Core.SyntaxNodes;
|
||||||
|
|
||||||
|
@ -10,4 +11,12 @@ public class Term : NonTerminatedSyntaxNode
|
||||||
{
|
{
|
||||||
return new Term { Children = children };
|
return new Term { Children = children };
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public override void GenerateCCode(CCodeBuilder builder)
|
||||||
|
{
|
||||||
|
foreach (var child in Children)
|
||||||
|
{
|
||||||
|
child.GenerateCCode(builder);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,4 +1,5 @@
|
||||||
using Canon.Core.Enums;
|
using Canon.Core.CodeGenerators;
|
||||||
|
using Canon.Core.Enums;
|
||||||
|
|
||||||
namespace Canon.Core.SyntaxNodes;
|
namespace Canon.Core.SyntaxNodes;
|
||||||
|
|
||||||
|
@ -10,4 +11,18 @@ public class TypeSyntaxNode : NonTerminatedSyntaxNode
|
||||||
{
|
{
|
||||||
return new TypeSyntaxNode { Children = children };
|
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
|
||||||
|
{
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,4 +1,5 @@
|
||||||
using Canon.Core.Enums;
|
using Canon.Core.CodeGenerators;
|
||||||
|
using Canon.Core.Enums;
|
||||||
|
|
||||||
namespace Canon.Core.SyntaxNodes;
|
namespace Canon.Core.SyntaxNodes;
|
||||||
|
|
||||||
|
@ -20,4 +21,10 @@ public class ValueParameter : NonTerminatedSyntaxNode
|
||||||
{
|
{
|
||||||
return new ValueParameter { Children = children };
|
return new ValueParameter { Children = children };
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public override void GenerateCCode(CCodeBuilder builder)
|
||||||
|
{
|
||||||
|
//可能涉及符号表访问
|
||||||
|
builder.AddString("valueParam ");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,4 +1,6 @@
|
||||||
using Canon.Core.Enums;
|
using Canon.Core.CodeGenerators;
|
||||||
|
using Canon.Core.Enums;
|
||||||
|
using Canon.Core.SemanticParser;
|
||||||
|
|
||||||
namespace Canon.Core.SyntaxNodes;
|
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
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,4 +1,5 @@
|
||||||
using Canon.Core.Enums;
|
using Canon.Core.CodeGenerators;
|
||||||
|
using Canon.Core.Enums;
|
||||||
|
|
||||||
namespace Canon.Core.SyntaxNodes;
|
namespace Canon.Core.SyntaxNodes;
|
||||||
|
|
||||||
|
@ -12,4 +13,9 @@ public class VarParameter : NonTerminatedSyntaxNode
|
||||||
{
|
{
|
||||||
return new VarParameter { Children = children };
|
return new VarParameter { Children = children };
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public override void GenerateCCode(CCodeBuilder builder)
|
||||||
|
{
|
||||||
|
ValueParameter.GenerateCCode(builder);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,5 +1,7 @@
|
||||||
using Canon.Core.Enums;
|
using Canon.Core.CodeGenerators;
|
||||||
|
using Canon.Core.Enums;
|
||||||
using Canon.Core.LexicalParser;
|
using Canon.Core.LexicalParser;
|
||||||
|
using Canon.Core.SemanticParser;
|
||||||
|
|
||||||
namespace Canon.Core.SyntaxNodes;
|
namespace Canon.Core.SyntaxNodes;
|
||||||
|
|
||||||
|
@ -17,4 +19,44 @@ public class Variable : NonTerminatedSyntaxNode
|
||||||
{
|
{
|
||||||
return new Variable { Children = children };
|
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
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -4,6 +4,7 @@ using Canon.Core.LexicalParser;
|
||||||
using Canon.Core.SyntaxNodes;
|
using Canon.Core.SyntaxNodes;
|
||||||
using Canon.Tests.GeneratedParserTests;
|
using Canon.Tests.GeneratedParserTests;
|
||||||
using Canon.Tests.Utils;
|
using Canon.Tests.Utils;
|
||||||
|
using Xunit.Abstractions;
|
||||||
|
|
||||||
namespace Canon.Tests.CCodeGeneratorTests;
|
namespace Canon.Tests.CCodeGeneratorTests;
|
||||||
|
|
||||||
|
@ -11,6 +12,12 @@ public class BasicTests
|
||||||
{
|
{
|
||||||
private readonly IGrammarParser _parser = GeneratedGrammarParser.Instance;
|
private readonly IGrammarParser _parser = GeneratedGrammarParser.Instance;
|
||||||
private readonly ILexer _lexer = new Lexer();
|
private readonly ILexer _lexer = new Lexer();
|
||||||
|
private readonly ITestOutputHelper _outputHelper;
|
||||||
|
|
||||||
|
public BasicTests(ITestOutputHelper outputHelper)
|
||||||
|
{
|
||||||
|
_outputHelper = outputHelper;
|
||||||
|
}
|
||||||
|
|
||||||
[Fact]
|
[Fact]
|
||||||
public void ProgramStructTest()
|
public void ProgramStructTest()
|
||||||
|
@ -28,6 +35,8 @@ public class BasicTests
|
||||||
ProgramStruct root = _parser.Analyse(tokens);
|
ProgramStruct root = _parser.Analyse(tokens);
|
||||||
root.GenerateCCode(builder);
|
root.GenerateCCode(builder);
|
||||||
|
|
||||||
Assert.Equal("#include <PascalCoreLib.h>", builder.Build());
|
string result = builder.Build();
|
||||||
|
_outputHelper.WriteLine(result);
|
||||||
|
Assert.Equal("#include <PascalCoreLib.h> int main(){statement; return 0;}", result);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
90
Canon.Tests/CCodeGeneratorTests/DeclarationsTests.cs
Normal file
90
Canon.Tests/CCodeGeneratorTests/DeclarationsTests.cs
Normal file
|
@ -0,0 +1,90 @@
|
||||||
|
using Canon.Core.Abstractions;
|
||||||
|
using Canon.Core.CodeGenerators;
|
||||||
|
using Canon.Core.LexicalParser;
|
||||||
|
using Canon.Core.SyntaxNodes;
|
||||||
|
using Canon.Tests.GeneratedParserTests;
|
||||||
|
using Canon.Tests.Utils;
|
||||||
|
using Xunit.Abstractions;
|
||||||
|
|
||||||
|
namespace Canon.Tests.CCodeGeneratorTests;
|
||||||
|
|
||||||
|
public class DeclarationsTest
|
||||||
|
{
|
||||||
|
private readonly IGrammarParser _parser = GeneratedGrammarParser.Instance;
|
||||||
|
private readonly ILexer _lexer = new Lexer();
|
||||||
|
private readonly ITestOutputHelper _outputHelper;
|
||||||
|
|
||||||
|
public DeclarationsTest(ITestOutputHelper outputHelper)
|
||||||
|
{
|
||||||
|
_outputHelper = outputHelper;
|
||||||
|
}
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public void VarDeclarationsTest()
|
||||||
|
{
|
||||||
|
CCodeBuilder builder = new();
|
||||||
|
|
||||||
|
const string program = """
|
||||||
|
program varTest;
|
||||||
|
var a, b, c, d: integer; m, n: real; k: boolean;
|
||||||
|
begin
|
||||||
|
end.
|
||||||
|
""";
|
||||||
|
|
||||||
|
IEnumerable<SemanticToken> tokens = _lexer.Tokenize(new StringSourceReader(program));
|
||||||
|
|
||||||
|
ProgramStruct root = _parser.Analyse(tokens);
|
||||||
|
root.GenerateCCode(builder);
|
||||||
|
|
||||||
|
string result = builder.Build();
|
||||||
|
_outputHelper.WriteLine(result);
|
||||||
|
Assert.Equal("#include <PascalCoreLib.h> char a; int main(){statement; return 0; }", result);
|
||||||
|
}
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public void ConstDeclarationsTest()
|
||||||
|
{
|
||||||
|
CCodeBuilder builder = new();
|
||||||
|
|
||||||
|
const string program = """
|
||||||
|
program varTest;
|
||||||
|
const a = 1; b = 2; c = 3; d = 2.5;
|
||||||
|
begin
|
||||||
|
end.
|
||||||
|
""";
|
||||||
|
|
||||||
|
IEnumerable<SemanticToken> tokens = _lexer.Tokenize(new StringSourceReader(program));
|
||||||
|
|
||||||
|
ProgramStruct root = _parser.Analyse(tokens);
|
||||||
|
root.GenerateCCode(builder);
|
||||||
|
|
||||||
|
string result = builder.Build();
|
||||||
|
_outputHelper.WriteLine(result);
|
||||||
|
Assert.Equal("#include <PascalCoreLib.h> int main(){statement; return 0; }", result);
|
||||||
|
}
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public void ArrayDeclarationsTest()
|
||||||
|
{
|
||||||
|
CCodeBuilder builder = new();
|
||||||
|
|
||||||
|
const string program = """
|
||||||
|
program arrayTest;
|
||||||
|
var a, b, c: array[1..6,5..8] of integer;
|
||||||
|
d: integer;
|
||||||
|
begin
|
||||||
|
a[2,3] := 10086;
|
||||||
|
d:=6;
|
||||||
|
end.
|
||||||
|
""";
|
||||||
|
|
||||||
|
IEnumerable<SemanticToken> tokens = _lexer.Tokenize(new StringSourceReader(program));
|
||||||
|
|
||||||
|
ProgramStruct root = _parser.Analyse(tokens);
|
||||||
|
root.GenerateCCode(builder);
|
||||||
|
|
||||||
|
string result = builder.Build();
|
||||||
|
_outputHelper.WriteLine(result);
|
||||||
|
Assert.Equal("#include <PascalCoreLib.h> int main(){statement; return 0; }", result);
|
||||||
|
}
|
||||||
|
}
|
47
Canon.Tests/CCodeGeneratorTests/ExpressionTests.cs
Normal file
47
Canon.Tests/CCodeGeneratorTests/ExpressionTests.cs
Normal file
|
@ -0,0 +1,47 @@
|
||||||
|
using Canon.Core.Abstractions;
|
||||||
|
using Canon.Core.CodeGenerators;
|
||||||
|
using Canon.Core.LexicalParser;
|
||||||
|
using Canon.Core.SyntaxNodes;
|
||||||
|
using Canon.Tests.GeneratedParserTests;
|
||||||
|
using Canon.Tests.Utils;
|
||||||
|
using Xunit.Abstractions;
|
||||||
|
|
||||||
|
namespace Canon.Tests.CCodeGeneratorTests;
|
||||||
|
|
||||||
|
public class ExpressionTests
|
||||||
|
{
|
||||||
|
private readonly IGrammarParser _parser = GeneratedGrammarParser.Instance;
|
||||||
|
private readonly ILexer _lexer = new Lexer();
|
||||||
|
private readonly ITestOutputHelper _outputHelper;
|
||||||
|
|
||||||
|
public ExpressionTests(ITestOutputHelper outputHelper)
|
||||||
|
{
|
||||||
|
_outputHelper = outputHelper;
|
||||||
|
}
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public void ExpressionTest1()
|
||||||
|
{
|
||||||
|
CCodeBuilder builder = new();
|
||||||
|
|
||||||
|
const string program = """
|
||||||
|
program varTest;
|
||||||
|
var a, b, c, d: integer; m, n: real; k: boolean;
|
||||||
|
begin
|
||||||
|
a := 1;
|
||||||
|
b := a + 6 * 9 + (a + 9) * 1 - (4 + a) * 5 / 1;
|
||||||
|
m := b / 3;
|
||||||
|
d := 9 mod 1;
|
||||||
|
end.
|
||||||
|
""";
|
||||||
|
|
||||||
|
IEnumerable<SemanticToken> tokens = _lexer.Tokenize(new StringSourceReader(program));
|
||||||
|
|
||||||
|
ProgramStruct root = _parser.Analyse(tokens);
|
||||||
|
root.GenerateCCode(builder);
|
||||||
|
|
||||||
|
string result = builder.Build();
|
||||||
|
_outputHelper.WriteLine(result);
|
||||||
|
Assert.Equal("#include <PascalCoreLib.h> char a; int main(){statement; return 0; }", result);
|
||||||
|
}
|
||||||
|
}
|
111
Canon.Tests/CCodeGeneratorTests/StatementTests.cs
Normal file
111
Canon.Tests/CCodeGeneratorTests/StatementTests.cs
Normal file
|
@ -0,0 +1,111 @@
|
||||||
|
using Canon.Core.Abstractions;
|
||||||
|
using Canon.Core.CodeGenerators;
|
||||||
|
using Canon.Core.LexicalParser;
|
||||||
|
using Canon.Core.SyntaxNodes;
|
||||||
|
using Canon.Tests.GeneratedParserTests;
|
||||||
|
using Canon.Tests.Utils;
|
||||||
|
using Xunit.Abstractions;
|
||||||
|
|
||||||
|
namespace Canon.Tests.CCodeGeneratorTests;
|
||||||
|
|
||||||
|
public class StatementTests
|
||||||
|
{
|
||||||
|
private readonly IGrammarParser _parser = GeneratedGrammarParser.Instance;
|
||||||
|
private readonly ILexer _lexer = new Lexer();
|
||||||
|
private readonly ITestOutputHelper _outputHelper;
|
||||||
|
|
||||||
|
public StatementTests(ITestOutputHelper outputHelper)
|
||||||
|
{
|
||||||
|
_outputHelper = outputHelper;
|
||||||
|
}
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public void VariableAssignTest()
|
||||||
|
{
|
||||||
|
CCodeBuilder builder = new();
|
||||||
|
|
||||||
|
const string program = """
|
||||||
|
program varAssignTest;
|
||||||
|
var a, b: integer;
|
||||||
|
begin
|
||||||
|
a := 1;
|
||||||
|
b := a;
|
||||||
|
a := b;
|
||||||
|
end.
|
||||||
|
""";
|
||||||
|
|
||||||
|
IEnumerable<SemanticToken> tokens = _lexer.Tokenize(new StringSourceReader(program));
|
||||||
|
|
||||||
|
ProgramStruct root = _parser.Analyse(tokens);
|
||||||
|
root.GenerateCCode(builder);
|
||||||
|
|
||||||
|
string result = builder.Build();
|
||||||
|
_outputHelper.WriteLine(result);
|
||||||
|
Assert.Equal("#include <PascalCoreLib.h> #include <stdbool.h> " +
|
||||||
|
"int a, b; int main(){ a = 1; b = a; a = b; return 0;}", result);
|
||||||
|
}
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public void IfTest()
|
||||||
|
{
|
||||||
|
CCodeBuilder builder = new();
|
||||||
|
|
||||||
|
const string program = """
|
||||||
|
program main;
|
||||||
|
var
|
||||||
|
a,b:integer;
|
||||||
|
begin
|
||||||
|
if a = 5 then
|
||||||
|
begin
|
||||||
|
if b = 3 then
|
||||||
|
b := b + 1
|
||||||
|
else
|
||||||
|
b := b + 2
|
||||||
|
end
|
||||||
|
else
|
||||||
|
a := 2
|
||||||
|
end.
|
||||||
|
|
||||||
|
""";
|
||||||
|
|
||||||
|
IEnumerable<SemanticToken> tokens = _lexer.Tokenize(new StringSourceReader(program));
|
||||||
|
|
||||||
|
ProgramStruct root = _parser.Analyse(tokens);
|
||||||
|
root.GenerateCCode(builder);
|
||||||
|
|
||||||
|
string result = builder.Build();
|
||||||
|
_outputHelper.WriteLine(result);
|
||||||
|
Assert.Equal("#include <PascalCoreLib.h> #include <stdbool.h> int a, b; " +
|
||||||
|
"int main(){ a = 1; if( a == 1){ a = a + 1; } else{ b = a + 2 }; return 0;}", result);
|
||||||
|
}
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public void ForLoopTest()
|
||||||
|
{
|
||||||
|
CCodeBuilder builder = new();
|
||||||
|
|
||||||
|
const string program = """
|
||||||
|
program ForLoopTest;
|
||||||
|
var a, b, c: integer;
|
||||||
|
begin
|
||||||
|
b := 1;
|
||||||
|
for a := b * 5 + 1 to 99 do
|
||||||
|
begin
|
||||||
|
c := a + 1;
|
||||||
|
b := a mod (a + c);
|
||||||
|
b := a + 1 - 1 * 1;
|
||||||
|
end;
|
||||||
|
end.
|
||||||
|
""";
|
||||||
|
|
||||||
|
IEnumerable<SemanticToken> tokens = _lexer.Tokenize(new StringSourceReader(program));
|
||||||
|
|
||||||
|
ProgramStruct root = _parser.Analyse(tokens);
|
||||||
|
root.GenerateCCode(builder);
|
||||||
|
|
||||||
|
string result = builder.Build();
|
||||||
|
_outputHelper.WriteLine(result);
|
||||||
|
Assert.Equal("#include <PascalCoreLib.h> #include <stdbool.h> int a, b; " +
|
||||||
|
"int main(){ a = 1; if( a == 1){ a = a + 1; } else{ b = a + 2 }; return 0;}", result);
|
||||||
|
}
|
||||||
|
}
|
Loading…
Reference in New Issue
Block a user