Skip to content

Commit

Permalink
feat(c): add support for single line macro declaration #24
Browse files Browse the repository at this point in the history
Add support for single line macro declaration in the C grammar. This allows parsing and analyzing single line macros in C code.
  • Loading branch information
phodal committed Jan 31, 2024
1 parent 8b20ca2 commit 56c876f
Show file tree
Hide file tree
Showing 3 changed files with 55 additions and 14 deletions.
3 changes: 3 additions & 0 deletions chapi-ast-c/build.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,9 @@ dependencies {

implementation("org.antlr:antlr4:4.13.1")
implementation("org.antlr:antlr4-runtime:4.13.1")

// coroutines
testImplementation("org.jetbrains.kotlinx:kotlinx-coroutines-core:1.8.0-RC2")
}

sourceSets.main {
Expand Down
9 changes: 5 additions & 4 deletions chapi-ast-c/src/main/antlr/C.g4
Original file line number Diff line number Diff line change
Expand Up @@ -38,10 +38,6 @@ compilationUnit
: (externalDeclaration | statement)* EOF
;

macroKeywords
: 'if' | 'undef' | 'else' | 'pragma' | 'endif' | 'ifdef' | 'ifndef' | 'elif' | 'define'
;

MultiLineMacro
: '#' (~[\n]*? '\\' '\r'? '\n')+ ~ [\n]+ -> channel (HIDDEN)
;
Expand Down Expand Up @@ -268,6 +264,7 @@ structDeclarationList
structDeclaration // The first two rules have priority order and cannot be simplified to one expression.
: specifierQualifierList structDeclaratorList? ';'
| staticAssertDeclaration
| singleLineMacroDeclaration
;

specifierQualifierList
Expand Down Expand Up @@ -479,6 +476,10 @@ singleLineMacroDeclaration
| '#' '#'? Identifier #macroCastDeclaration
;

macroKeywords
: 'if' | 'undef' | 'else' | 'pragma' | 'endif' | 'ifdef' | 'ifndef' | 'elif' | 'define'
;

labeledStatement
: Identifier ':' statement?
| 'case' constantExpression ':' statement
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,9 @@
package chapi.ast.cast

import kotlinx.coroutines.flow.asFlow
import kotlinx.coroutines.flow.collect
import kotlinx.coroutines.flow.mapNotNull
import kotlinx.coroutines.runBlocking
import org.junit.jupiter.api.Test
import java.io.File
import kotlin.test.assertEquals
Expand All @@ -9,16 +13,20 @@ internal class CFullIdentListenerTest {
@Test
fun allGrammarUnderResources() {
val content = this::class.java.getResource("/grammar")!!.toURI()
// val content = "/Users/phodal/Downloads/redis-unstable/deps/jemalloc/src"
File(content).walkTopDown().forEach {
if (it.isFile && (it.extension == "c" || it.extension == "h")) {
val start = System.currentTimeMillis()
println("Analyse ${it.path}")
CAnalyser().analysis(it.readText(), it.name)
val end = System.currentTimeMillis()
val seconds = (end - start) / 1000
println("cost ${end - start}ms")
}
// val content = "/Users/phodal/Downloads/redis-unstable"
runBlocking {
File(content).walkTopDown().asFlow().mapNotNull {
if (it.isFile && (it.extension == "c" || it.extension == "h")) {
val start = System.currentTimeMillis()
println("Analyse ${it.path}")
val analysis = CAnalyser().analysis(it.readText(), it.name)
val end = System.currentTimeMillis()
println("cost ${end - start}ms")
analysis
} else {
null
}
}.collect()
}
}

Expand Down Expand Up @@ -550,4 +558,33 @@ typedef struct {
val codeFile = CAnalyser().analysis(code, "helloworld.c")
assertEquals(codeFile.DataStructures.size, 0)
}

@Test
fun shouldHandleMacroIArrayDefine() {
val code = """
static char log_filename[
#ifdef JEMALLOC_PROF
PATH_MAX +
#endif
1];
""".trimIndent()

val codeFile = CAnalyser().analysis(code, "helloworld.c")
assertEquals(codeFile.DataStructures.size, 0)
}

@Test
fun shouldEnableMacroInTypedefStruct() {
val code = """
typedef struct {
uint64_t ns;
#ifdef JEMALLOC_DEBUG
uint32_t magic; /* Tracks if initialized. */
#endif
} nstime_t;
""".trimIndent()

val codeFile = CAnalyser().analysis(code, "helloworld.c")
assertEquals(codeFile.DataStructures.size, 1)
}
}

0 comments on commit 56c876f

Please sign in to comment.