$ template make_parser() $ $ output $basedir + '/parser.cs' /* This file was generated by SableCC (http://www.sablecc.org/). */ using System; using System.Collections; using System.Text; using System.IO; using @package.node; using @package.lexer; using @package.analysis; namespace @package.parser { $ // generate the ParserException class public class ParserException : ApplicationException { Token token; public ParserException(Token token, String message) : base(message) { this.token = token; } public Token Token { get { return token; } } } $ // generate the State class internal class State { internal int state; internal ArrayList nodes; internal State(int state, ArrayList nodes) { this.state = state; this.nodes = nodes; } } $ // generate the TokenIndex class internal class TokenIndex : AnalysisAdapter { internal int index; $ foreach {//token[@parser_index]} public override void Case@ename(@ename node) { index = @parser_index; } $ end foreach public override void CaseEOF(EOF node) { index = ${tokens/eof/@parser_index}; } } $ // generate the Parser class public class Parser { private Analysis ignoredTokens = new AnalysisAdapter(); public Analysis IgnoredTokens { get { return ignoredTokens; } } protected ArrayList nodeList; private Lexer lexer; private Stack stack = new Stack(); private int last_shift; private int last_pos; private int last_line; private Token last_token; private TokenIndex converter = new TokenIndex(); private int[] action = new int[2]; private const int SHIFT = 0; private const int REDUCE = 1; private const int ACCEPT = 2; private const int ERROR = 3; public Parser(Lexer lexer) { this.lexer = lexer; } private int GoTo(int index) { int state = State(); int low = 1; int high = gotoTable[index].Length - 1; int value = gotoTable[index][0][1]; while(low <= high) { int middle = (low + high) / 2; if(state < gotoTable[index][middle][0]) { high = middle - 1; } else if(state > gotoTable[index][middle][0]) { low = middle + 1; } else { value = gotoTable[index][middle][1]; break; } } return value; } private void Push(int numstate, ArrayList listNode) { this.nodeList = listNode; stack.Push(new State(numstate, this.nodeList)); } private int State() { State s = (State) stack.Peek(); return s.state; } private ArrayList Pop() { return (ArrayList) ((State) stack.Pop()).nodes; } private int Index(Switchable token) { converter.index = -1; token.Apply(converter); return converter.index; } public Start Parse() { Push(0, null); IList ign = null; while(true) { while(Index(lexer.Peek()) == -1) { if(ign == null) { ign = new TypedList(NodeCast.Instance); } ign.Add(lexer.Next()); } if(ign != null) { ignoredTokens.SetIn(lexer.Peek(), ign); ign = null; } last_pos = lexer.Peek().Pos; last_line = lexer.Peek().Line; last_token = lexer.Peek(); int index = Index(lexer.Peek()); action[0] = actionTable[State()][0][1]; action[1] = actionTable[State()][0][2]; int low = 1; int high = actionTable[State()].Length - 1; while(low <= high) { int middle = (low + high) / 2; if(index < actionTable[State()][middle][0]) { high = middle - 1; } else if(index > actionTable[State()][middle][0]) { low = middle + 1; } else { action[0] = actionTable[State()][middle][1]; action[1] = actionTable[State()][middle][2]; break; } } switch(action[0]) { case SHIFT: { ArrayList list = new ArrayList(); list.Add(lexer.Next()); Push(action[1], list); last_shift = action[1]; } break; case REDUCE: switch(action[1]) { $ foreach {rules/rule} case @index: { ArrayList list = New@index(); Push(GoTo(@leftside), list); } break; $ end foreach } break; case ACCEPT: { EOF node2 = (EOF) lexer.Next(); ${/parser/productions/production/@ename} node1 = (${/parser/productions/production/@ename}) ((ArrayList)Pop())[0]; Start node = new Start(node1, node2); return node; } case ERROR: throw new ParserException(last_token, "[" + last_line + "," + last_pos + "] " + errorMessages[errors[action[1]]]); } } } $ foreach {rules/rule} ArrayList New@index() { ArrayList nodeList = new ArrayList(); $ foreach {action} $ choose $ when {@cmd='POP'} ArrayList @result = (ArrayList) Pop(); $ end $ when {@cmd='FETCHLIST'} TypedList @result = (TypedList)@from[@index]; $ end $ when {@cmd='FETCHNODE'} @etype @result = (@etype)@from[@index]; $ end $ when {@cmd='ADDNODE'} if ( @node != null ) { @tolist.Add(@node); } $ end $ when {@cmd='ADDLIST'} if ( @fromlist != null ) { @tolist.AddAll(@fromlist); } $ end $ when {@cmd='MAKELIST'} TypedList @result = new TypedList(); $ end $ when {@cmd='MAKENODE'} @etype @result = new @etype ( $ foreach {arg} $ if @null null[-sep ','-] $ else ${.}[-sep ','-] $ end if $ end foreach ); $ end $ when {@cmd='RETURNNODE'} $ if @null nodeList.Add(null); $ else nodeList.Add(@node); $ end $ end $ when {@cmd='RETURNLIST'} nodeList.Add(@list); $ end $ end choose $ end foreach return nodeList; } $ end foreach private static int[][][] actionTable = { $ foreach {parser_data/action_table/row} new int[][] { $ foreach {action} new int[] {@from, @action, @to}, $ end foreach }, $ end foreach }; private static int[][][] gotoTable = { $ foreach {parser_data/goto_table/row} new int[][] { $ foreach {goto} new int[] {@from, @to}, $ end foreach }, $ end foreach }; private static String[] errorMessages = { $ foreach {parser_data/error_messages/msg} "${sablecc:escape_string_literal(string(.))}", $ end }; private static int[] errors = { [-foreach {parser_data/errors/i}-]${.}, [-end-] }; } } $ end output $ end template