
jlibs.nblr.codegen.State Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of jlibs-nblr Show documentation
Show all versions of jlibs-nblr Show documentation
Non-Blocking Language Recognition
/**
* Copyright 2015 Santhosh Kumar Tekuri
*
* The JLibs authors license this file to you under the Apache License,
* version 2.0 (the "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at:
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
* License for the specific language governing permissions and limitations
* under the License.
*/
package jlibs.nblr.codegen;
import jlibs.core.annotation.processing.Printer;
import jlibs.core.lang.ArrayUtil;
import jlibs.core.lang.ImpossibleException;
import jlibs.core.lang.StringUtil;
import jlibs.core.util.Range;
import jlibs.nblr.codegen.java.SyntaxClass;
import jlibs.nblr.matchers.Matcher;
import jlibs.nblr.rules.Node;
import jlibs.nblr.rules.Path;
import jlibs.nblr.rules.Routes;
import java.util.ArrayList;
import java.util.Collections;
import java.util.LinkedHashSet;
import java.util.List;
import static jlibs.core.annotation.processing.Printer.MINUS;
import static jlibs.core.annotation.processing.Printer.PLUS;
/**
* @author Santhosh Kumar T
*/
public class State{
public final RuleMethod ruleMethod;
public Node fromNode;
public final List decisions = new ArrayList();
public final RootIf rootIF = new RootIf(this);
public final List ifBlocks = rootIF.children;
public State(RuleMethod ruleMethod, Node fromNode){
this.ruleMethod = ruleMethod;
this.fromNode = fromNode;
Routes routes = new Routes(ruleMethod.rule, fromNode, true);
if(routes.toString().endsWith("[)]"))
System.out.print("");
for(int lookAhead: routes.lookAheads())
processLookAhead(routes.determinateRoutes(lookAhead));
// move loop without fallback to the beginning
for(Decision decision: decisions){
if(decision.usesFinishAll()){
ruleMethod.syntaxClass.addToFinishAll(decision.matchers[0]);
decisions.remove(decision);
decisions.add(0, decision);
break;
}
}
if(routes.indeterminateRoute!=null)
decisions.add(new Decision(this, routes.indeterminateRoute.route()[0]));
if(routes.routeStartingWithEOF!=null)
decisions.add(new Decision(this, routes.routeStartingWithEOF));
optimize();
populateIfBlocks();
}
private void processLookAhead(List routes){
processLookAhead(routes, 1);
}
private void processLookAhead(List routes, int depth){
List> groups = new ArrayList>();
Matcher matcher = null;
for(Path route: routes){
Path path = route.route()[depth-1];
Matcher curMatcher = path.matcher();
if(curMatcher==null)
curMatcher = eofMatcher;
if(matcher==null || !curMatcher.same(matcher)){
groups.add(new ArrayList());
matcher = curMatcher;
}
groups.get(groups.size()-1).add(route);
}
for(List group: groups){
Path route = group.get(0);
if(depth> lists = new ArrayList>();
for(int i=decisions.size()-1; i>=0; i--){
Decision decision = decisions.get(i);
if(decision.path.matcher()==null && isCandidate(decision)){
boolean listFound = false;
for(List list: lists){
if(decision.path.equals(list.get(0).path)){
listFound = true;
list.add(decision);
break;
}
}
if(!listFound){
List newList = new ArrayList();
newList.add(decision);
lists.add(newList);
}
}
}
if(lists.size()==0)
return;
if(decisions.get(decisions.size()-1).matchers[0]==null){
Decision lastDecision = decisions.get(decisions.size()-1);
for(List list: lists){
if(list.get(0).path.equals(lastDecision.path)){
lists.clear();
lists.add(list);
break;
}
}
}
List preferredList = lists.get(0);
for(int i=1; i list = lists.get(i);
if(list.size()>preferredList.size())
preferredList = list;
}
Decision preferredDecision = preferredList.get(0);
if(preferredList.size()==1 && preferredDecision.matchers.length statesVisited, LinkedHashSet statesPending){
for(Decision decision: decisions)
decision.computeNextStates(statesVisited, statesPending);
}
private void populateIfBlocks(){
List> lists = new ArrayList>();
int lastLen = 0;
for(Decision decision: decisions){
IfBlock curIf = null;
if(lastLen!=decision.matchers.length){
lists.add(new ArrayList());
lastLen = decision.matchers.length;
}
for(Matcher matcher: decision.matchers){
List children = curIf==null ? lists.get(lists.size()-1) : curIf.children;
IfBlock found = null;
if(matcher!=null){
for(IfBlock child: children){
if(matcher.same(child.matcher)){
found = child;
break;
}
}
}
if(found==null){
found = new IfBlock(this);
found.matcher = matcher;
children.add(found);
found.parent = curIf;
}
curIf = found;
}
curIf.path = decision.path;
}
for(List list: lists)
rootIF.children.addAll(list);
rootIF.computeCommon();
}
public boolean readCodePoint(){
for(Decision decision: decisions){
if(decision.readCodePoint())
return true;
}
return false;
}
public boolean readCharacter(){
for(Decision decision: decisions){
if(!decision.readCharacter())
return false;
}
return true;
}
public boolean matchesNewLine(){
for(Decision decision: decisions){
if(decision.matchesNewLine())
return true;
}
return false;
}
public String expected(){
StringBuilder builder = new StringBuilder();
for(Decision decision: decisions){
if(builder.length()>0)
builder.append(" OR ");
builder.append(decision.expected());
}
return builder.toString();
}
public boolean requiresContinue(State nextState){
for(Decision decision: decisions){
if(decision.requiresContinue(nextState))
return true;
}
return false;
}
public int maxLookAhead(){
int maxLookAhead = 0;
for(Decision decision: decisions)
maxLookAhead = Math.max(maxLookAhead, decision.matchers.length);
return maxLookAhead;
}
public boolean lookAheadRequired(){
return maxLookAhead()>1;
}
public String readMethod(){
if(!lookAheadRequired() && readCharacter() && !matchesNewLine())
return "position==limit ? marker : input[position]";
else
return "codePoint()";
}
public String breakStatement(){
return ruleMethod.requiresWhile() ? "break loop;" : "break;";
}
public void generate(Printer printer, State nextState){
printer.printlns(
"case "+fromNode.stateID+":",
PLUS
);
rootIF.generate(printer, nextState);
printer.printlns(
MINUS
);
}
public void generate1(Printer printer, State nextState){
printer.printlns(
"case "+fromNode.stateID+":",
PLUS
);
if(readCodePoint() && (!decisions.get(0).usesFinishAll() || lookAheadRequired())){
printer.printlns(
"if((ch="+readMethod()+")==EOC)"+(SyntaxClass.DEBUGGABLE ? "{" : ""),
PLUS
// "exiting(RULE_"+ruleMethod.rule.name.toUpperCase()+", "+fromNode.stateID+");"
);
if(SyntaxClass.DEBUGGABLE)
printer.println("handler.currentNode("+ruleMethod.rule.id+", "+fromNode.stateID+");");
printer.println(breakStatement());
printer.printlns(
// "return false;",
MINUS,
SyntaxClass.DEBUGGABLE ? "}" : null
);
}
boolean lookAheadReqd = lookAheadRequired();
int lastLookAhead = 0;
int elseAfterDecision = 1;
int lastDecisionAction = Decision.ADD_CONTINUE;
boolean closeLALengthCheck = false;
for(int i=0; ilastLookAhead){
elseAfterDecision = 1;
lastDecisionAction = Decision.ADD_CONTINUE;
if(decision.usesFinishAll())
elseAfterDecision = 2;
if(lookAheadReqd){
if(curLookAhead>1){
if(lastLookAhead<=1){
printer.println("addToLookAhead(ch);");
lastLookAhead = 1;
}
String prefix, condition;
if(curLookAhead==lastLookAhead+1){
prefix = "if";
condition = "ch!=EOF";
}else{
prefix = "while";
condition = "ch!=EOF && laLen<"+curLookAhead;
}
printer.printlns(
prefix+"("+condition+"){",
PLUS,
"if((ch=codePoint())==EOC)",
PLUS,
breakStatement(),
MINUS,
"addToLookAhead(ch);",
MINUS,
"}"
);
}
closeLALengthCheck = true;
if(curLookAhead>1){
printer.printlns(
"if(laLen=="+curLookAhead+"){",
PLUS
);
}
}
}
boolean closeBlock = false;
if(!lookAheadReqd && (elseAfterDecision<=0 || lastDecisionAction==Decision.GOTO_NEXT_CASE || lastDecisionAction==Decision.CALL_RULE_AND_NEXT_DECISION)){
printer.print("else ");
if(decision.matchers[0]==null){
closeBlock = true;
printer.printlns(
"{",
PLUS
);
}
}
if(decision.usesFinishAll())
decision.generate(printer, nextState);
else{
Decision prevDecision = i==0 ? null : decisions.get(i-1);
int common = common(prevDecision, decision);
for(int j=common; j1){
printer.printlns(
MINUS,
"}"
);
}
}
lastLookAhead = curLookAhead;
elseAfterDecision--;
lastDecisionAction = decision.returnAction(nextState);
}
Decision lastDecision = decisions.get(decisions.size()-1);
if(lastDecision.matchers[0]!=null){
if(!lookAheadReqd)
printer.print("else ");
printer.println("expected(ch, \""+ StringUtil.toLiteral(expected(), false)+"\");");
}
printer.printlns(
MINUS
);
}
private int common(Decision decision1, Decision decision2){
if(decision1==null || decision2==null)
return 0;
if(decision1.matchers.length!=decision2.matchers.length)
return 0;
if(decision1.usesFinishAll())
return 0;
for(int i=0; i ranges(){
return Collections.emptyList();
}
};
}
© 2015 - 2025 Weber Informatics LLC | Privacy Policy