Hacker Newsnew | past | comments | ask | show | jobs | submitlogin

"seem so..awkward"? Sure because you don't understand prolog. it's very easy to implement languages.

Look how simple I can compile down to asm code in 35 lines of pure prolog code.

https://github.com/segmond/PrologThingz/blob/master/clause_a...

  /*
  	c := 1;
  	r := 1;
  	while c < n do
  	     (c := c + 1;
  	      r := r * c)
  */
  program(1, (
      assign(c,1);
      assign(r,1);
         while((c < n),
  	  (assign(c, c+1);
             assign(r, r*c))))).

  ?- compile(1).
    movc(1,r(1))
    stm(r(1),c)
    movc(1,r(1))
    stm(r(1),r)
  label(_G3638)
    movm(c,r(1))
    movm(n,r(2))
    cmp(1,2)
    bge(1)
    movm(c,r(1))
    movc(1,r(2))
    add(r(2),r(1))
    stm(r(1),c)
    movm(r,r(1))
    movm(c,r(2))
    mul(r(2),r(1))
    stm(r(1),r)
    br(_G3638)
  label(1)


This is great, thank you for sharing this!

Your Prolog compiler is also notable because it can be easily made so general that it not only compiles, but even generates programs.

For example, if I use pattern matching to generalize the first two clauses via:

    cg(i(I), R, [movc(I, r(R))|Z]-Z).
    cg(a(A), R, [movm(a(A), r(R))|Z]-Z).
then we can already use the same code to generate programs and compiled instructions:

    ?- cg(Prog, N, Asm-[]).
    Prog = i(_5354),
    Asm = [movc(_5354, r(N))] ;
    Prog = a(_5354),
    Asm = [movm(a(_5354), r(N))] .
The other clauses can be also generalized, using integer constraints to make them usable in all directions.

For example, if we write:

    cg(X+Y, R, C0-C2):-
            cg(X, R, C0-C1),
            R1 #= R + 1,
            cg(Y, R1, C1-[add(r(R1),r(R))|C2]).
then we can compile an addition whose operands are not even yet fully known:

    ?- cg(i(X)+i(Y), N, Asm-[]).
    Asm = [movc(X, r(N)), movc(Y, r(_8850)), add(r(_8850), r(N))],
    N+1#=_8850.
Still, we can inspect the general pattern that is generated as a result of the compilation, and therefore write for example test cases that subsume many possible concrete cases!

On a general note, one reason why Prolog is so popular for writing compilers is that the language has a built-in mechanism for writing parsers, and in fact describing all kinds of sequences (for example, of tokens, of instructions etc.) in a very convenient way.

For example, the above three clauses can be written equivalently as a so-called definite clause grammar (DCG):

    cg(i(I), R) --> [movc(I, r(R))].
    cg(a(A), R) --> [movm(a(A), r(R))].
    cg(X+Y, R)  -->
            { R1 #= R + 1 },
            cg(X, R),
            cg(Y, R1),
            [add(r(R1),r(R))].

This makes it very easy to see the key aspects of the code. At the same time, the description is so general that it can be used in all directions, to generate, parse and test instructions.

Sample query:

    ?- phrase(cg(i(X)+i(Y), N), Ls).
    Ls = [movc(X, r(N)), movc(Y, r(_2288)), add(r(_2288), r(N))],
    N+1#=_2288.





Guidelines | FAQ | Lists | API | Security | Legal | Apply to YC | Contact

Search: