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