
delFrontSep([Sep | R], Sep, S) :- delFrontSep(R,Sep,S),!.
delFrontSep(S, _, S).

fronttoken(String, FrontToken, RestString, Sep) :-
	delFrontSep(String, Sep, String1),
	append(FrontToken,[Sep|RestString],String1),!.
fronttoken(String, FrontToken, RestString) :- 
	fronttoken(String,FrontToken,RestString,0' ). /* Sep = ' ' */

tokens(S,[T|R]) :- fronttoken(S,T,S1),!, tokens(S1,R).
tokens(_,[]).


as(S) :- tokens(S,T), compound_instr(T,["."]).

/*
  compound_instr ->  BEGIN instr_list END 
*/
compound_instr(Tokens,RestTokens) :- 
	Tokens = ["begin" | T1], 
	instr_list(T1,T2),
	T2 = ["end" | RestTokens].

/*
  instr_list -> instr ; instr_list 
               | instr
*/
instr_list(Tokens,RestTokens) :- 
	instr(Tokens,T1),
	T1 = [";" | T2],
	instr_list(T2,RestTokens).
instr_list(Tokens,RestTokens) :- 
	instr(Tokens,RestTokens).
	
/*
  instr -> compound_instr 
          | assignment
	  | if_then_else
	  | nil 
*/
instr(Tokens,RestTokens) :- 
	compound_instr(Tokens,RestTokens);
	assignment(Tokens,RestTokens);
	if_then_else(Tokens,RestTokens);
	RestTokens=Tokens. /* instr vida */

/*
  assignment -> ident := expr
*/

assignment(Tokens,RestTokens) :- 
	Tokens = [Ident, ":=" | T1], ident(Ident),
	expr(T1,RestTokens).

/* 
  if_then_else -> IF expr THEN instr ELSE instr
*/  
if_then_else(Tokens,RestTokens) :- 
	Tokens = ["if" | T1],
	expr(T1,T2),
	T2 = ["then"|T3],
	instr(T3,T4),
	T4 = ["else" | T5],
	instr(T5,RestTokens).

/*
  expr   ->  termen expr1
  expr1  ->  [+-] termen expr1 | nil
  termen ->  numar | ident | (expr)
*/

expr(Tokens,RestTokens) :- 
	termen(Tokens,T1),
	expr1(T1,RestTokens).
expr1(Tokens,RestTokens) :- 
	(Tokens = ["+" | T1]; Tokens = ["-" | T1]),
	termen(T1, T2),
	expr1(T2,RestTokens),!;
	RestTokens = Tokens.
termen([Numar | RestTokens],RestTokens) :- numar(Numar).
termen([Ident | RestTokens],RestTokens) :- ident(Ident).
termen(Tokens,RestTokens) :- 
	Tokens = ["(" | T1],
	expr(T1,T2),
	T2 = [")" | RestTokens].


numar(S) :- number_chars(N,S), number(N). 
                              /* number e un predicat predefinit ce testeaza
				 daca argumentul sau este un numar */
letter(L) :- L >= 0'a,  /* a */
	     L =< 0'z. /* z */
ident([L|R]) :- letter(L), ident(R).
ident([L]) :- letter(L).



/* exemplu de program */

prog("begin                   \
       if 1 then i := i + 1   \
            else i := 2       \
      end . ").


p1("begin i := 1 end . ").  
p2("begin end . ").