]> gerrit.simantics Code Review - simantics/platform.git/blob - bundles/org.simantics.scl.compiler/src/org/simantics/scl/compiler/parser/grammar/input/GrammarParserImpl.java
Moved SCL parser generator to platform repository.
[simantics/platform.git] / bundles / org.simantics.scl.compiler / src / org / simantics / scl / compiler / parser / grammar / input / GrammarParserImpl.java
1 package org.simantics.scl.compiler.parser.grammar.input;
2
3 import java.io.IOException;
4 import java.io.InputStream;
5 import java.io.InputStreamReader;
6 import java.io.Reader;
7 import java.util.ArrayList;
8
9 import org.simantics.scl.compiler.parser.grammar.Grammar;
10 import org.simantics.scl.compiler.parser.grammar.Production;
11 import org.simantics.scl.compiler.parser.regexp.RAtom;
12 import org.simantics.scl.compiler.parser.regexp.Regexp;
13
14 import gnu.trove.list.array.TIntArrayList;
15 import gnu.trove.map.hash.TIntByteHashMap;
16 import gnu.trove.map.hash.TObjectIntHashMap;
17
18 public class GrammarParserImpl extends GrammarParser {
19     private final GrammarLexer lexer;
20     
21     ArrayList<String> terminals = new ArrayList<String>();
22     ArrayList<String> nonterminals = new ArrayList<String>();
23     TObjectIntHashMap<String> symbols = new TObjectIntHashMap<String>();
24     ArrayList<Production> productions = new ArrayList<Production>();
25     TIntArrayList initials = new TIntArrayList();
26
27     public GrammarParserImpl(Reader reader) {
28         lexer = new GrammarLexer(reader);
29     }
30     
31     private int getId(String symbol) {
32         if(symbols.contains(symbol))
33             return symbols.get(symbol);
34         int id;
35         if(Character.isUpperCase(symbol.charAt(0))) {
36             id = terminals.size();
37             terminals.add(symbol);
38         }
39         else {
40             id = ~nonterminals.size();
41             nonterminals.add(symbol);
42         }
43         symbols.put(symbol, id);
44         return id;
45     }
46     
47     @Override
48     protected Token nextToken() {
49         try {
50             Token token = lexer.nextToken();
51             return token;
52         } catch(Exception e) {
53             if(e instanceof RuntimeException)
54                 throw (RuntimeException)e;
55             else
56                 throw new RuntimeException(e);
57         }
58     }
59
60     @Override
61     protected RuntimeException syntaxError(Token token, String description) {
62         return new RuntimeException(description);
63     }
64
65     @Override
66     protected Object reduceFile() {
67         return null;
68     }
69
70     @Override
71     protected Object reduceProduction() {
72         int lhs = getId(((Token)get(0)).text);
73         for(int i=2;i<length();i+=2) {
74             Production prod = (Production)get(i);
75             prod.lhs = lhs;
76             productions.add(prod);
77         }
78         return null;
79     }
80
81     @Override
82     protected Object reduceInitial() {
83         initials.add(getId(((Token)get(1)).text));
84         return null;
85     }
86     
87     @Override
88     protected Object reduceTerminal() {
89         return new RAtom(getId(((Token)get(0)).text));
90     }
91
92     private static Regexp postOp(Regexp regexp, Token op) {
93         switch(op.id) {
94         case GrammarTerminals.STAR: return Regexp.star(regexp);
95         case GrammarTerminals.PLUS: return Regexp.plus(regexp);
96         case GrammarTerminals.OPTIONAL: return Regexp.optional(regexp);
97         default: throw new IllegalStateException();
98         }
99     }
100
101     @Override
102     protected Object reduceConcatenation() {
103         ArrayList<Regexp> regexps = new ArrayList<Regexp>(length());
104         for(int i=0;i<length();++i) {
105             Object obj = get(i);
106             if(obj instanceof Regexp)
107                 regexps.add((Regexp)obj);
108             else {
109                 Token token = (Token)obj;
110                 Regexp regexp = regexps.remove(regexps.size()-1);
111                 regexps.add(postOp(regexp, token));
112             }
113         }
114         return Regexp.seq(regexps.toArray(new Regexp[regexps.size()]));
115     }
116     
117     @Override
118     protected Object reduceUnion() {
119         Regexp[] regexps = new Regexp[length()/2];
120         for(int i=1;i<length();i+=2)
121             regexps[i/2] = (Regexp)get(i);
122         return Regexp.or(regexps);
123     }
124     
125     @Override
126     protected Object reduceProductionRhs() {
127         Regexp rhs = (Regexp)get(0);
128         String name = ((Token)get(2)).text;
129         TIntByteHashMap annotations = new TIntByteHashMap();
130         for(int i=4;i<length();i+=3) {
131             Token type = (Token)get(i);
132             int id = getId(((Token)get(i+1)).text);
133             annotations.put(id, (byte)(type.id == GrammarTerminals.SHIFT ? 0 : 1));
134         }
135         return new Production(name, 0, rhs, annotations);
136     }
137
138     public Grammar getGrammar() {
139         return new Grammar(
140                 productions.toArray(new Production[productions.size()]),
141                 terminals.toArray(new String[terminals.size()]),
142                 nonterminals.toArray(new String[nonterminals.size()]),
143                 initials.toArray()
144                 );
145     }
146
147     public static Grammar read(InputStream inputStream) throws IOException {
148         GrammarParserImpl parser = new GrammarParserImpl(new InputStreamReader(inputStream, "UTF-8"));
149         parser.parseFile();
150         return parser.getGrammar();
151     }
152 }