% Analyse syntaxique % Produit l'ASA d'un programme. Donne un noeud

. program(prog(T)) --> statement(T). % Produit l'ASA d'un enonce. Donne un noeud . % ::= if1(,) | if2(,,) | while(,) | % do(,) | seq(,) | empty | expr() statement(if1(E,S)) --> token("if"), paren_expr(E), statement(S). statement(if2(E,S1,S2)) --> token("if"), paren_expr(E), statement(S1), token("else"), statement(S2). statement(while(E,S)) --> token("while"), paren_expr(E), statement(S). statement(do(S,E)) --> token("do"), statement(S), token("while"), paren_expr(E), token(";"). statement(S) --> token("{"), statement_list(S), token("}"). statement(expr(E)) --> expr(E), token(";"). statement(empty) --> token(";"). statement_list(empty) --> []. statement_list(seq(S1,S2)) --> statement(S1), statement_list(S2). % ::= assign(,) | lt(,) | add(,) | sub(,) | % var() | cst() % est une variable (un atome Prolog a une lettre) % est un nombre paren_expr(E) --> token("("), expr(E), token(")"). expr(E) --> test(E). expr(assign(V,E)) --> token(id(V)), token("="), expr(E). test(E2) --> sum(E1), test_next(E1,E2). test_next(E,E) --> []. test_next(E1,lt(E1,E2)) --> token("<"), sum(E2). sum(E2) --> term(E1), sum_next(E1,E2). sum_next(E1,E3) --> token("+"), term(E2), sum_next(add(E1,E2),E3). sum_next(E1,E3) --> token("-"), term(E2), sum_next(sub(E1,E2),E3). sum_next(E,E) --> []. term(var(V)) --> token(id(V)). term(cst(N)) --> token(int(N)). term(E) --> paren_expr(E). % Analyseur lexical: consomme les espaces; produit une liste contenant % un mot-cle ou un operateur, un identificateur `id()' ou un entier % `int()' token(T) --> " ", token(T). token(T) --> word(T). token(int(N)) --> integer(N). token([X]) --> [X]. word(T) --> letters(L), {word_next(L,T)}. word_next([X],id(V)) :- char_code(V,X). word_next(L,L). % Lit autant de lettres que possible letters(""), [X] --> [X], {X < "a"; X > "z"}. letters([X|L]) --> [X], {"a" =< X, X =< "z"}, letters(L). % Lit autant de chiffres que possible integer(N2) --> [X], {"0" =< X, X =< "9"}, {N1 is X - "0"}, int_next(N1,N2). int_next(N,N), [X] --> [X], {X < "0"; X > "9"}. int_next(N1,N3) --> [X], {"0" =< X, X =< "9"}, {N2 is 10 * N1 + X - "0"}, int_next(N2,N3). % Generation de code % Produit un melange d'atomes et de nombres signes conformes a ceux qui % sont produits par le compilateur original, p. 99. Note: une autre % grammaire DCG est utilisee pour PRODUIRE le code-octets; des % etiquettes sont propagees pour connaitre la position de chaque % instruction; comme les sauts sont relatifs, une variable est emise % afin de representer la distance et le calcul de cette distance est % remis a plus tard compile(prog(N),Lin,Lout) --> compile(N,Lin,L1), emit(return,L1,Lout). compile(if1(E,S),Lin,Lout) --> compile(E,Lin,L1), emit(ifeq,L1,L2), emit_jump(Lout,L2,L3,C1), compile(S,L3,Lout), {C1}. compile(if2(E,S1,S2),Lin,Lout) --> compile(E,Lin,L1), emit(ifeq,L1,L2), emit_jump(L6,L2,L3,C1), compile(S1,L3,L4), emit(goto,L4,L5), emit_jump(Lout,L5,L6,C2), compile(S2,L6,Lout), {C1, C2}. compile(while(E,S),Lin,Lout) --> compile(E,Lin,L1), emit(ifeq,L1,L2), emit_jump(Lout,L2,L3,C1), compile(S,L3,L4), emit(goto,L4,L5), emit_jump(Lin,L5,Lout,C2), {C1, C2}. compile(do(S,E),Lin,Lout) --> compile(S,Lin,L1), compile(E,L1,L2), emit(ifne,L2,L3), emit_jump(Lin,L3,Lout,C1), {C1}. compile(seq(S1,S2),Lin,Lout) --> compile(S1,Lin,L1), compile(S2,L1,Lout). compile(empty,Lin,Lin) --> []. compile(expr(E),Lin,Lout) --> compile(E,Lin,L1), emit(pop,L1,Lout). compile(assign(V,E),Lin,Lout) --> compile(E,Lin,L1), emit(dup,L1,L2), emit(istore,L2,L3), {char_code(V,Code)}, {No is Code - "a"}, emit(No,L3,Lout). compile(lt(E1,E2),Lin,Lout) --> emit(bipush,Lin,L1), emit(1,L1,L2), compile(E1,L2,L3), compile(E2,L3,L4), emit(isub,L4,L5), emit(iflt,L5,L6), emit_jump(Lout,L6,L7,C1), emit(pop,L7,L8), emit(bipush,L8,L9), emit(0,L9,Lout), {C1}. compile(add(E1,E2),Lin,Lout) --> compile(E1,Lin,L1), compile(E2,L1,L2), emit(add,L2,Lout). compile(sub(E1,E2),Lin,Lout) --> compile(E1,Lin,L1), compile(E2,L1,L2), emit(sub,L2,Lout). compile(var(V),Lin,Lout) --> emit(iload,Lin,L1), {char_code(V,Code)}, {No is Code - "a"}, emit(No,L1,Lout). compile(cst(N),Lin,Lout) --> emit(bipush,Lin,L1), emit(N,L1,Lout). emit_jump(Ldest,Lin,Lout,D is Ldest-Lin) --> [D], {Lout is Lin+1}. emit(X,Lin,Lout) --> [X], {Lout is Lin+1}. % Exemple d'utilisation de `compile': % program(Node,"while (x<0) x=x+1;",""), compile(Node,0,_,BC,[]), write(BC).