這個主要使用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