graphviz and ui
This commit is contained in:
parent
1ce8f94be6
commit
c7f8a7c30b
3 changed files with 162 additions and 7 deletions
|
@ -1,26 +1,86 @@
|
|||
import androidx.compose.desktop.ui.tooling.preview.Preview
|
||||
import androidx.compose.foundation.layout.Arrangement
|
||||
import androidx.compose.foundation.layout.Column
|
||||
import androidx.compose.foundation.layout.Row
|
||||
import androidx.compose.foundation.layout.fillMaxHeight
|
||||
import androidx.compose.foundation.layout.fillMaxSize
|
||||
import androidx.compose.foundation.layout.fillMaxWidth
|
||||
import androidx.compose.foundation.layout.padding
|
||||
import androidx.compose.material.Button
|
||||
import androidx.compose.material.ButtonColors
|
||||
import androidx.compose.material.MaterialTheme
|
||||
import androidx.compose.material.Text
|
||||
import androidx.compose.material.TextField
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.runtime.getValue
|
||||
import androidx.compose.runtime.mutableStateOf
|
||||
import androidx.compose.runtime.remember
|
||||
import androidx.compose.runtime.setValue
|
||||
import androidx.compose.ui.Alignment
|
||||
import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.text.ExperimentalTextApi
|
||||
import androidx.compose.ui.text.TextStyle
|
||||
import androidx.compose.ui.text.font.FontFamily
|
||||
import androidx.compose.ui.unit.dp
|
||||
import androidx.compose.ui.window.Window
|
||||
import androidx.compose.ui.window.application
|
||||
import core.SourceFile
|
||||
|
||||
@OptIn(ExperimentalTextApi::class)
|
||||
@Composable
|
||||
@Preview
|
||||
fun App() {
|
||||
var text by remember { mutableStateOf("Hello, World!") }
|
||||
var text by remember { mutableStateOf("") }
|
||||
var isReady by remember { mutableStateOf(false) }
|
||||
var source: SourceFile? = null
|
||||
|
||||
MaterialTheme {
|
||||
Button(onClick = {
|
||||
text = "Hello, Desktop!"
|
||||
}) {
|
||||
Text(text)
|
||||
Column(
|
||||
modifier = Modifier.fillMaxSize()
|
||||
.padding(horizontal = 10.dp, vertical = 5.dp),
|
||||
horizontalAlignment = Alignment.Start,
|
||||
verticalArrangement = Arrangement.Center
|
||||
) {
|
||||
Text("请输入您的代码")
|
||||
|
||||
TextField(
|
||||
value = text,
|
||||
onValueChange = { text = it },
|
||||
modifier = Modifier.fillMaxWidth(0.95f)
|
||||
.weight(1f),
|
||||
textStyle = TextStyle.Default.copy(fontFamily = FontFamily("monospace"))
|
||||
)
|
||||
|
||||
Row(
|
||||
modifier = Modifier.fillMaxWidth(0.9f)
|
||||
.padding(vertical = 5.dp),
|
||||
horizontalArrangement = Arrangement.SpaceEvenly,
|
||||
verticalAlignment = Alignment.CenterVertically
|
||||
) {
|
||||
Button(
|
||||
modifier = Modifier.padding(vertical = 10.dp),
|
||||
onClick = {
|
||||
val s = SourceFile(text.toString())
|
||||
text = s.content
|
||||
source = s
|
||||
},
|
||||
) {
|
||||
Text("格式化")
|
||||
}
|
||||
|
||||
Button(
|
||||
modifier = Modifier.padding(vertical = 10.dp),
|
||||
onClick = {
|
||||
source = SourceFile(text.toString())
|
||||
isReady = true
|
||||
},
|
||||
enabled = !isReady
|
||||
) {
|
||||
Text("分析")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
|
|
91
src/main/kotlin/core/GraphvizHelper.kt
Normal file
91
src/main/kotlin/core/GraphvizHelper.kt
Normal file
|
@ -0,0 +1,91 @@
|
|||
package core
|
||||
|
||||
data class Relation(val from: String, val to: String)
|
||||
|
||||
fun generateGraph(relations: Map<String, List<Relation>>, crossLabelPaths: List<String>? = null): String {
|
||||
val sb = StringBuilder()
|
||||
sb.append("digraph G {\n")
|
||||
|
||||
for ((label, edges) in relations) {
|
||||
sb.append(" subgraph cluster_$label {\n")
|
||||
sb.append(" label = \"$label\";\n")
|
||||
|
||||
val uniquePaths = mutableSetOf<String>()
|
||||
|
||||
for (relation in edges) {
|
||||
uniquePaths.add("${relation.from} -> ${relation.to}")
|
||||
sb.append(" ${relation.from} -> ${relation.to};\n")
|
||||
}
|
||||
|
||||
sb.append(" }\n")
|
||||
}
|
||||
|
||||
if (crossLabelPaths != null) {
|
||||
// 处理跨函数
|
||||
for (path in crossLabelPaths) {
|
||||
val parts = path.split(":")
|
||||
if (parts.size == 2) {
|
||||
val subPath = parts[1].split("->") // 栗子: main:z->a->m
|
||||
if (subPath.size >= 2) {
|
||||
val fromNode = subPath[0] // 这里就是z
|
||||
val toNode = subPath[1] // 下一个就是
|
||||
// from 到 to 用虚线
|
||||
sb.append(" $fromNode -> $toNode [style=dashed];\n")
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
sb.append("}\n")
|
||||
return sb.toString()
|
||||
}
|
||||
|
||||
|
||||
fun parseRelation(funcName: String, parse: String): Map<String, List<Relation>>{
|
||||
val list = mutableListOf<Relation>()
|
||||
val added = mutableListOf<Int>()
|
||||
parse.split('\n').forEach { line ->
|
||||
val split = line.split("->")
|
||||
if (split.size < 2){
|
||||
return@forEach
|
||||
}
|
||||
for (i in 0..<split.lastIndex){
|
||||
val hash = "${split[i]}->${split[i+1]}".hashCode()
|
||||
if (hash !in added){
|
||||
list.add(Relation(split[i],split[i+1]))
|
||||
added.add(hash)
|
||||
}
|
||||
}
|
||||
}
|
||||
return mapOf(
|
||||
funcName to list
|
||||
)
|
||||
}
|
||||
|
||||
fun List<CFunction>.getInvokeGraph(funcName: String): String {
|
||||
val relations = mutableMapOf<String, List<Relation>>()
|
||||
val func = this.find(funcName) ?: return ""
|
||||
|
||||
this.forEach {
|
||||
relations.putAll(parseRelation(it.name,it.getTraceTree().getStringRepr()))
|
||||
}
|
||||
|
||||
val crossLabelPaths = this.getInvokeTree(func.name).getFuncRepr(func.name)
|
||||
return generateGraph(relations,crossLabelPaths.split('\n'))
|
||||
}
|
||||
|
||||
fun main() {
|
||||
val relations = mapOf(
|
||||
"main" to listOf(
|
||||
Relation("x", "y"),
|
||||
Relation("z", "x"),
|
||||
Relation("c", "d")
|
||||
),
|
||||
"A" to listOf(
|
||||
Relation("a", "m")
|
||||
)
|
||||
)
|
||||
|
||||
val graphCode = generateGraph(relations)
|
||||
println(graphCode)
|
||||
}
|
|
@ -4,6 +4,7 @@ package core
|
|||
|
||||
import java.io.File
|
||||
import core.CLanguage.Companion.OPERATION.*
|
||||
|
||||
class SourceFile {
|
||||
companion object {
|
||||
val function_define_regex = """\b([a-zA-Z_][a-zA-Z0-9_]*)\s*\([^)]*\)\s*\{""".toRegex() // main(){ 匹配函数名
|
||||
|
@ -18,7 +19,7 @@ class SourceFile {
|
|||
}
|
||||
}
|
||||
|
||||
private val content: String
|
||||
val content: String
|
||||
private var functions: List<CFunction> = emptyList()
|
||||
|
||||
constructor(file: File) {
|
||||
|
@ -105,15 +106,18 @@ class SourceFile {
|
|||
fun main() {
|
||||
val sourceFile = SourceFile(File("/home/kagura/repo/VariableRelation/src/main/CTests/test.c"))
|
||||
val funcs = sourceFile.parseFunction()
|
||||
val relations = mutableMapOf<String, List<Relation>>()
|
||||
funcs.forEach {
|
||||
println("${it.name}(${it.params}) -> ${it.returnType} {\n${it.content}\n} ")
|
||||
it.cParser.sentenceList.forEach{ s->
|
||||
println("${s.left},${s.right},${s.type}")
|
||||
}
|
||||
println(it.getTraceTree().getStringRepr())
|
||||
relations.putAll(parseRelation(it.name,it.getTraceTree().getStringRepr()))
|
||||
}
|
||||
println(funcs.getInvokeTree("main").getFuncRepr("main"))
|
||||
|
||||
println(sourceFile.getDef())
|
||||
println(sourceFile.getUse())
|
||||
println(generateGraph(relations))
|
||||
println(funcs.getInvokeGraph("main"))
|
||||
}
|
Loading…
Reference in a new issue