2013-12-17 28 views
6

Jestem nowy w prologu, więc jest to dla mnie duże wyzwanie. Mam zaimplementować prosty język podobny do C w Prologu.wdrożyć prosty język podobny do C w Prologu?

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 

Jednak utknąłem w pierwszym kroku. Oto co osiągnąłem do tej pory. z lokalnego stosu!

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). 

Oto moja logika. Najpierw chcę być w stanie skonsumować listę (tak ją interpretuję -!), Więc struktura gramatyki jest naprawdę bardzo ważna. Zastanawiam się również nad użyciem listy zmiennych "Vars" w formach [[nazwa, wartość], [a, 1], [b, 2] ...] i zaktualizowanej wersji - "_Vars". Mogę więc przekazać go do innych zdań, takich jak pętla while i pisać.

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

Ale ... Wygląda na to, że logika jest błędna od samego początku. : \ below to wersja uproszczona. Byłbym bardzo wdzięczny, jeśli możesz mi pomóc tutaj. I naprawdę mam nadzieję, że nie zabiorę tego ze sobą w Boże Narodzenie. 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-jak, czy na pewno? Wygląda to okropnie jak Pascal :) –

+3

To ciekawe ćwiczenie, w przeciwieństwie do wszystkiego, co widziałem. – hardmath

+0

Haha. Będę aktualizował ten post. – Hashbug

Odpowiedz

2

To jak bym go o to:

  1. przekształcić kod źródłowy w drzewo składniowe

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

    staje

    statements([ 
        assign(a, number(1)), 
        while(greater(variable(a), number(5))), 
          statements([ 
           assign(a, plus(variable(a), number(1))) 
            ]) 
         ) 
          ]) 
    
  2. build tłumacz dla to.

    Istnieje wiele tłumaczy. Najłatwiejszy jest tłumacz vanilla. Oto jeden Chciałbym zacząć:

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

ta struktura jest już domyślnie obsługiwana przez DCG, jak użyto w pytaniu OP. – CapelliC

+0

Problemem, z którym teraz borykam się, jest wzorzec rekursji oraz aktualizacja i przekazywanie zmiennych. Ale i tak dzięki. streszczenie drzewo składniowe rodzaj dzwonków dzwonek. – Hashbug

+0

Myślę, że możesz być w stanie ominąć rekurencję za pomocą 'repeat' oraz powiązać i odłączyć zmienne LUB używając listy wszystkich stanów z niezwiązaną zmienną w końcu, która jest wyspecjalizowana dla każdego powtórzenia LUB używając' assert' i 'retrakcji'. – User

2

Kod wydaje się właściwe, tylko niektóre typo wokół, powodując singletons, że prawdopodobnie zaszkodzić zasadność swojej próbie.

Istnieje + 2 singletons w simple_assign (Var_Name2 i Var_Value) i + Var_Name2 jest Singleton w var_name

Chyba nie używasz i IDE z właściwego podświetlanie składni ...

edytuj pojedynczo oddzielnie, muszę powiedzieć, że odpowiedź użytkownika jest bardziej przydatna niż moja (+1). Próba dostarczenia modyfikowalnego środowiska podczas analizowania nie działa. Oto jak przetestowałem, z nieco inną wersją twojej gramatyki:

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

... i ignorowanie ostrzeżeń kompilatora ... –

+1

dzięki chłopaki. Używam wiązania tekstowego z wtyczką syntaktycznego prologu i mam tendencję do ignorowania singletonów. – Hashbug

+0

@Hashbug Nie powinieneś ignorować singletonów, ponieważ mogą wskazywać na błąd. – lurker