2013-12-17 34 views
6

我是新來的prolog,所以這對我來說是一個很大的挑戰。 我應該在Prolog中實現一個簡單的C語言。在Prolog中實現一個簡單的C語言?

the ultimate goal is to be able to execute something like this: 
?- run([begin,a,:=,10,while,a,>,5,begin,write,a,a,:=,a,-,1,end,end]). 

and get: 
10 
9 
8 
7 
6 
yes 

但是,我被困在第一步。 這是我迄今爲止取得的成就。超出本地堆棧!

statement(Vars,_Vars) --> assign(Vars,_Vars). 
statement(Vars,Vars2) --> statement(Vars,Vars1), statement(Vars1,Vars2). 

assign(Vars,_Vars) --> default_assign(Vars,_Vars). 
assign(Vars,_Vars) --> simple_assign(Vars,_Vars). 

% a //default value 0 
default_assign(Vars,_Vars) --> 
    var_name(Var_Name), 
    {update_vars([Var_Name,0],Vars,_Vars)}. 

% a = 0 
simple_assign(Vars,_Vars) --> 
    var_name(Var_Name),[=],var_value(Var_Value), 
    {update_vars([Var_Name,Var_Value],Vars,_Vars)}. 

% a = b 
simple_assign(Vars,_Vars) --> 
    var_name(Var_Name1),[=],var_name(Var_Name2), 
    { 
    update_vars([Var_Name1,Var_Value],Vars,_Vars) 
    }. 

var_name(Var_Name) --> [Var_Name],{\+number(Var_Name2)}.  
var_value(Var_Value) -->[Var_Value],{number(Var_Value)}. 

% found match, update 
update_vars(Var,Vars,_Vars):- 
    member(Var,Vars), 
    update(Var,Vars,_Vars), 
    _Vars\==[]. 
% no match, append 
update_vars(Var,Vars,_Vars):- 
    \+member(Var,Vars), 
    append(Var,Vars,_Vars). 

update([Name,Value],[],[]). 
update([Name,Value],[[Name,Old_Value]|T1],[[Name,Value]|T2]):- 
    update([Name,Value],T1,T2). 
update([Name,Value],[[Name1,Value1]|T1],[[Name1,Value1]|T2]):- 
    [Name,Value]\=[Name1,Value1], 
    update([Name,Value],T1,T2). 

append([Name,Value],[],[[Name,Value]]). 
append([Name,Value],[H|T1],[H|T2]):- 
    append([Name,Value],T1,T2). 

這是我的邏輯。首先,我希望能夠使用列表(這就是我解釋它的方式 - - !),所以語法結構真的非常重要。 而且我也想用[[Name,Value],[a,1],[b,2] ...]和更新版本'_Vars'的形式使用變量列表'Vars'。所以我可以將它傳遞給while循環和寫入等其他語句。

statement(Vars,Vars2) --> statement(Vars,Vars1), statement(Vars1,Vars2). 
% this seems wrong... 

但是......看起來邏輯從一開始就是錯誤的。 :\下面是簡化版本。 如果你能在這裏幫助我,我將不勝感激。我真的希望我不會在聖誕節期間帶着這個。 TT

statement --> assign. 
statement --> statement, statement. 

assign --> simple_assign. 
assign --> default_assign. 

default_assign --> 
    var_name(Var_Name). 
simple_assign --> 
    var_name,[=],var_value. 

var_name --> 
    [Var_Name],{\+number(Var_Name)}.  
var_value --> 
    [Var_Value],{number(Var_Value)}. 
+3

C-like,你確定嗎?這看起來非常像帕斯卡:) – 2013-12-17 11:09:44

+3

這是一個有趣的練習,不像我見過的任何東西。 – hardmath

+0

哈哈。我會保持這篇文章更新。 – Hashbug

回答

2

這是我怎麼會去一下:

  1. 變換的源代碼轉換成一個抽象語法樹

    begin 
        a := 1 
        while a < 5 
        begin 
        a := a + 1; 
        end 
    end 
    

    成爲

    statements([ 
        assign(a, number(1)), 
        while(greater(variable(a), number(5))), 
          statements([ 
           assign(a, plus(variable(a), number(1))) 
            ]) 
         ) 
          ]) 
    
  2. 構建一位翻譯它。

    有各種口譯員。最簡單的是香草翻譯。 這是一個我會首先:

    interpret(number(N), State, N, State). 
    interpret(assign(Variable, Statement), State, Value, NewState) :- 
        interpret(Statement, State, Value, NewState1), 
        assignVariable(Variable, Value, NewState1, NewState). 
    
+1

這個結構已經隱式地由DCG處理,就像在OP的問題中使用的那樣。 – CapelliC

+0

我現在面臨的問題是遞歸模式,更新和傳遞變量列表。不過謝謝。抽象語法樹種響鈴。 – Hashbug

+0

我認爲你可以通過使用'repeat'來綁定和解除綁定變量,或者使用一個所有狀態的列表,並在最後使用''assert'和'retract'來專門爲每個重複或者一個未綁定的變量來規避遞歸。 – User

2

您的代碼似乎是恰當的,只是一些錯字左右,導致單身,這可能損害您嘗試的穩健性。

有在simple_assign + 2單身(Var_Name2和Var_Value),並 + Var_Name2是VAR_NAME單

我你不使用IDE和適當的語法高亮猜...

編輯分開,我必須說用戶的回答比我的(+1)更有用。試圖提供可修改的環境,而解析不起作用。下面是我測試過的,語法有些不同的版本:

test :- 
    phrase(statement(S), [begin,a,:=,10,while,a,>,5,begin,write,a,a,:=,a,-,1,end,end]), 
    eval(S, [], _). 

% grammar 

statement(Var := Expr) --> var(Var), [:=], expr(Expr). 
statement(write(E)) --> [write], expr(E). 
statement(while(C, S)) --> [while], condition(C), statement(S). 
statement(S) --> [begin], statements(S), [end]. 

statements([S|R]) --> statement(S), statements(R). 
statements([]) --> []. 

condition(L > R) --> expr(L), [>], expr(R). 

expr(L - R) --> (var(L) ; num(L)), [-], expr(R). 
expr(E) --> (var(E) ; num(E)). 

var(var(V)) --> [V], {atom(V)}. 
num(num(N)) --> [N], {number(N)}. 

% evaluation 

eval([S|R], Vs, Us) :- eval(S, Vs, V1), eval(R, V1, Us). 
eval([], Vs, Vs). 

eval(V := E, Vs, Us) :- 
    exprv(E, Vs, Ve), 
    (select(V := _, Vs, R) -> Us = [V := Ve | R] ; Us = [V := Ve | Vs]). 
eval(write(E), Vs, Vs) :- exprv(E, Vs, Ve), writeln(Ve). 
eval(while(C, S), Vs, Ts) :- 
    satisfied(C, Vs) -> eval(S, Vs, Us), eval(while(C, S), Us, Ts) ; Vs = Ts. 

% no side effect here 

exprv(L-E, Vs, Ve) :- exprv(L, Vs, Vl), exprv(E, Vs, R), Ve is Vl - R. 
exprv(num(N), _, N). 
exprv(var(V), Vs, Vv) :- memberchk(var(V) := Vv, Vs). 

satisfied(L > R, Vs) :- exprv(L, Vs, Vl), exprv(R, Vs, Vr), Vl > Vr. 
+2

...並忽略編譯器警告.... – 2013-12-17 12:30:10

+1

謝謝你們。我正在使用帶有序言語法突出顯示插件的文本伴侶,並且我傾向於忽略單例。 – Hashbug

+0

@Hashbug您不應該忽略單例,因爲它們可能指向一個錯誤。 – lurker