花了兩天的時(shí)間終于完成了Vczh Lazy Script的語(yǔ)法分析工作。語(yǔ)法分析是編譯的第一步,旨在把輸入的字符串(代碼)分析稱跟代碼結(jié)構(gòu)一致的語(yǔ)法樹,以便后續(xù)工作。
藉著去年開(kāi)發(fā)的Syngram工具包,這兩天過(guò)得還算輕松,僅僅對(duì)語(yǔ)言做了一份配置,不過(guò)這份配置也花掉了1200多行代碼。語(yǔ)法分析其余的部分是數(shù)據(jù)結(jié)構(gòu)。目前的數(shù)據(jù)結(jié)構(gòu)僅僅用于再現(xiàn)語(yǔ)言的結(jié)構(gòu),而沒(méi)有附加任何的數(shù)據(jù)。接下來(lái)的工作是檢查所有的identifier,看看有沒(méi)有哪些identifier是使用錯(cuò)誤的。一般來(lái)說(shuō)都是在左值使用函數(shù)、類構(gòu)造標(biāo)簽參數(shù)不全、轉(zhuǎn)移運(yùn)算符指向的函數(shù)并沒(méi)有聲明成函數(shù)等等比較基本的東西。但是后續(xù)的工作就相當(dāng)?shù)芈闊┝恕?br>
作為一門lazy+pure的函數(shù)范式程序語(yǔ)言,我模仿了Haskell的大部分語(yǔ)法,加上自己的一點(diǎn)點(diǎn)修改(因?yàn)镠askell的語(yǔ)法實(shí)在是太詭異了),但是主要功能是沒(méi)有變化的。等上面所說(shuō)的identifier完成以后,我就要開(kāi)始寫Lazy的類型推導(dǎo)程序了。類型推導(dǎo)程序用于計(jì)算出代碼中省略的類型聲明,相當(dāng)于把整份代碼轉(zhuǎn)換成類型方程然后求解。理論上解有無(wú)窮多個(gè),因此需要找到一個(gè)最好的解。當(dāng)然如果程序?qū)戝e(cuò)的話,也是有可能無(wú)解的,這個(gè)時(shí)候就需要處理錯(cuò)誤信息了。
這個(gè)類型推導(dǎo)跟c#的var關(guān)鍵字還是相差很大的。Lazy語(yǔ)言的所有類型聲明都允許省略,只要類型推導(dǎo)程序能夠找到一個(gè)最好的類型解就可以了。譬如如下代碼:
makelist num list = if (num<=0)
list
(makelist (num-1) ([num]++list));
makelist的意思其實(shí)很簡(jiǎn)單,如果你輸入makelist 5 []的話,你就可以得到數(shù)組[1 , 2 , 3 , 4 , 5]。類型推導(dǎo)過(guò)程如下:
1:Lazy是強(qiáng)類型的(不允許任何隱式類型轉(zhuǎn)換),所以為了讓num<=0合法,num的類型就必須是Int。
2:因?yàn)閇num]++list,所以list的類型必須是[Int]。
3:因?yàn)閕f的第二個(gè)參數(shù)是list,所以makelist的返回值是[Int]。
4:我們得到makelist的類型聲明是makelist :: Int -> [Int] -> [Int]。
5:檢查makelist (num-1) ([num]++list),發(fā)現(xiàn)符合要求。找到一個(gè)最優(yōu)解。
所以上述函數(shù)的類型就被確定了。而且因?yàn)樯鲜龊瘮?shù)的類型可以被如此確定,所以類型聲明makelist::Int->[Int]->[Int]就可以被省略了。
除此之外Lazy還有其他各種各樣的表達(dá)式,形式復(fù)雜多變,而且類型系統(tǒng)包含tuple(匿名struct)和復(fù)合類型(你可以定義一個(gè)量的類型是“整數(shù)或字符串”,因此這個(gè)變量就可以保存兩種類型的數(shù)值了,而且Lazy也提供了獲取這種量的內(nèi)容的渠道)。這幾天得好好計(jì)劃一下。
在此貼一下目前語(yǔ)法分析的成果:
源程序:
1 module main exports
2 main
3 where
4 import System.IO;
5
6 qsort::Ord T,[T]->[T];
7 qsort [] = [];
8 qsort (x:xs) = left ++ [x] ++ right where
9 left = qsort [y|y<-xs,y<x];
10 right = qsort [y|y<-xs,y>=x];
11 end;
12
13 readints::[int]->IO [int];
14 readints ints = do
15 num <- read;
16 if (num<0)
17 (return ints)
18 (readints (ints++[nums]));
19 end;
20
21 main::IO unit;
22 main = do
23 ints <- readints;
24 write (qsort ints);
25 end;
26
27 end;
分析結(jié)果:
1 正在讀取文件
2 正在構(gòu)造自動(dòng)機(jī)
3 正在分析代碼
4 module main {
5 exports {
6 main
7 }
8 declarations {
9 import System.IO
10 funchead main :: (IO unit)
11 funcbody main {
12 parameters {
13 }
14 do {
15 left-exp {
16 ints
17 readints
18 }
19 invoke {
20 write
21 invoke {
22 qsort
23 ints
24 }
25 }
26 }
27 }
28 funchead qsort :: Ord T, ([T] -> [T])
29 funcbody qsort {
30 parameters {
31 list {
32 }
33 }
34 list {
35 }
36 }
37 funcbody qsort {
38 parameters {
39 cons {
40 x
41 xs
42 }
43 }
44 where {
45 invoke {
46 invoke {
47 ++
48 invoke {
49 invoke {
50 ++
51 left
52 }
53 list {
54 x
55 }
56 }
57 }
58 right
59 }
60 declarations {
61 funcbody left {
62 parameters {
63 }
64 invoke {
65 qsort
66 array builder {
67 y
68 constructors {
69 left-exp {
70 y
71 xs
72 }
73 invoke {
74 invoke {
75 <
76 y
77 }
78 x
79 }
80 }
81 }
82 }
83 }
84 funcbody right {
85 parameters {
86 }
87 invoke {
88 qsort
89 array builder {
90 y
91 constructors {
92 left-exp {
93 y
94 xs
95 }
96 invoke {
97 invoke {
98 >=
99 y
100 }
101 x
102 }
103 }
104 }
105 }
106 }
107 }
108 }
109 }
110 funchead readints :: ([int] -> (IO [int]))
111 funcbody readints {
112 parameters {
113 ints
114 }
115 do {
116 left-exp {
117 num
118 read
119 }
120 invoke {
121 invoke {
122 invoke {
123 if
124 invoke {
125 invoke {
126 <
127 num
128 }
129 0
130 }
131 }
132 invoke {
133 return
134 ints
135 }
136 }
137 invoke {
138 readints
139 invoke {
140 invoke {
141 ++
142 ints
143 }
144 list {
145 nums
146 }
147 }
148 }
149 }
150 }
151 }
152 }
153 }
154
今天就寫到這里了。看看電影休息一下……
posted on 2008-04-22 04:03
陳梓瀚(vczh) 閱讀(2552)
評(píng)論(4) 編輯 收藏 引用 所屬分類:
Vczh Lazy Script