llcppsigfech:basic struct

llcppsigfetch:basic parse converter

llcppsigfetch:converter top decl

llcppg:converter test
This commit is contained in:
luoliwoshang
2024-08-08 15:59:08 +08:00
parent 9f8b9ea806
commit 33af9e878b
4 changed files with 242 additions and 1 deletions

View File

@@ -16,6 +16,65 @@
package main
import (
"fmt"
"io"
"os"
"path/filepath"
"strings"
"github.com/goplus/llgo/chore/_xtool/llcppsigfetch/parse"
"github.com/goplus/llgo/chore/_xtool/llcppsymg/config"
)
func main() {
// TODO(xsw): implement llcppsigfetch tool
cfgFile := "llcppg.cfg"
if len(os.Args) > 1 {
cfgFile = os.Args[1]
}
var data []byte
var err error
if cfgFile == "-" {
data, err = io.ReadAll(os.Stdin)
} else {
data, err = os.ReadFile(cfgFile)
}
check(err)
conf, err := config.GetConf(data)
check(err)
defer conf.Delete()
if err != nil {
fmt.Fprintln(os.Stderr, "Failed to parse config file:", cfgFile)
}
files := getHeaderFiles(conf.CFlags, conf.Include)
context := parse.NewContext()
err = context.ProcessFiles(files)
check(err)
outputInfo(context)
}
func check(err error) {
if err != nil {
panic(err)
}
}
func getHeaderFiles(cflags string, files []string) []string {
prefix := cflags
prefix = strings.TrimPrefix(prefix, "-I")
var paths []string
for _, f := range files {
paths = append(paths, filepath.Join(prefix, f))
}
return paths
}
func outputInfo(context *parse.Context) {
// TODO(zzy):
}

View File

@@ -0,0 +1,98 @@
package parse
import (
"errors"
"fmt"
"unsafe"
"github.com/goplus/llgo/c"
"github.com/goplus/llgo/c/clang"
"github.com/goplus/llgo/chore/llcppg/ast"
)
type Converter struct {
files map[string]*ast.File
typeMap map[clang.Type]*ast.Expr
declMap map[clang.Cursor]*ast.Decl
curLoc ast.Location
index *clang.Index
unit *clang.TranslationUnit
}
func NewConverter(filepath string) (*Converter, error) {
args := []*c.Char{
c.Str("-x"),
c.Str("c++"),
c.Str("-std=c++11"),
}
index := clang.CreateIndex(0, 0)
unit := index.ParseTranslationUnit(
c.AllocaCStr(filepath),
unsafe.SliceData(args), 3,
nil, 0,
clang.DetailedPreprocessingRecord,
)
if unit == nil {
return nil, errors.New("failed to parse translation unit")
}
return &Converter{
typeMap: make(map[clang.Type]*ast.Expr),
declMap: make(map[clang.Cursor]*ast.Decl),
files: make(map[string]*ast.File),
index: index,
unit: unit,
}, nil
}
func (ct *Converter) Dispose() {
ct.index.Dispose()
ct.unit.Dispose()
}
// visit top decls (struct,class,function,enum & marco,include)
func visit(cursor, parent clang.Cursor, clientData unsafe.Pointer) clang.ChildVisitResult {
ct := (*Converter)(clientData)
switch cursor.Kind {
case clang.CursorInclusionDirective:
fmt.Println("todo: Process include")
return clang.ChildVisit_Continue
case clang.CursorMacroDefinition:
fmt.Println("todo: Process macro")
return clang.ChildVisit_Continue
case clang.CursorEnumDecl:
fmt.Println("todo: Process enum")
return clang.ChildVisit_Continue
case clang.CursorClassDecl:
ct.ProcessClass(cursor)
return clang.ChildVisit_Continue
case clang.CursorStructDecl:
fmt.Println("todo: Process struct")
return clang.ChildVisit_Continue
case clang.CursorFunctionDecl:
ct.ProcessFunc(cursor)
return clang.ChildVisit_Continue
default:
// non-top-level decl, continue recursion
return clang.ChildVisit_Recurse
}
}
func (ct *Converter) ProcessFunc(cursor clang.Cursor) {
println("todo: Process func")
}
func (ct *Converter) ProcessClass(cursor clang.Cursor) {
println("todo: Process class")
}
func (ct *Converter) Convert() (map[string]*ast.File, error) {
cursor := ct.unit.Cursor()
// visit top decls (struct,class,function & marco,include)
clang.VisitChildren(cursor, visit, c.Pointer(ct))
return nil, nil
}
func (ct *Converter) UpdateLocation(loc ast.Location) {
ct.curLoc = loc
}

View File

@@ -0,0 +1,24 @@
package main
import (
"fmt"
"os"
"github.com/goplus/llgo/c"
"github.com/goplus/llgo/chore/_xtool/llcppsigfetch/parse"
)
func main() {
if c.Argc != 2 {
fmt.Fprintln(os.Stderr, "Usage: cvt <headerFile>")
return
}
sourceFile := *c.Advance(c.Argv, 1)
c.Printf(c.Str("sourceFile: %s\n"), sourceFile)
converter, err := parse.NewConverter(c.GoString(sourceFile))
if err != nil {
panic(err)
}
defer converter.Dispose()
converter.Convert()
}

View File

@@ -0,0 +1,60 @@
package parse
import (
"errors"
"github.com/goplus/llgo/chore/llcppg/ast"
)
type Context struct {
Files map[string]*ast.File
}
func NewContext() *Context {
return &Context{
Files: make(map[string]*ast.File),
}
}
// ProcessFiles processes the given files and adds them to the context
func (p *Context) ProcessFiles(files []string) error {
for _, file := range files {
if err := p.processFile(file); err != nil {
return err
}
}
return nil
}
// parse file and add it to the context,avoid duplicate parsing
func (p *Context) processFile(path string) error {
if _, exists := p.Files[path]; exists {
return nil
}
parsedfiles, err := p.parseFile(path)
if err != nil {
return errors.New("failed to parse file: " + path)
}
for path, file := range parsedfiles {
if _, exist := p.Files[path]; !exist {
p.Files[path] = file
}
}
return nil
}
func (p *Context) parseFile(path string) (map[string]*ast.File, error) {
converter, err := NewConverter(path)
if err != nil {
return nil, errors.New("failed to create converter " + path)
}
defer converter.Dispose()
files, err := converter.Convert()
if err != nil {
return nil, err
}
return files, nil
}