2013-12-17 7 views
6

Ich bin neu in Prolog, also ist das eine ziemliche Herausforderung für mich. Ich soll eine einfache C-ähnliche Sprache in Prolog implementieren.implementieren Sie eine einfache C wie Sprache in Prolog?

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 

Allerdings stecke ich im ersten Schritt fest. Das habe ich bisher erreicht. aus dem lokalen Stapel!

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

Hier ist meine Logik. Zuerst möchte ich die Liste konsumieren können (so interpretiere ich sie - -!), So dass die Grammatikstruktur wirklich sehr wichtig ist. Und ich denke auch über die Verwendung einer Variablenliste 'Vars' in Formen von [[Name, Wert], [a, 1], [b, 2] ...], und eine aktualisierte Version - '_Vars'. So kann ich es an andere Anweisungen wie while loop und write weitergeben.

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

Aber ... Es sieht so aus, als wäre die Logik von Anfang an falsch. : \ unten ist die vereinfachte Version. Ich würde es wirklich schätzen, wenn Sie mir hier helfen können. Und ich hoffe wirklich, dass ich das zu Weihnachten nicht mitnehme. 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, bist du sicher? Das sieht schrecklich nach Pascal aus :) –

+3

Dies ist eine interessante Übung, anders als alles, was ich gesehen habe. – hardmath

+0

Haha. Ich werde diesen Beitrag auf dem neuesten Stand halten. – Hashbug

Antwort

2

Dies ist, wie ich es gehen würde:

  1. den Quellcode in einen abstrakten Syntaxbaum

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

    wird

    statements([ 
        assign(a, number(1)), 
        while(greater(variable(a), number(5))), 
          statements([ 
           assign(a, plus(variable(a), number(1))) 
            ]) 
         ) 
          ]) 
    
  2. build-Transformation ein Dolmetscher für es.

    Es gibt verschiedene Dolmetscher. Der einfachste ist der Vanille-Interpreter. Hier ist, den ich mit beginnen würde:

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

Diese Struktur wird bereits implizit von DCG behandelt, wie es in der OP-Frage verwendet wird. – CapelliC

+0

Das Problem, mit dem ich gerade konfrontiert bin, ist das Rekursionsmuster und die Aktualisierung und Weitergabe der Variablenliste. Danke trotzdem. abstrakte Syntax Baum Art der Ringe eine Glocke. – Hashbug

+0

Ich denke, dass Sie in der Lage sein können, die Rekursion zu umgehen, indem Sie 'repeat' verwenden und Variablen binden oder losbinden ODER eine Liste aller Zustände mit einer ungebundenen Variable am Ende verwenden, die auf jede Wiederholung ODER mit' assert' und 'retract' spezialisiert ist. – User

2

Ihr Code angemessen erscheint, um nur einige Tippfehler um, was zu Singletons, dass wahrscheinlich die Solidität Ihres Versuchs schaden.

Es gibt + 2 Singletons in simple_assign (Var_Name2 und var_value) und + Var_Name2 ist Singletons in var_name

Ich denke, Sie sind nicht mit der richtigen Syntax und IDE-Hervorhebung ...

bearbeiten Singletons auseinander, muss ich sagen, dass User 'Antwort ist nützlicher als meins (+1). Der Versuch, eine änderbare Umgebung bereitzustellen während Parsing funktioniert nicht. Hier ist, wie ich getestet habe, mit einer etwas anderen Version Ihrer Grammatik:

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

... und ignorieren Compiler Warnungen .... –

+1

danke Jungs. Ich benutze Text-Mate mit einem Prolog-Syntax Highlight Plug-in. Und ich neige dazu, Singletons zu ignorieren .. – Hashbug

+0

@Hashbug Sie sollten nicht Singletons ignorieren, da sie auf einen Fehler hinweisen können. – lurker

Verwandte Themen