Skip to content

Commit

Permalink
feat(c): add first function call demos #96
Browse files Browse the repository at this point in the history
  • Loading branch information
phodal committed Jan 6, 2024
1 parent 69e3149 commit fa10d9a
Show file tree
Hide file tree
Showing 3 changed files with 84 additions and 7 deletions.
16 changes: 9 additions & 7 deletions chapi-ast-c/src/main/antlr/C.g4
Original file line number Diff line number Diff line change
Expand Up @@ -69,15 +69,17 @@ genericAssociation
;

postfixExpression
: (primaryExpression | '__extension__'? '(' typeName ')' '{' initializerList ','? '}') (
'[' expression ']'
| '(' argumentExpressionList? ')'
| ('.' | '->') Identifier
| '++'
| '--'
)*
: (primaryExpression | extensionExpression) (postixCall | '++' | '--')*
;

extensionExpression : '__extension__'? '(' typeName ')' '{' initializerList ','? '}' ;

postixCall
:'[' expression ']' #arrayAccessPostfixExpression
| '(' argumentExpressionList? ')' #functionCallPostfixExpression
| ('.' | '->') Identifier #memberAccessPostfixExpression
;

argumentExpressionList
: assignmentExpression (',' assignmentExpression)*
;
Expand Down
41 changes: 41 additions & 0 deletions chapi-ast-c/src/main/kotlin/chapi/ast/cast/CFullIdentListener.kt
Original file line number Diff line number Diff line change
Expand Up @@ -189,6 +189,47 @@ open class CFullIdentListener(fileName: String) : CAstBaseListener() {

}

override fun enterPostfixExpression(ctx: CParser.PostfixExpressionContext?) {
val call = ctx?.postixCall() ?: return
val functionName = ctx.primaryExpression()?.Identifier()?.text ?: return

val children = call.firstOrNull()?.children ?: return
// function call children should be '(', some parameters?, ')', so the size should be at least 2
if (children.size < 2) return

val codeCall = CodeCall(
FunctionName = functionName,
Parameters = buildParameters(call),
Position = buildPosition(ctx)
)

currentFunction.FunctionCalls += codeCall
}

private fun buildParameters(call: List<CParser.PostixCallContext>): List<CodeProperty> {
return call.mapNotNull { callContext ->
when(callContext) {
is CParser.ArrayAccessPostfixExpressionContext -> {
null
}
is CParser.FunctionCallPostfixExpressionContext -> {
callContext.argumentExpressionList()?.assignmentExpression()?.map {
CodeProperty(
TypeType = it.text,
TypeValue = it.text
)
}?.toList() ?: listOf()
}

is CParser.MemberAccessPostfixExpressionContext -> {
null
}

else -> null
}
}.flatten()
}

fun getNodeInfo(): CodeContainer {
if (defaultDataStruct.Functions.isNotEmpty()) {
codeContainer.DataStructures += defaultDataStruct
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -196,4 +196,38 @@ typedef struct {
assertEquals(elementDs.Fields[1].TypeType, "struct element")
assertEquals(elementDs.Fields[1].TypeValue, "")
}

@Test
fun shouldIdentifyFirstFunctionCall() {
val code = """
void aX(void);
int a1(int param1);
int a2(int param1, param2);
void a3();
void a3(void);
int f(int arg1, char arg2)
{
a1(arg1);
a2(arg1, arg2);
a3();
}
""".trimIndent()

val codeFile = CAnalyser().analysis(code, "helloworld.c")
assertEquals(codeFile.DataStructures.size, 1)
assertEquals(codeFile.DataStructures[0].Functions.size, 1)
val functionCalls = codeFile.DataStructures[0].Functions[0].FunctionCalls
assertEquals(functionCalls.size, 3)
assertEquals(functionCalls[0].FunctionName, "a1")
assertEquals(functionCalls[0].Parameters[0].TypeValue, "arg1")

assertEquals(functionCalls[1].FunctionName, "a2")
assertEquals(functionCalls[1].Parameters[0].TypeValue, "arg1")
assertEquals(functionCalls[1].Parameters[1].TypeValue, "arg2")

assertEquals(functionCalls[2].FunctionName, "a3")
assertEquals(functionCalls[2].Parameters.size, 0)
}
}

0 comments on commit fa10d9a

Please sign in to comment.