From 201ec4375413fbabccf476b8ec6277fe44e6fd7e Mon Sep 17 00:00:00 2001 From: morpheuschoo Date: Mon, 12 May 2025 02:47:48 +0800 Subject: [PATCH] feat: added static type casting --- .../parser/c-ast/expression/unaryExpression.ts | 13 ++++++++++--- ctowasm/src/parser/peggyjs/parser.pegjs | 18 +++++++++++++++++- ctowasm/src/processor/processExpression.ts | 18 ++++++++++++++++++ ctowasm/src/translator/translateExpression.ts | 8 ++++++++ 4 files changed, 53 insertions(+), 4 deletions(-) diff --git a/ctowasm/src/parser/c-ast/expression/unaryExpression.ts b/ctowasm/src/parser/c-ast/expression/unaryExpression.ts index 1e08529..e8d2428 100644 --- a/ctowasm/src/parser/c-ast/expression/unaryExpression.ts +++ b/ctowasm/src/parser/c-ast/expression/unaryExpression.ts @@ -2,9 +2,9 @@ * Definition for unary expression nodes. */ -import { PostfixOperator, PrefixOperator } from "~src/common/types"; +import { PostfixOperator, PrefixOperator, ScalarCDataType } from "~src/common/types"; import { CNodeBase, Expression } from "~src/parser/c-ast/core"; -import { DataType } from "~src/parser/c-ast/dataTypes"; +import { DataType, PrimaryDataType } from "~src/parser/c-ast/dataTypes"; type UnaryExpression = | PostfixExpression @@ -13,7 +13,8 @@ type UnaryExpression = | StructMemberAccess | PointerDereference | AddressOfExpression - | SizeOfExpression; + | SizeOfExpression + | TypeCastingExpression; export default UnaryExpression; // All unary expressions should inherit this (like function calls) @@ -27,6 +28,12 @@ export interface PostfixExpression extends UnaryExpressionBase { operator: PostfixOperator; } +export interface TypeCastingExpression extends UnaryExpressionBase { + type: "TypeCastingExpression"; + expr: Expression; + targetDataType: PrimaryDataType; +} + export interface PrefixExpression extends UnaryExpressionBase { type: "PrefixExpression"; operator: PrefixOperator; diff --git a/ctowasm/src/parser/peggyjs/parser.pegjs b/ctowasm/src/parser/peggyjs/parser.pegjs index 96fbe72..40c7186 100644 --- a/ctowasm/src/parser/peggyjs/parser.pegjs +++ b/ctowasm/src/parser/peggyjs/parser.pegjs @@ -18,6 +18,21 @@ /** * Helper function to create and return a Node with position and type information */ + function createTypeCastNode(type, expr) { + // Perform type checking for the cast + if (type.primaryDataType === "void") { + error("Cannot cast to void type"); + } + if (expr.type === "StructMemberAccess" || expr.type === "StructPointerMemberAccess") { + error("Cannot cast struct or struct pointer types"); + } + + return generateNode("TypeCastingExpression", { + expr: expr, + targetDataType: type, + }); + } + function generateNode(type, data) { return { type: type, @@ -1938,7 +1953,8 @@ multiply_divide_expression / unary_expression // as the last binary expression (highest precedence), this rule is needed unary_expression - = operations:(@prefix_operation _)+ firstExpr:postfix_expression { return createPrefixExpressionNode(firstExpr, operations); } + = "(" _ type:type_name _ ")" _ expr:unary_expression { return createTypeCastNode(type, expr); } + / operations:(@prefix_operation _)+ firstExpr:postfix_expression { return createPrefixExpressionNode(firstExpr, operations); } / postfix_expression prefix_operation diff --git a/ctowasm/src/processor/processExpression.ts b/ctowasm/src/processor/processExpression.ts index cdaf706..36c94b5 100644 --- a/ctowasm/src/processor/processExpression.ts +++ b/ctowasm/src/processor/processExpression.ts @@ -270,6 +270,24 @@ export default function processExpression( ...returnObjectMemoryLoads.slice(1), ], }; + } else if (expr.type === "TypeCastingExpression") { + // type casting is just a way to tell the compiler to treat an expression as another type + // no actual conversion is done here + const processedExpr = processExpression(expr.expr, symbolTable); + const targetDataType = expr.targetDataType; + + return { + originalDataType: targetDataType, + exprs: [ + { + type: "PreStatementExpression", + statements: [], + expr: processedExpr.exprs[0], + dataType: processedExpr.exprs[0].dataType, + }, + ...processedExpr.exprs.slice(1), + ], + }; } else if (expr.type === "PrefixExpression") { return processPrefixExpression(expr, symbolTable); } else if (expr.type === "PostfixExpression") { diff --git a/ctowasm/src/translator/translateExpression.ts b/ctowasm/src/translator/translateExpression.ts index a5bcab2..b15a7a1 100644 --- a/ctowasm/src/translator/translateExpression.ts +++ b/ctowasm/src/translator/translateExpression.ts @@ -42,6 +42,14 @@ export default function translateExpression( ) { return convertConstantToWasmConst(expr); } else if (expr.type === "PreStatementExpression") { + const translatedStatements = expr.statements.map((statement) => + translateStatement(statement, enclosingLoopDetails), + ); + const translatedExpr = translateExpression( + expr.expr, + expr.expr.dataType, + enclosingLoopDetails, + ); return { type: "PreStatementExpression", statements: expr.statements.map((statement) =>