packages feed

SableCC2Hs-0.0.0.1: prolog/parser.pl

:- consult('parser_tables.pl').
:- consult('trim_ast.pl').

test1:- lift(Input),runParser(Input,_).
test2:-runParser("#EXPRESSION\n 1+1",_).
test3:-runParser("#PREDICATE\n e:M",_).


lift("\
MACHINE Lift\n\
\n\
ABSTRACT_VARIABLES  floor\n\
\n\
INVARIANT /*test comment*/ floor : 0..99\n\
\n\
ASSERTIONS floor>=0\n\
INITIALISATION floor := 4\n\
\n\
OPERATIONS\n\
\n\
	inc = PRE floor<99 THEN floor := floor + 1 END ;\n\
	\n\
	dec = BEGIN floor := floor - 1 END;\n\
	\n\
	result  <-- ground = \n\
	            IF floor=0 THEN\n\
	             result := TRUE\n\
	            ELSE\n\
	             result := FALSE\n\
	            END\n\
	\n\
END").


runParser(Input,AST2):-
  lexerLoop(Input,mode_0/0,[],LexerTokens),!,
  mapTokenIDs(LexerTokens,ParserTokens),!,
%  printTokens(ParserTokens),
  parserLoop([pstate_0/dummyStack],ParserTokens,[(_/AST1)|_]),!,
%  write(AST1),nl,nl,
  trim(AST1,AST2),!,
  write(AST2).

parserLoop(Stack,Input,Res) :-
  findAction(Stack,Input,Action),!,
  parserLoop2(Action,Stack,Input,Res).
parserLoop2(accept,Stack,_,Stack).
parserLoop2(error(ErrorID),_Stack,_,_Res) :- !,errorMessage(ErrorID,Msg),name(N,Msg),throw(parseError(N)).
parserLoop2(shift(_),_Stack,[],_Res) :- !,throw(parserBug('shift action with empty input')).
parserLoop2(shift(NewState),Stack,[H|Rest],Res) :- !,
  parserLoop([(NewState/H)|Stack],Rest,Res).
parserLoop2(reduce(ID,PopCount,GotoIndex),Stack,Input,Res) :- !,
  takeNodes(PopCount,Stack,Nodes),
  constructAST(ID,Nodes,AST),
  dropStack(PopCount,Stack,RestStack),
  findGoto(GotoIndex,RestStack,NewState),
  parserLoop([(NewState/AST)|RestStack],Input,Res).

findAction([], _,_) :- !, throw(parserBug('findAction : empty Stack')).
findAction(_ ,[],_) :- !, throw(parserBug('findAction : empty Input')).
findAction([(StateID/_)|_],[(TokenID/_)|_],Res) :- action(StateID, TokenID, Res),!.
findAction([(StateID/_)|_],_,Res) :- !,defaultAction(StateID,Res).
findAction(_,_,_) :- trow(parserBug('findAction : lookup failed')).

findGoto(_GI,[],_Res) :- !, throw(parserBug('findGoto : empty stack')).
findGoto(GI,[(StateID/_)|_],Res) :- goto(GI,StateID,Res),!.
findGoto(GI,_,Res) :- !,defaultGoto(GI,Res).
findGoto(_,_,_) :- trow(parserBug('findGoto : look failed')).

takeNodes(0,_,[]).
takeNodes(I,[(_/Node)|Rest],[Node|RR]):- !,
  I2 is I-1,
  takeNodes(I2,Rest,RR).

dropStack(0,R,R).
dropStack(I,[_|T],Res) :- !,
  I2 is I-1,
  dropStack(I2,T,Res).

constructAST(ID,Nodes,AST) :-
  reductionRule(ID,Nodes,Term),
  evalReduction(Term,AST).

evalReduction(var(X),X):- !.
evalReduction(emptyList,[]):- !.
evalReduction(singletonList(L),[Res]):-!,evalReduction(L,Res).
evalReduction(appendList(L1,L2),Res):- !,
  evalReduction(L1,R1),
  evalReduction(L2,R2),
  append(R1,R2,Res).
evalReduction(appendNode(L,N),Res):-!,
  evalReduction(L,R1),
  evalReduction(N,R2),
  append(R1,[R2],Res).
evalReduction(newNode(Constructor1,Constructor2,L),Res):-!,
  reduceList(L,Nodes),
  % for almost all cases Construct1 has all information we need and we could almost write
  % Res=..[Constructor1|[pos(0,0,0,0,0,0)|Nodes]].
  % but there are two exceptions ! ('true' and 'false')
  % therefore we keep both and use an extra trim pass.
  Res = node(Constructor1,Constructor2,pos(0,0,0,0),Nodes).
evalReduction(head(E),Res):-!,
  evalReduction(E,[Res]).
evalReduction(_,_):-throw(parserBug('cannot eval reduction')).

reduceList([],[]).
reduceList([H|T],[H2|T2]) :-
  evalReduction(H,H2),
  reduceList(T,T2).

mapTokenIDs([],[(EOF_ID/'dummy eof token')]):-eof_token_id(EOF_ID).
mapTokenIDs([(TokenID/TokenString)|Rest],[(NewID/TokenString)|R]) :-
  token(TokenID,_,just(NewID)),!,
  mapTokenIDs(Rest,R).
mapTokenIDs([(TokenID/_)|Rest],R) :-
  token(TokenID,_,nothing),!,
  mapTokenIDs(Rest,R).

printTokens([]).
printTokens([(TokenID/TokenString)|Rest]) :-
  format("tokenID :"),
  write(TokenID),
  format(" TokenString "),
  format('~s',[TokenString]),nl,
  printTokens(Rest).

lexerLoop([],_,Acc,Res):- reverse(Acc,Res).
lexerLoop(Input,Mode/Nest,Acc,Res) :-
  checkState(left('error:no token recognized'),state_0/Mode,Input,[],NextToken),!,
  lexerLoop2(Mode/Nest,Acc,NextToken,Res).

lexerLoop2(ModeNest,Acc,right(NewInput,TokenString,TokenID),Res) :-
  updateMode(ModeNest,TokenID,NewModeNest),
  lexerLoop(NewInput,NewModeNest,[TokenID/TokenString|Acc],Res).
lexerLoop2(_ModeNest,_Acc,left(Err),_Res) :- throw(Err).

scanChar(_,_,[],_,_Res) :- throw('internalLexerError').
scanChar(LastAcceptedToken,State/Mode,[H|Rest],Acc,Res) :-
  transition(State,Mode,ITable),
  lookupInterval(H,ITable,NextState),
  scanChar2(NextState,LastAcceptedToken,State/Mode,[H|Rest],Acc,Res).

scanChar2(nothing,LastAcceptedToken,_,_,_,LastAcceptedToken).
scanChar2(just(epsilon(NewState)),LastAcceptedToken,_/Mode,[H|Rest],Acc,Res):-
  scanChar(LastAcceptedToken,NewState/Mode,[H|Rest],Acc,Res).

scanChar2(just(notEpsilon(NewState)),LastAcceptedToken,_/Mode,[H|Rest],Acc,Res):-
  checkState(LastAcceptedToken,NewState/Mode,Rest,[H|Acc],Res).


checkState(LastAcceptedToken,State/Mode,Input,Acc,Res) :-
  accepts(State,Mode,Accept),!,
  checkState2(Accept,LastAcceptedToken,State/Mode,Input,Acc,Res).

checkState2(just(TokenID),_LastAcceptedToken,_,[],Acc,right([],Seen,TokenID)) :- !,
  reverse(Acc,Seen).

checkState2(nothing,LastAcceptedToken,_,[],_Seen,LastAcceptedToken).

checkState2(just(TokenID),_LastAcceptedToken,State/Mode,Input,Acc,Res) :- !,
  reverse(Acc,Seen),
  scanChar(right(Input,Seen,TokenID),State/Mode,Input,Acc,Res).

checkState2(nothing,LastAcceptedToken,State/Mode,Input,Acc,Res) :- !,
  scanChar(LastAcceptedToken,State/Mode,Input,Acc,Res).

lookupInterval(_,leaf,nothing).
lookupInterval(Char,node(LowTree,LowChar,_,_,_),Res) :-
  Char < LowChar, ! , lookupInterval(Char,LowTree,Res).
lookupInterval(Char,node(_,_,_,HighChar,HighTree),Res) :-
  Char > HighChar, ! , lookupInterval(Char,HighTree,Res).
lookupInterval(Char,node(_,LowChar,State,HighChar,_),just(State)) :-
  Char =< HighChar, Char >= LowChar.

%
% hardcoded token IDs :
% token(token_0, 'TComment', nothing).
% token(token_1, 'TCommentEnd', nothing).
%


updateMode(Mode/Nest,TokenID,Res) :-
  modeTransition(TokenID, Mode,TMode),
  updateMode2(TMode/Nest, TokenID, Res).

updateMode2(Mode/Nest, token_0,Res) :- !,
  NewNest is Nest + 1,
  updateMode3(Mode/NewNest, token_0,Res).

updateMode2(Mode/Nest, token_1,Res) :- !,
  NewNest is Nest - 1,
  updateMode3(Mode/NewNest, token_1,Res).

updateMode2(ModeNest,Token,Res) :- updateMode3(ModeNest,Token,Res).

updateMode3(_/0,token_1,mode_0/0):- !.
updateMode3(ModeNest,_,ModeNest).