標籤:style color strong 檔案 資料 os
深入探究WEB GENI來源程式
折騰WEB GENI的目的,是為了摸清它的結構設計、運行機制,為山寨出自己的專家系統外殼,積累經驗,啟發思路。
為此,必須深入細緻地研讀來源程式代碼。
WEBGENI包括2個模組:geni.pro和cgitools.pro。前者是主程式,負責推理、產生網頁等;後者負責相對底層的CGI資料處理。本文探究的對象,主要是geni.pro。
Visual Prolog(以下簡稱VIP)程式由幾種程式碼片段構成:
PREDICATES :謂詞段。相當於C語言的函式宣告
CLAUSES :子句段。相當於C語言的函數實現
DOMAINS :域段。相當於C語言聲明資料類型結構
DATABASE 或 FACTS : 內部資料庫(事實)段。它是Prolog特有的機制,實際上是儲存結構化資料的記憶體緩衝。Erlang Eresye有對它的模仿。
GOAL :目標段。程式啟動並執行起點,相當於C語言的函數main()。
程式的起點GOAL段
GOALstartpage,CGI_String = cgi_GetString(),str_namelist(CGI_String,ParmList),consult_kb(ParmList,ParmList1),userdefined_startpage(),write_startform(),assert_conditions(ParmList1), infer().
以下,逐句追蹤、剖析器。
1、子句startpage
startpage :- write("Content-type: text/html\n\n"), write("<HTML>\n"), write("<HEAD>\n"), write("<TITLE>\n"), write("Prolog Development Center A/S EXPERT SYSTEM\n"), write("</TITLE>\n"), write("</HEAD>\n"), write("<BODY bgcolor=yellow>\n").
本程式在伺服器端運行,對用戶端瀏覽器的請求,做出以上回應。
2、子句cgi_GetString()
它的謂詞聲明在檔案cgitools.pre中。.pre檔案,專門用來聲明謂詞。
GLOBAL PREDICATES procedure STRING cgi_GetString()
Global 修飾的謂詞、常量、域等,允許多個程式模組調用。
關鍵字procedure把謂詞定義為子程式。子程式從不失敗(fail),從不回溯,只有一個運行結果(但執行階段錯誤除外)。
在檔案cgitools.pro中,定義子句 cgi_GetString( CGI_String )
注意!
謂詞cgi_GetString()聲明時沒有參數,而子句cgi_GetString( CGI_String )實現時有參數。
聲明與定義的這種不一致,VIP編譯器並不認為有錯。
而且,CGI_String = cgi_GetString() 這樣的賦值語句,也不是Prolog應該有的。
為什麼會這樣,不知道。
VIP還有些類似的情況,下面還會遇到。但願VIP沒錯,僅僅是我沒弄明白。
3、關注CGI資料的內容
我用了很長時間在cgitools.pro中察看cgi_GetString()擷取CGI_String,和str_namelist獲得ParmList的過程。
我覺得,這兩件事情的細節,與建造專家系統關係不大,沒必要研究。
重要的是,弄清楚CGI_String與ParmList的內容和結構。
從cgi_GetString的謂詞聲明可見,CGI_String是字串。
在cgitools.dom中,有以下聲明:
GLOBAL DOMAINS PARM = parm(STRING Name,STRING Val) PARMLIST = PARM*
可見,ParmList的結構是這種形式:
[parm("aaa","one"),parm("bbb","two"),parm("ccc","three")]
可用以下辦法驗證。
把geni.pro中的GOAL段全部用注釋屏蔽,用以下代碼取代:
PREDICATESwrite_vars(PARMLIST)write_data(STRING)CLAUSES write_data(CGI_String):- write("<p>"), writef("%",CGI_String), write("</p>"). write_vars([]):-!. write_vars([parm(Key,Value)|Rest]):- writef("<tr><td>%</td><td>%</td></tr>\n",Key,Value), write_vars(Rest).GOALstartpage,CGI_String = cgi_GetString(),file_str("c:\\dd.dat",CGI_String),str_namelist(CGI_String,ParmList),write_data(CGI_String),write("<table>\n"),write_vars(ParmList),write("</table>\n"), write("<br />\n"), write("</body></html>\n").
謂詞file_str,很有Prolog特色。
file_str (STRING OSFileName, STRING StringVariable)
流模式(i, o), (i, i)
讀寫檔案,用同一個“函數”,怕是只有Prolog做得到。
本例,把字串存入檔案dd.dat。
檔案內容是:
knowledgebase=animal
兩個謂詞write_vars(PARMLIST)和write_data(STRING),寫入網頁的內容,可自行驗證。
“knowledgebase=animal”的來源是這樣的:
開啟檔案 D:\Apache2.2\htdocs\GENI\default.htm
<form action="geni.exe" method="post">
<select name="knowledgebase" size="1">
<option>animal</option>
<option>Starting</option>>
<option>Tyre</option>>
</select>
<input type="submit" value="Select problem">
</form>
knowledgebase正是“變數”select的名稱,而animal則是該變數的一個值
該變數的取值,有3種可能:animal,Starting,Tyre
該變數的取值,是由使用者在瀏覽器決定的