C語言函數庫查詢系統(ACCESS)

這個主要使用ACCESS來進行製作,可以將C語言的函數、全局變量、宏、聯合、結構、枚舉等類型的字符串分類儲存起來,能使用窗體查詢這裏裏面的函數或者宏,也可以用來查看某個函數屬於哪個頭文件,比如printf()函數:

當然,要是人工一個一個的輸函數,還不得累死,因此使用VBA製作了簡單的程序,可以從語言的頭文件或者源文件自動識別出函數、全局變量、結構、宏、聯合、枚舉等,然後添加到表中,不過技術能力有限,還有BUG,識別錯誤,或者報告文件導入失敗其實已經成功是常有的事,目前只能作爲一個輔助工具來使用。當程序寫大了,或者在看不知名的代碼,可以使用這個工具導入一下,就可以看到這個文件包含哪些東西。使用效果如圖,這裏面已經導入了幾個C語言標準庫的頭文件:

 

 

github地址:https://github.com/lindorx/Cfunlibsearch

VB忘很久了,所以代碼寫的很亂,不算註釋空行大概470多行,VBA的代碼:

Option Compare Database
Public depth As Integer     '記錄當前代碼的嵌套深度
Public ann As Boolean       '記錄當前代碼書否屬於多行註釋
Public num As Integer       '記錄a字符串數組的大小
Public 所屬文件 As String   '儲存當前正在處理的文件名
Public line As Long         '記錄當前所在行
Public sql As String        '儲存要執行的DQL語句
Public headfile As String   '儲存當前文件引用到的頭文件
Public fnum As Long          '記錄函數數量
Public vnum As Long         '記錄變量數量
Public model As Integer       '記錄當前模式,1:檢索標準庫,2:導入文件

Private Sub Form_Load()
Label0.Caption = "文件路徑:"
command0.Caption = "執行"
model = 2
加入.Visible = False
End Sub

Private Sub 檢索標準庫_Click()
Label0.Caption = "輸入查詢的函數或宏:"
command0.Caption = "查詢"
model = 1

End Sub

Private Sub 加入_Click()
    Text0.SetFocus  '將焦點移到文本框,就可以隱藏控件本身
    用戶確認 = MsgBox("是否加入?", vbYesNo, "warring")
    If 用戶確認 = vbNo Then GoTo 加入_End
    If standlib() Then
    MsgBox "導入完成"
    Else: MsgBox "導入失敗"
    End If
加入_End:
加入.Visible = False
End Sub
Private Sub command0_Click()
If model = 1 Then               '判斷當前模式,1爲查詢標準庫,2爲導入文件
Dim db
Dim 標準庫 As Recordset
Dim 找到 As Boolean             '找到函數名或者宏名標誌
找到 = False
Set db = CurrentDb              '令db指向當前的數據庫
Set 標準庫 = db.OpenRecordset("select * from 標準庫")   '通過SQL語句獲得表
'從text0讀取要查詢的函數名或宏名
s = Text0.value
If 標準庫.EOF Then Exit Sub         '判斷當前表是否爲空
標準庫.MoveFirst                    '將表定位到第一行
Do While Not 標準庫.EOF            '遍歷表,進行查詢
    temp = 標準庫.Fields("函數名")
    If IsNull(temp) Then GoTo l1       '判斷該表項是否爲空
    函數名 = CStr(temp)
    If 函數名 = s Then
        找到 = True
        Text1.value = 函數名
        Text2.value = CStr(標準庫.Fields("函數參數"))
        Text5.value = CStr(標準庫.Fields("文件名"))
        Text3.value = ""
        Text4.value = ""
    End If
l1:
    標準庫.MoveNext         '移動到下一行
Loop
If Not 找到 Then
 標準庫.MoveFirst
    Do While Not 標準庫.EOF
    On Error GoTo l2
    temp = 標準庫.Fields("宏名")
    If IsNull(temp) Then GoTo l2
    宏名 = CStr(temp)
    If 宏名 = s Then
        找到 = True
        Text3.value = 宏名
        On Error GoTo nodef
        Text4.value = CStr(標準庫.Fields("宏定義"))
        Text5.value = CStr(標準庫.Fields("文件名"))
        Text1.value = ""
        Text2.value = ""
    End If
l2:
    標準庫.MoveNext
Loop
End If
標準庫.Close
If Not 找到 Then
    Text1.value = ""
    Text2.value = ""
    Text3.value = ""
    Text5.value = ""
nodef:
    Text4.value = ""
End If
Exit Sub
ElseIf model = 2 Then
    Dim filename As String
    If IsNull(Text0.value) Then Exit Sub
    filename = Text0.value
    If filename <> "" And filename <> "輸入要讀取的文件路徑" Then filectrl (filename)
    model = 2
End If
End Sub

Private Sub Text0_GotFocus()
Text0.Text = ""
End Sub

Private Sub Text0_LostFocus()
If Text0.Text = "" And model <> 1 Then Text0.Text = "輸入要讀取的文件路徑"
End Sub

Private Sub 讀取文件_Click()
    Label0.Caption = "文件路徑:"
    command0.Caption = "執行"
    model = 2
End Sub

Function filectrl(filename As String) As Boolean
filectrl = False
    Dim buf As String       '儲存截取出的字符串
   Dim strstart As Integer  '記錄字符串的起始位置
   Dim strend As Integer    '記錄字符串的結束位置
   Dim i As Integer         '遍歷字符串
   Dim length As Integer    '記錄字符串長度
   Dim ann As Boolean       '記錄多行註釋,當目前內容是註釋時,設爲真
   depth = 0
   ann = False
   line = 0
   is_struct_union_equm = False
   headfile = ""
   fnum = 0
   vnum = 0
   存在花括號 = False
   DoCmd.SetWarnings False      '關掉彈窗警告
    '提出文件名
    最後一個分割線位置 = InStrRev(filename, "\", Len(filename))
    所屬文件 = Mid(filename, 最後一個分割線位置 + 1, Len(filename) - 最後一個分割線位置)
    On Error GoTo ferr  '如果讀取錯誤,就跳轉到ferr這裏
    Open filename For Input As #1
    Do While Not EOF(1) '判斷是否到達文件尾
        Line Input #1, buf  '讀取一行字符串到buf
        line = line + 1
        '去除註釋
        buf = subcomment(buf)
        If buf = "" Then GoTo donext
        buf = Replace(buf, """", """""")
        '判斷宏
        If Mid(buf, 1, 1) = "#" Then
            If cdefine(buf) Then GoTo donext
            If chead(buf) Then GoTo donext
        End If
        左花括號 = InStr(1, buf, "{")
        右花括號 = InStr(1, buf, "}")
        If 左花括號 > 0 And 右花括號 = 0 Then 存在花括號 = True
        '將結構這樣帶有定義的關鍵字整體放到一行
        If (InStr(1, buf, "struct") > 0 Or InStr(1, buf, "union") > 0 Or InStr(1, buf, "enum") > 0) And 存在花括號 Then
            is_struct_union_equm = True
            Do While 存在花括號 And Not EOF(1)
                Line Input #1, s
                line = line + 1
                If InStr(1, s, "}") > 0 Then
                存在花括號 = False
                buf = buf + s
                Else
                buf = buf + s
                End If
            Loop
        End If
        '判斷是否屬於結構,聯合,枚舉等類型
        If is_struct_union_equm Then
            cblock (buf)
            is_struct_union_equm = False '重新置位,防止下一次循環錯誤使用
            GoTo donext
        End If
        '判斷函數
        If fun(buf) Then
        GoTo donext
        '判斷變量
        ElseIf cvalue(splitStr(buf)) Then
        GoTo donext
        End If
        If 左花括號 > 0 Then depth = depth + 1
        If 右花括號 > 0 Then depth = depth - 1
        If depth < 0 Then Exit Do
donext:
    Loop
    Close #1
文件類型 = "未知"
句號未知 = InStr(2, 所屬文件, ".")
If 句號位置 > 0 Then
後綴名 = Mid(所屬文件, 句號位置, Len(所屬文件) - 句號位置)
    If 後綴名 = "h" Or 後綴名 = "H" Then
        文件類型 = "頭文件"
    ElseIf 後綴名 = "c" Or 後綴名 = "C" Then
        文件類型 = "源文件"
    End If
End If
sql = "insert into C代碼表(文件名,文件類型,代碼行數,函數數量,變量數量,引用到的頭文件) values(""" _
        + 所屬文件 + """,""" + 文件類型 + """," + str(line) + "," + str(fnum) + "," + str(vnum) + ",""" + headfile + """);"
'MsgBox sql
DoCmd.RunSQL sql
MsgBox "文件導入完成"
加入.Visible = True
filectrl = True
Exit Function
ferr:   '文件讀取錯誤
Close #1
MsgBox "文件路徑錯誤"
End Function

'函數處理
Function fun(buf)
Dim 右 As Boolean
右 = False
fun = False
 '查找括號,如果存在括號,則將括號前以非英文字符、數字、下劃線劃分的字符串提出
        length = InStr(1, buf, "(")
        左花括號 = InStr(1, buf, "{")
        右花括號 = InStr(1, buf, "}")
        等於號 = InStr(1, buf, "=")
        If 等於號 <> 0 Then GoTo exitfun
        If length = 0 Then GoTo exitfun
        
        If 左花括號 > 0 And 左花括號 < length Then
            depth = depth + 1
            Exit Function
        End If
        If 右花括號 > 0 And 右花括號 < length Then
            depth = depth - 1
            右 = True
        End If
        strend = length
        If strend > 0 And depth = 0 Then  '存在括號且嵌套深度爲0
        a = splitStr(buf)
        函數類型 = ""
        For i = 1 To num
            t = InStr(1, a(i), "(")
            If t > 0 Then
            If t > 1 Then
                函數名 = Mid(a(i), 1, t - 1)
                For j = 1 To i - 1
                    函數類型 = 函數類型 + a(j) + " "
                Next
            Else
                函數名 = a(i - 1)
                For j = 1 To i - 2
                    函數類型 = 函數類型 + a(j) + " "
                Next
            End If
            Exit For
            End If
        Next
        '取出函數參數
        t = InStr(length, buf, ")")
        If t <> 0 Then
        函數參數 = Mid(buf, length, t - length + 1)
        'MsgBox "函數參數:" + 函數參數
        End If
        End If
If 函數名 <> "" Then
fun = True
Else
Exit Function
End If
sql = "insert into 函數(函數名,類型,參數,所在行,所屬文件,引用到的函數,定義) values(""" + _
        函數名 + """,""" + 函數類型 + """,""" + 函數參數 + """," + str(line) + ",""" + 所屬文件 + _
        """,""" + "未知" + """,""" + "未知" + """);"
'MsgBox sql
DoCmd.RunSQL sql
fnum = fnum + 1
exitfun:
If 左花括號 > 0 Then depth = depth + 1
If 右花括號 > 0 And Not 右 Then depth = depth - 1
End Function

'去除註釋
Function subcomment(buf)
Dim length As Integer
Dim strstart As Integer
Dim strend As Integer
    strstart = 1
    strend = -1
    '將所有換行符替換爲空格
    length = InStr(1, buf, "*/")
    If length > 0 Then
        ann = False
        strstart = length + 2  'i指向有效的字符串位置
    End If
    
    If ann Then
        subcomment = ""
        Exit Function
    End If
   
    If strstart > Len(buf) Then
    subcomment = ""
    Exit Function
    End If
    
    length = InStr(strstart, buf, "/*")
    If length > 0 Then
        strend = length - 1
        ann = True
    End If
    length = InStr(strstart, buf, "//")
    If length > 0 Then
        strend = length - 1
    End If
    If strend = -1 Then
        strend = Len(buf)
    ElseIf strend = 0 Then
        subcomment = ""
        Exit Function
    End If
    '通過strstart和strend兩個下標值確定非註釋字符串的位置,取出字符串
    buf = Mid(buf, strstart, strend - strstart + 1)
    '去除字符串左右兩邊的多餘空格,製表符
    buf = Replace(buf, vbTab, " ") '將製表符全部替換爲空格
    buf = Trim(buf)
    subcomment = buf
End Function
'宏處理
Function cdefine(buf)
cdefine = False
    第一個空格的位置 = InStr(1, buf, " ")
    If 第一個空格的位置 < 2 Then
    Exit Function
    End If
    第一個字符串 = Mid(buf, 2, 第一個空格的位置 - 2)
    If 第一個字符串 = "define" Then
        第二個空格的位置 = InStr((第一個空格的位置 + 1), buf, " ")
        length = 0
        If 第二個空格的位置 = 0 Then
            If Len(buf) > 第一個空格的位置 Then
                length = Len(buf) - 第一個空格的位置
                Else
                Exit Function
            End If
        Else
            length = 第二個空格的位置 - 第一個空格的位置 - 1
        End If
        第二個字符串 = Mid(buf, 第一個空格的位置 + 1, length)
    Else
        Exit Function
    End If
    If 第二個空格的位置 > 0 Then
        第三個字符串 = Mid(buf, 第二個空格的位置, Len(buf) + 1 - 第二個空格的位置)
    Else
        第三個字符串 = ""
    End If
    'MsgBox "宏:" + 第一個字符串
    'MsgBox "宏名:" + 第二個字符串
    'MsgBox "宏定義:" + 第三個字符串
    sql = "insert into 宏(宏名,值,所在行,所屬文件) values(""" + Trim(第二個字符串) + """,""" + Trim(第三個字符串) + """," + str(line) + ",""" + 所屬文件 + """);"
    'MsgBox sql
    DoCmd.RunSQL sql
    cdefine = True
End Function
'全局變量處理,函數內部的變量識別複雜,而且通常情況沒有必要,因此沒有實現
Function cvalue(a)
Dim i As Integer
cvalue = False
類型 = ""
變量名 = ""
值 = ""
    If depth <> 0 Then
    Exit Function
    End If
    '遍歷a,查看是否有=,如果有說明該變量被賦值
    找到等於號 = False
    For i = 1 To num
        等於號位置 = InStr(1, a(i), "=")
        If 等於號位置 > 0 Then
            找到等於號 = True
            Exit For
        End If
    Next
    If 找到等於號 Then
        For j = 1 To i - 2
            類型 = 類型 + a(j) + " "
        Next
        If 等於號位置 = 1 Then '說明該a(i)第一個字符爲等於號
            變量名 = a(i - 1)
            值 = a(num)
            
        Else
            變量名 = Mid(a(i), 1, 等於號位置 - 1)
            類型 = 類型 + a(i - 1) + " "
            值 = Mid(a(i), 等於號位置 + 1, Len(a(i)) - 等於號位置)
        End If
    Else
        變量名 = a(num)
        For j = 1 To num - 1
        類型 = 類型 + a(j) + " "
        Next
    End If
    'MsgBox 變量名
    'MsgBox 類型
    'MsgBox 值
cvalue = True
sql = "insert into 變量(變量名,類型,初始值,所在行,所屬文件) values(""" + 變量名 + """,""" + 類型 + """,""" + 值 + """," + str(line) + ",""" + 所屬文件 + """);"
DoCmd.RunSQL sql
vnum = vnum + 1
End Function

'按空格分割字符串,返回一個字符串數組,這個數組的長度由全集變量num說明
Function splitStr(codestr)
Dim a() As String
num = 1
Dim i As Integer
i = 1
Do While i < Len(codestr)
    b = InStr(i, codestr, " ")
    If b <> 0 Then
        If b > i Then
            ReDim Preserve a(num)
            a(num) = Trim(Mid(codestr, i, b - i))
            num = num + 1
        End If
        i = b + 1
    Else
        Exit Do
    End If
Loop
'還有最後一個字符串可能沒有讀入
ReDim Preserve a(num)
a(num) = Trim(Mid(codestr, i, Len(codestr) - i))
splitStr = a
End Function

'對結構,聯合,枚舉的處理
Function cblock(buf)
cblock = False
左花括號 = InStr(1, buf, "{")
右花括號 = InStr(1, buf, "}")
If 左花括號 = 0 Or 右花括號 = 0 Then
    Exit Function
End If
's儲存關鍵字名
s = Trim(Mid(buf, 1, 左花括號 - 1))
定義 = Trim(Mid(buf, 左花括號, 右花括號 - 左花括號 + 1))
別名 = Trim(Mid(buf, 右花括號 + 1, Len(buf) - 右花括號 - 1))
If InStr(1, s, "struct") > 0 Then
    sql = "insert into 結構(結構名,定義,別名,所在行,所屬文件) values(""" + s + """,""" + 定義 + """,""" + 別名 + """," + str(line) + ",""" + 所屬文件 + """);"
    DoCmd.RunSQL sql
ElseIf InStr(1, s, "union") > 0 Then
    sql = "insert into 聯合體(聯合體名,定義,別名,所在行,所屬文件) values(""" + s + """,""" + 定義 + """,""" + 別名 + """," + str(line) + ",""" + 所屬文件 + """);"
    DoCmd.RunSQL sql
ElseIf InStr(1, s, "enum") > 0 Then
    sql = "insert into 枚舉(枚舉名,定義,別名,所在行,所屬文件) values(""" + s + """,""" + 定義 + """,""" + 別名 + """," + str(line) + ",""" + 所屬文件 + """);"
    DoCmd.RunSQL sql
Else
    Exit Function
End If
'MsgBox "名:" + s
'MsgBox "定義:" + 定義
'MsgBox "別名:" + 別名
cblock = True
End Function
'處理頭文件
Function chead(buf)
chead = False
    inc = Mid(buf, 2, 7)
    If inc = "include" Then
    '讀取後面括號或者引號之間的文件名
        左 = InStr(9, buf, "<")
        If 左 > 0 Then
            右 = InStr(10, buf, ">")
            If 右 = 0 Then
            Exit Function
            End If
            headfile = headfile + Mid(buf, 左, 右 - 左 + 1) + ";"
        Else
            左 = InStr(9, buf, """")
            右 = InStr(10, buf, """")
            If 左 = 0 Or 右 = 0 Then
            Exit Function
            End If
            headfile = headfile + Mid(buf, 左, 右 - 左 + 1) + ";"
        End If
    End If
chead = True
End Function

'標準庫操作,將函數表和宏表合併到標準庫表
Function standlib() As Boolean
standlib = False
函數表可用 = True
宏表可用 = True
  Dim db
  Dim 宏表 As Recordset
  Dim 函數表 As Recordset
  Dim s As String       '儲存讀取標識符
  Set db = CurrentDb    '設定爲當前數據庫
  Set 宏表 = db.OpenRecordset("select * from 宏")
  Set 函數表 = db.OpenRecordset("select * from 函數")
  If 宏表.EOF And 函數表.EOF Then Exit Function
  
  If 宏表.EOF Then
  宏表可用 = False
  Else: 宏表.MoveFirst
  End If
  If 函數表.EOF Then
  函數表可用 = False
  Else: 函數表.MoveFirst
  End If
  
  Do While (Not 宏表.EOF) Or (Not 函數表.EOF)
    If Not 宏表.EOF And 宏表可用 Then
    On Error GoTo fnext              '錯誤處理,一般情況是讀取到了空表項,此時利用goto來跳轉
    宏名 = CStr(宏表.Fields("宏名"))
    On Error GoTo fnext
    宏定義 = Replace(CStr(宏表.Fields("值")), """", """""")
    On Error GoTo fnext
    文件名 = CStr(宏表.Fields("所屬文件"))
    sql = "insert into 標準庫(宏名,宏定義,文件名) values(""" + 宏名 + """,""" _
        + 宏定義 + """,""" + 文件名 + """);"
    On Error GoTo fnext
    DoCmd.RunSQL sql
    standlib = True
fnext:
    宏表.MoveNext
    End If
    If Not 函數表.EOF And 函數表可用 Then
    On Error GoTo anext
    函數名 = CStr(函數表.Fields("函數名"))
    On Error GoTo anext
    函數參數 = CStr(函數表.Fields("參數"))
    On Error GoTo anext
    文件名 = CStr(函數表.Fields("所屬文件"))
    sql = "insert into 標準庫(函數名,函數參數,文件名) values(""" + 函數名 + """,""" _
            + 函數參數 + """,""" + 文件名 + """);"
    On Error GoTo anext
    DoCmd.RunSQL sql
    standlib = True
anext:
    函數表.MoveNext
    End If
    Loop
    宏表.Close      '關閉表
    函數表.Close
End Function

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章