move parser code from grammar to src/magic/grammar
parent
e6f09e1d07
commit
6acc44d88a
24
Makefile
24
Makefile
|
@ -447,3 +447,27 @@ support/ui:
|
|||
wiki/UpcomingCards.wiki: cards/new.txt
|
||||
echo "#summary New cards in the next release" > $@
|
||||
cat <(echo "{{{") $^ <(echo "}}}") >> $@
|
||||
|
||||
parser/test: $(MAG) grammar/parsable.txt
|
||||
$(JAVA) magic.grammar.Check < $(word 2,$^)
|
||||
|
||||
parser/test_all: $(MAG) grammar/rules.txt
|
||||
$(JAVA) magic.grammar.Check < $(word 2,$^)
|
||||
|
||||
parser/run: $(MAG)
|
||||
$(JAVA) magic.grammar.Check
|
||||
|
||||
grammar/parsable.txt: grammar/mtg.peg
|
||||
make parser/test_all > grammar/test_all.out
|
||||
cat grammar/test_all.out | grep PARSED | sed 's/PARSED: //' | sort | uniq > $@
|
||||
cat grammar/test_all.out | grep FAILED | sort | uniq -c | sort -n > grammar/failed.txt
|
||||
|
||||
src/magic/grammar/MagicRuleParser.java: grammar/mtg.peg
|
||||
java -cp lib/Mouse-1.5.1.jar mouse.Generate -M -G $^ -P MagicRuleParser -S MagicSyntaxTree -p magic.grammar -r magic.grammar
|
||||
mv MagicRuleParser.java $@
|
||||
sed -i 's/accept()/sem.action() \&\& accept()/g' $@
|
||||
|
||||
grammar/CounterType: grammar/rules.txt
|
||||
grep -o "[^ ]* counter \(on\|from\)" $@ | cut -d' ' -f1 | sort | uniq > $@
|
||||
# remove a, each, that
|
||||
# add poison
|
||||
|
|
|
@ -1,4 +1,6 @@
|
|||
import mouse.runtime.SourceString;
|
||||
package magic.grammar;
|
||||
|
||||
import magic.grammar.SourceString;
|
||||
import java.util.Scanner;
|
||||
|
||||
class Check {
|
|
@ -0,0 +1,57 @@
|
|||
//=========================================================================
|
||||
//
|
||||
// Part of PEG parser generator Mouse.
|
||||
//
|
||||
// Copyright (C) 2009 by Roman R. Redziejowski (www.romanredz.se).
|
||||
//
|
||||
// Licensed 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.
|
||||
//
|
||||
//-------------------------------------------------------------------------
|
||||
//
|
||||
// Change log
|
||||
// 090701 License changed by the author to Apache v.2.
|
||||
// 090717 Name changed from 'Parser' to 'CurrentRule'.
|
||||
//
|
||||
//=========================================================================
|
||||
|
||||
package magic.grammar;
|
||||
|
||||
|
||||
//HHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHH
|
||||
//
|
||||
// Current Rule seen by a semantic action
|
||||
//
|
||||
//HHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHH
|
||||
|
||||
public interface CurrentRule
|
||||
{
|
||||
//-------------------------------------------------------------------
|
||||
// Left-hand side.
|
||||
//-------------------------------------------------------------------
|
||||
Phrase lhs();
|
||||
|
||||
//-------------------------------------------------------------------
|
||||
// Number of right-hand side items.
|
||||
//-------------------------------------------------------------------
|
||||
int rhsSize();
|
||||
|
||||
//-------------------------------------------------------------------
|
||||
// i-th item on the right-hand side.
|
||||
//-------------------------------------------------------------------
|
||||
Phrase rhs(int i);
|
||||
|
||||
//-------------------------------------------------------------------
|
||||
// String represented by right-hand side items i through j-1.
|
||||
//-------------------------------------------------------------------
|
||||
String rhsText(int i,int j);
|
||||
}
|
File diff suppressed because it is too large
Load Diff
|
@ -1,4 +1,6 @@
|
|||
class MagicSyntaxTree extends mouse.runtime.SemanticsBase {
|
||||
package magic.grammar;
|
||||
|
||||
class MagicSyntaxTree extends magic.grammar.SemanticsBase {
|
||||
Node tree;
|
||||
boolean action() {
|
||||
final Node node = new Node();
|
|
@ -1,3 +1,5 @@
|
|||
package magic.grammar;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.LinkedList;
|
||||
|
|
@ -0,0 +1,758 @@
|
|||
//=========================================================================
|
||||
//
|
||||
// Part of PEG parser generator Mouse.
|
||||
//
|
||||
// Copyright (C) 2009, 2010, 2011, 2012
|
||||
// by Roman R. Redziejowski (www.romanredz.se).
|
||||
//
|
||||
// Licensed 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.
|
||||
//
|
||||
//-------------------------------------------------------------------------
|
||||
//
|
||||
// Change log
|
||||
// 090720 Created for Mouse 1.1.
|
||||
// Version 1.2
|
||||
// 100320 Bug fix in accept(): upgrade error info on success.
|
||||
// 100320 Bug fix in rejectNot(): backtrack before registering failure.
|
||||
// Version 1.3
|
||||
// 100429 Bug fix in errMerge(Phrase): assignment to errText replaced
|
||||
// by clear + addAll (assignment produced alias resulting in
|
||||
// explosion of errText in memo version).
|
||||
// 101105 Changed errMerge(msg,pos) to errAdd(who).
|
||||
// 101105 Commented error handling.
|
||||
// 101129 Added 'boolReject'.
|
||||
// 101203 Convert result of 'listErr' to printable.
|
||||
// Version 1.4
|
||||
// 110918 Changed 'listErr' to separate 'not' texts as 'not expected'.
|
||||
// 111004 Added methods to implement ^[s].
|
||||
// 111004 Implemented method 'where' of Phrase.
|
||||
// Version 1.5
|
||||
// 111027 Revised methods for ^[s] and ^[c].
|
||||
// 111104 Implemented methods 'rule' and 'isTerm' of Phrase.
|
||||
// Version 1.5.1
|
||||
// 120102 (Steve Owens) Ensure failure() method does not emit blank
|
||||
// line when error info is absent.
|
||||
//
|
||||
//=========================================================================
|
||||
|
||||
package magic.grammar;
|
||||
|
||||
import magic.grammar.Source;
|
||||
import java.util.Vector;
|
||||
|
||||
|
||||
//HHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHH
|
||||
//
|
||||
// ParserBase
|
||||
//
|
||||
//HHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHH
|
||||
|
||||
|
||||
public class ParserBase implements magic.grammar.CurrentRule
|
||||
{
|
||||
//-------------------------------------------------------------------
|
||||
// Input
|
||||
//-------------------------------------------------------------------
|
||||
Source source; // Source of text to parse
|
||||
int endpos; // Position after the end of text
|
||||
int pos; // Current position in the text
|
||||
|
||||
//-------------------------------------------------------------------
|
||||
// Semantics (base)
|
||||
//-------------------------------------------------------------------
|
||||
protected magic.grammar.SemanticsBase sem;
|
||||
|
||||
//-------------------------------------------------------------------
|
||||
// Trace string.
|
||||
//-------------------------------------------------------------------
|
||||
protected String trace = "";
|
||||
|
||||
//-------------------------------------------------------------------
|
||||
// Current phrase (top of parse stack).
|
||||
//-------------------------------------------------------------------
|
||||
Phrase current = null;
|
||||
|
||||
//-------------------------------------------------------------------
|
||||
// Constructor
|
||||
//-------------------------------------------------------------------
|
||||
protected ParserBase()
|
||||
{}
|
||||
|
||||
//-------------------------------------------------------------------
|
||||
// Initialize parsing
|
||||
//-------------------------------------------------------------------
|
||||
public void init(Source src)
|
||||
{
|
||||
source = src;
|
||||
pos = 0;
|
||||
endpos = source.end();
|
||||
current = new Phrase("","",0); // Dummy bottom of parse stack
|
||||
}
|
||||
|
||||
//-------------------------------------------------------------------
|
||||
// Implementation of Parser interface CurrentRule
|
||||
//-------------------------------------------------------------------
|
||||
public Phrase lhs()
|
||||
{ return current; }
|
||||
|
||||
public Phrase rhs(int i)
|
||||
{ return current.rhs.elementAt(i); }
|
||||
|
||||
public int rhsSize()
|
||||
{ return current.rhs.size(); }
|
||||
|
||||
public String rhsText(int i,int j)
|
||||
{ return source.at(rhs(i).start,rhs(j-1).end); }
|
||||
|
||||
//-------------------------------------------------------------------
|
||||
// Set trace
|
||||
//-------------------------------------------------------------------
|
||||
public void setTrace(String trace)
|
||||
{
|
||||
this.trace = trace;
|
||||
sem.trace = trace;
|
||||
}
|
||||
|
||||
//-------------------------------------------------------------------
|
||||
// Print final error message (if not caught otherwise).
|
||||
//-------------------------------------------------------------------
|
||||
protected boolean failure()
|
||||
{
|
||||
if (current.errPos>=0)
|
||||
System.out.println(current.errMsg());
|
||||
return false;
|
||||
}
|
||||
|
||||
//=====================================================================
|
||||
//
|
||||
// Methods called from parsing procedures
|
||||
//
|
||||
//=====================================================================
|
||||
//-------------------------------------------------------------------
|
||||
// Initialize processing of a nonterminal
|
||||
//-------------------------------------------------------------------
|
||||
protected void begin(final String name)
|
||||
{
|
||||
Phrase p = new Phrase(name,name,pos);
|
||||
p.parent = current;
|
||||
current = p;
|
||||
}
|
||||
|
||||
protected void begin(final String name,final String diag)
|
||||
{
|
||||
Phrase p = new Phrase(name,diag,pos);
|
||||
p.parent = current;
|
||||
current = p;
|
||||
}
|
||||
|
||||
//-------------------------------------------------------------------
|
||||
// Accept Rule
|
||||
// Note: 'upgrade error info' is applied when rule such as
|
||||
// R = A/B/C/... or R = (A/B/C/...)* consumed empty string after one
|
||||
// or more of A,B,C failed without advancing cursor.
|
||||
// In case of a later failure, it gives message 'expected R',
|
||||
// which is not strictly correct because R succeeded, but is
|
||||
// more comprehensible than 'expected A or B or C or ...'.
|
||||
//-------------------------------------------------------------------
|
||||
protected boolean accept()
|
||||
{
|
||||
Phrase p = pop(); // Pop p from compile stack
|
||||
p.rhs = null; // Remove right-hand side of p
|
||||
if (p.errPos==p.start) // Upgrade error info of p
|
||||
p.errSet(p.diag,p.start);
|
||||
p.success = true; // Indicate p successful
|
||||
current.end = pos; // Update end of parent
|
||||
current.rhs.add(p); // Attach p to rhs of parent
|
||||
current.errMerge(p); // Merge error info with parent
|
||||
return true;
|
||||
}
|
||||
|
||||
//-------------------------------------------------------------------
|
||||
// Accept Inner
|
||||
//-------------------------------------------------------------------
|
||||
protected boolean acceptInner()
|
||||
{
|
||||
Phrase p = pop(); // Pop p from compile stack
|
||||
p.success = true; // Indicate p successful
|
||||
current.end = pos; // Update end of parent
|
||||
current.rhs.addAll(p.rhs); // Add rhs of p to rhs of parent
|
||||
current.errMerge(p); // Merge error info with parent
|
||||
return true;
|
||||
}
|
||||
|
||||
//-------------------------------------------------------------------
|
||||
// Accept And-predicate (argument was accepted)
|
||||
// Note: we ignore all failures encountered in processing the argument.
|
||||
//-------------------------------------------------------------------
|
||||
protected boolean acceptAnd()
|
||||
{
|
||||
Phrase p = pop(); // Pop p from compile stack
|
||||
p.end = p.start; // Reset end of P
|
||||
p.rhs = null; // Remove right-hand side of p
|
||||
p.errClear(); // Remove error info from p
|
||||
p.success = true; // Indicate p successful
|
||||
pos = p.start; // Backtrack to start of p
|
||||
return true;
|
||||
}
|
||||
|
||||
//-------------------------------------------------------------------
|
||||
// Accept Not-predicate (argument was rejected)
|
||||
// Note: we ignore all failures encountered in processing the argument.
|
||||
//-------------------------------------------------------------------
|
||||
protected boolean acceptNot()
|
||||
{
|
||||
Phrase p = pop(); // Pop p from compile stack
|
||||
p.rhs = null; // Remove right-hand side of p
|
||||
p.errClear(); // Remove error info from p
|
||||
p.success = true; // Indicate p successful
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
|
||||
//-------------------------------------------------------------------
|
||||
// Reject Rule
|
||||
// Note: 'upgrade error info' is applied when rule such as
|
||||
// R = A/B/C/... failed after one or more of A,B,C failed without
|
||||
// advancing cursor. In case of a later failure, it gives message
|
||||
// 'expected R', instead of 'expected A or B or C or ...'.
|
||||
//-------------------------------------------------------------------
|
||||
protected boolean reject()
|
||||
{
|
||||
Phrase p = pop(); // Pop p from compile stack
|
||||
p.end = p.start; // Reset end of p
|
||||
p.rhs = null; // Remove right-hand side of p
|
||||
if (p.errPos==p.start) // Upgrade error info of p
|
||||
p.errSet(p.diag,p.start);
|
||||
p.success = false; // Indicate p failed
|
||||
current.errMerge(p); // Merge error info with parent
|
||||
pos = p.start; // Backtrack to start of p
|
||||
return false;
|
||||
}
|
||||
|
||||
//-------------------------------------------------------------------
|
||||
// Simulate failure after boolean action returned false.
|
||||
// Note: the action was called after the Rule accepted some text.
|
||||
// We ignore all failures encountered in the process
|
||||
// and report failure at the start of the text.
|
||||
//-------------------------------------------------------------------
|
||||
protected boolean boolReject()
|
||||
{
|
||||
pos = current.start; // Backtrack to start
|
||||
current.end = pos; // Reset end
|
||||
current.rhs.clear(); // Clear right-hand side
|
||||
current.errSet(current.diag,pos);// Register failure
|
||||
return false;
|
||||
}
|
||||
|
||||
//-------------------------------------------------------------------
|
||||
// Reject Inner
|
||||
//-------------------------------------------------------------------
|
||||
protected boolean rejectInner()
|
||||
{
|
||||
Phrase p = pop(); // Pop p from compile stack
|
||||
p.end = p.start; // Reset end of p
|
||||
p.rhs = null; // Remove right-hand side of p
|
||||
p.success = false; // Indicate p failed
|
||||
current.errMerge(p); // Merge error info with parent
|
||||
pos = p.start; // Backtrack to start of p
|
||||
return false;
|
||||
}
|
||||
|
||||
//-------------------------------------------------------------------
|
||||
// Reject And-predicate (argument was rejected)
|
||||
// Note: we ignore all failures encountered in processing the argument,
|
||||
// and register failure at the point of call of the predicate.
|
||||
//-------------------------------------------------------------------
|
||||
protected boolean rejectAnd()
|
||||
{
|
||||
Phrase p = pop(); // Pop p from compile stack
|
||||
p.rhs = null; // Remove right-hand side of p
|
||||
p.errSet(p.diag,pos); // Register 'xxx expected'
|
||||
p.success = false; // Indicate p failed
|
||||
current.errMerge(p); // Merge error info with parent
|
||||
return false;
|
||||
}
|
||||
|
||||
//-------------------------------------------------------------------
|
||||
// Reject Not-predicate (argument was accepted)
|
||||
// Note: we ignore all failures encountered in processing the argument,
|
||||
// and register failure at the point of call of the predicate.
|
||||
//-------------------------------------------------------------------
|
||||
protected boolean rejectNot()
|
||||
{
|
||||
Phrase p = pop(); // Pop p from compile stack
|
||||
p.end = p.start; // Reset end of p
|
||||
p.rhs = null; // Remove right-hand side of p
|
||||
pos = p.start; // Backtrack to start of p
|
||||
p.errSet(p.diag,pos); // Register 'xxx not expected'
|
||||
p.success = false; // Indicate p failed
|
||||
current.errMerge(p); // Merge error info with parent
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
//-------------------------------------------------------------------
|
||||
// Execute expression 'c'
|
||||
//-------------------------------------------------------------------
|
||||
protected boolean next(char ch)
|
||||
{
|
||||
if (pos<endpos && source.at(pos)==ch) return consume(1);
|
||||
else return fail("'" + ch + "'");
|
||||
}
|
||||
|
||||
//-------------------------------------------------------------------
|
||||
// Execute expression ^'c'
|
||||
//-------------------------------------------------------------------
|
||||
protected boolean nextNot(char ch)
|
||||
{
|
||||
if (pos<endpos && source.at(pos)!=ch) return consume(1);
|
||||
else return fail("not '" + ch + "'");
|
||||
}
|
||||
|
||||
//-------------------------------------------------------------------
|
||||
// Execute expression &'c', !^'c'
|
||||
//-------------------------------------------------------------------
|
||||
protected boolean ahead(char ch)
|
||||
{
|
||||
if (pos<endpos && source.at(pos)==ch) return true;
|
||||
else return fail("'" + ch + "'");
|
||||
}
|
||||
|
||||
protected boolean aheadNotNot(char ch) // temporary
|
||||
{ return ahead(ch); }
|
||||
|
||||
//-------------------------------------------------------------------
|
||||
// Execute expression !'c', &^'c'
|
||||
//-------------------------------------------------------------------
|
||||
protected boolean aheadNot(char ch)
|
||||
{
|
||||
if (pos<endpos && source.at(pos)==ch) return fail("not '" + ch + "'");
|
||||
else return true;
|
||||
}
|
||||
|
||||
|
||||
//-------------------------------------------------------------------
|
||||
// Execute expression "s"
|
||||
//-------------------------------------------------------------------
|
||||
protected boolean next(String s)
|
||||
{
|
||||
int lg = s.length();
|
||||
if (pos+lg<=endpos && source.at(pos,pos+lg).equals(s)) return consume(lg);
|
||||
else return fail("'" + s + "'");
|
||||
}
|
||||
|
||||
//-------------------------------------------------------------------
|
||||
// Execute expression &"s"
|
||||
//-------------------------------------------------------------------
|
||||
protected boolean ahead(String s)
|
||||
{
|
||||
int lg = s.length();
|
||||
if (pos+lg<=endpos && source.at(pos,pos+lg).equals(s)) return true;
|
||||
else return fail("'" + s + "'");
|
||||
}
|
||||
|
||||
//-------------------------------------------------------------------
|
||||
// Execute expression !"s"
|
||||
//-------------------------------------------------------------------
|
||||
protected boolean aheadNot(String s)
|
||||
{
|
||||
int lg = s.length();
|
||||
if (pos+lg<=endpos && source.at(pos,pos+lg).equals(s)) return fail("not '" + s + "'");
|
||||
else return true;
|
||||
}
|
||||
|
||||
|
||||
//-------------------------------------------------------------------
|
||||
// Execute expression [s]
|
||||
//-------------------------------------------------------------------
|
||||
protected boolean nextIn(String s)
|
||||
{
|
||||
if (pos<endpos && s.indexOf(source.at(pos))>=0) return consume(1);
|
||||
else return fail("[" + s + "]");
|
||||
}
|
||||
|
||||
//-------------------------------------------------------------------
|
||||
// Execute expression ^[s]
|
||||
//-------------------------------------------------------------------
|
||||
protected boolean nextNotIn(String s)
|
||||
{
|
||||
if (pos<endpos && s.indexOf(source.at(pos))<0) return consume(1);
|
||||
else return fail("not [" + s + "]");
|
||||
}
|
||||
|
||||
//-------------------------------------------------------------------
|
||||
// Execute expression &[s], !^[s]
|
||||
//-------------------------------------------------------------------
|
||||
protected boolean aheadIn(String s)
|
||||
{
|
||||
if (pos<endpos && s.indexOf(source.at(pos))>=0) return true;
|
||||
else return fail("[" + s + "]");
|
||||
}
|
||||
|
||||
protected boolean aheadNotNotIn(String s) // temporary
|
||||
{ return aheadIn(s); }
|
||||
|
||||
//-------------------------------------------------------------------
|
||||
// Execute expression ![s], &^[s]
|
||||
//-------------------------------------------------------------------
|
||||
protected boolean aheadNotIn(String s)
|
||||
{
|
||||
if (pos<endpos && s.indexOf(source.at(pos))>=0) return fail("not [" + s + "]");
|
||||
else return true;
|
||||
}
|
||||
|
||||
|
||||
//-------------------------------------------------------------------
|
||||
// Execute expression [a-z]
|
||||
//-------------------------------------------------------------------
|
||||
protected boolean nextIn(char a, char z)
|
||||
{
|
||||
if (pos<endpos && source.at(pos)>=a && source.at(pos)<=z)
|
||||
return consume(1);
|
||||
else return fail("[" + a + "-" + z + "]");
|
||||
}
|
||||
|
||||
//-------------------------------------------------------------------
|
||||
// Execute expression &[a-z]
|
||||
//-------------------------------------------------------------------
|
||||
protected boolean aheadIn(char a, char z)
|
||||
{
|
||||
if (pos<endpos && source.at(pos)>=a && source.at(pos)<=z)
|
||||
return true;
|
||||
else return fail("[" + a + "-" + z + "]");
|
||||
}
|
||||
|
||||
//-------------------------------------------------------------------
|
||||
// Execute expression ![a-z]
|
||||
//-------------------------------------------------------------------
|
||||
protected boolean aheadNotIn(char a, char z)
|
||||
{
|
||||
if (pos<endpos && source.at(pos)>=a && source.at(pos)<=z)
|
||||
return fail("not [" + a + "-" + z + "]");
|
||||
else return true;
|
||||
}
|
||||
|
||||
|
||||
//-------------------------------------------------------------------
|
||||
// Execute expression _
|
||||
//-------------------------------------------------------------------
|
||||
protected boolean next()
|
||||
{
|
||||
if (pos<endpos) return consume(1);
|
||||
else return fail("any character");
|
||||
}
|
||||
|
||||
//-------------------------------------------------------------------
|
||||
// Execute expression &_
|
||||
//-------------------------------------------------------------------
|
||||
protected boolean ahead()
|
||||
{
|
||||
if (pos<endpos) return true;
|
||||
else return fail("any character");
|
||||
}
|
||||
|
||||
//-------------------------------------------------------------------
|
||||
// Execute expression !_
|
||||
//-------------------------------------------------------------------
|
||||
protected boolean aheadNot()
|
||||
{
|
||||
if (pos<endpos) return fail("end of text");
|
||||
else return true;
|
||||
}
|
||||
|
||||
|
||||
//-------------------------------------------------------------------
|
||||
// Pop Phrase from compile stack
|
||||
//-------------------------------------------------------------------
|
||||
private Phrase pop()
|
||||
{
|
||||
Phrase p = current;
|
||||
current = p.parent;
|
||||
p.parent = null;
|
||||
return p;
|
||||
}
|
||||
|
||||
//-------------------------------------------------------------------
|
||||
// Consume terminal
|
||||
//-------------------------------------------------------------------
|
||||
private boolean consume(int n)
|
||||
{
|
||||
Phrase p = new Phrase("","",pos);
|
||||
pos += n;
|
||||
p.end = pos;
|
||||
current.rhs.add(p);
|
||||
current.end = pos;
|
||||
return true;
|
||||
}
|
||||
|
||||
//-------------------------------------------------------------------
|
||||
// Fail
|
||||
//-------------------------------------------------------------------
|
||||
private boolean fail(String msg)
|
||||
{
|
||||
current.errAdd(msg);
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
|
||||
//HHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHH
|
||||
//
|
||||
// Phrase
|
||||
//
|
||||
//HHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHH
|
||||
|
||||
public class Phrase implements magic.grammar.Phrase
|
||||
{
|
||||
//===================================================================
|
||||
//
|
||||
// Data
|
||||
//
|
||||
//===================================================================
|
||||
|
||||
final String name;
|
||||
final String diag;
|
||||
final int start;
|
||||
int end;
|
||||
boolean success;
|
||||
Vector<Phrase> rhs = new Vector<Phrase>(10,10);
|
||||
Object value = null;
|
||||
Phrase parent = null;
|
||||
|
||||
//-----------------------------------------------------------------
|
||||
// Errors encountered in processing of this Phrase.
|
||||
// We keep information about the failure farthest down in text,
|
||||
// and only failure of a rule or a terminal (inner expressions
|
||||
// do not have diagnostic names.
|
||||
// - 'errPos' is position the failure, or -1 if there was none.
|
||||
// - 'errTxt' identifies the expression(s) that failed at 'errPos'.
|
||||
// There may be several such expressions if 'errPos' was reached
|
||||
// on several attempts. The expressions are identified
|
||||
// by their diagnostic names.
|
||||
//-----------------------------------------------------------------
|
||||
int errPos = -1;
|
||||
Vector<String> errTxt = new Vector<String>();
|
||||
|
||||
|
||||
//===================================================================
|
||||
//
|
||||
// Constructor
|
||||
//
|
||||
//===================================================================
|
||||
|
||||
Phrase(final String name,final String diag,int start)
|
||||
{
|
||||
this.name = name;
|
||||
this.diag = diag;
|
||||
this.start = start;
|
||||
this.end = start;
|
||||
}
|
||||
|
||||
//===================================================================
|
||||
//
|
||||
// Interface 'magic.grammar.Phrase'
|
||||
//
|
||||
//===================================================================
|
||||
//-----------------------------------------------------------------
|
||||
// Set value
|
||||
//-----------------------------------------------------------------
|
||||
public void put(Object o)
|
||||
{ value = o; }
|
||||
|
||||
//-----------------------------------------------------------------
|
||||
// Get value
|
||||
//-----------------------------------------------------------------
|
||||
public Object get()
|
||||
{ return value; }
|
||||
|
||||
//-----------------------------------------------------------------
|
||||
// Get text
|
||||
//-----------------------------------------------------------------
|
||||
public String text()
|
||||
{ return source.at(start,end); }
|
||||
|
||||
//-------------------------------------------------------------------
|
||||
// Get i-th character of text
|
||||
//-------------------------------------------------------------------
|
||||
public char charAt(int i)
|
||||
{ return source.at(start+i); }
|
||||
|
||||
//-----------------------------------------------------------------
|
||||
// Is text empty?
|
||||
//-----------------------------------------------------------------
|
||||
public boolean isEmpty()
|
||||
{ return start==end; }
|
||||
|
||||
//-------------------------------------------------------------------
|
||||
// Get name of rule that created this Phrase.
|
||||
//-------------------------------------------------------------------
|
||||
public String rule()
|
||||
{ return name; }
|
||||
|
||||
//-------------------------------------------------------------------
|
||||
// Was this Phrase created by rule 'rule'?
|
||||
//-------------------------------------------------------------------
|
||||
public boolean isA(String rule)
|
||||
{ return name.equals(rule); }
|
||||
|
||||
//-------------------------------------------------------------------
|
||||
// Was this Phrase created by a terminal?
|
||||
//-------------------------------------------------------------------
|
||||
public boolean isTerm()
|
||||
{ return name.isEmpty(); }
|
||||
|
||||
//-----------------------------------------------------------------
|
||||
// Get error message
|
||||
//-----------------------------------------------------------------
|
||||
public String errMsg()
|
||||
{
|
||||
if (errPos<0) return "";
|
||||
return source.where(errPos) + ":" + listErr();
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------
|
||||
// Clear error information
|
||||
//-----------------------------------------------------------------
|
||||
public void errClear()
|
||||
{
|
||||
errTxt.clear();
|
||||
errPos = -1;
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------
|
||||
// Describe position of i-th character of the Phrase in source text.
|
||||
//-----------------------------------------------------------------
|
||||
public String where(int i)
|
||||
{ return source.where(start+i); }
|
||||
|
||||
|
||||
//===================================================================
|
||||
//
|
||||
// Operations on error info
|
||||
//
|
||||
//===================================================================
|
||||
|
||||
//-----------------------------------------------------------------
|
||||
// Set fresh info ('who' failed 'where'), discarding any previous.
|
||||
//-----------------------------------------------------------------
|
||||
void errSet(final String who, int where)
|
||||
{
|
||||
errTxt.clear();
|
||||
errTxt.add(who);
|
||||
errPos = where;
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------
|
||||
// Add info about 'who' failing at current position.
|
||||
//-----------------------------------------------------------------
|
||||
void errAdd(final String who)
|
||||
{
|
||||
if (errPos>pos) return; // If current position older: forget
|
||||
if (errPos<pos) // If current position newer: replace
|
||||
{
|
||||
errTxt.clear();
|
||||
errPos = pos;
|
||||
errTxt.add(who);
|
||||
return;
|
||||
}
|
||||
// If error at same position: add
|
||||
errTxt.add(who);
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------
|
||||
// Merge error info with with that from Phrase 'p'.
|
||||
//-----------------------------------------------------------------
|
||||
void errMerge(final Phrase p)
|
||||
{
|
||||
if (p.errPos<pos && errPos<pos) // If we passed all error points
|
||||
{
|
||||
errClear();
|
||||
return;
|
||||
}
|
||||
|
||||
if (p.errPos<0) return; // If no error in p: forget
|
||||
if (errPos>p.errPos) return; // If error in p older: forget
|
||||
if (errPos<p.errPos) // If error in p newer: replace all info
|
||||
{
|
||||
errTxt.clear();
|
||||
errPos = p.errPos;
|
||||
errTxt.addAll(p.errTxt);
|
||||
return;
|
||||
}
|
||||
// If error in p at same position
|
||||
errTxt.addAll(p.errTxt); // Add all from p
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------
|
||||
// List errors
|
||||
//-----------------------------------------------------------------
|
||||
private String listErr()
|
||||
{
|
||||
StringBuilder one = new StringBuilder();
|
||||
StringBuilder two = new StringBuilder();
|
||||
Vector<String> done = new Vector<String>();
|
||||
for (String s: errTxt)
|
||||
{
|
||||
if (done.contains(s)) continue;
|
||||
done.add(s);
|
||||
if (s.startsWith("not "))
|
||||
toPrint(" or " + s.substring(4),two);
|
||||
else
|
||||
toPrint(" or " + s,one);
|
||||
}
|
||||
|
||||
if (one.length()>0)
|
||||
{
|
||||
if (two.length()==0)
|
||||
return " expected " + one.toString().substring(4);
|
||||
else
|
||||
return " expected " + one.toString().substring(4) +
|
||||
"; not expected " + two.toString().substring(4);
|
||||
}
|
||||
else
|
||||
return " not expected " + two.toString().substring(4);
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------
|
||||
// Convert string to printable and append to StringBuilder.
|
||||
//-----------------------------------------------------------------
|
||||
private void toPrint(final String s, StringBuilder sb)
|
||||
{
|
||||
for (int i=0;i<s.length();i++)
|
||||
{
|
||||
char c = s.charAt(i);
|
||||
switch(c)
|
||||
{
|
||||
case '\b': sb.append("\\b"); continue;
|
||||
case '\f': sb.append("\\f"); continue;
|
||||
case '\n': sb.append("\\n"); continue;
|
||||
case '\r': sb.append("\\r"); continue;
|
||||
case '\t': sb.append("\\t"); continue;
|
||||
default:
|
||||
if (c<32 || c>256)
|
||||
{
|
||||
String u = "000" + Integer.toHexString(c);
|
||||
sb.append("\\u" + u.substring(u.length()-4,u.length()));
|
||||
}
|
||||
else sb.append(c);
|
||||
continue;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
|
@ -0,0 +1,224 @@
|
|||
//=========================================================================
|
||||
//
|
||||
// Part of PEG parser generator Mouse.
|
||||
//
|
||||
// Copyright (C) 2009, 2010
|
||||
// by Roman R. Redziejowski (www.romanredz.se).
|
||||
//
|
||||
// Licensed 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.
|
||||
//
|
||||
//-------------------------------------------------------------------------
|
||||
//
|
||||
// Change log
|
||||
// 090721 Created for Mouse 1.1.
|
||||
// Version 1.3
|
||||
// 100504 Added c.diag to arguments of begin in saved and savedInner.
|
||||
// 100504 In Cache(String) set diag to name instead of null.
|
||||
//
|
||||
//=========================================================================
|
||||
|
||||
package magic.grammar;
|
||||
|
||||
import magic.grammar.Source;
|
||||
|
||||
|
||||
//HHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHH
|
||||
//
|
||||
// ParserMemo
|
||||
//
|
||||
//HHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHH
|
||||
|
||||
|
||||
public class ParserMemo extends ParserBase
|
||||
{
|
||||
//-------------------------------------------------------------------
|
||||
// Cache size.
|
||||
//-------------------------------------------------------------------
|
||||
int cacheSize = 1;
|
||||
|
||||
//-------------------------------------------------------------------
|
||||
// Phrase to reuse.
|
||||
//-------------------------------------------------------------------
|
||||
Phrase reuse;
|
||||
|
||||
//-------------------------------------------------------------------
|
||||
// List of Cache objects for initialization.
|
||||
//-------------------------------------------------------------------
|
||||
protected Cache[] caches;
|
||||
|
||||
//-------------------------------------------------------------------
|
||||
// Constructor
|
||||
//-------------------------------------------------------------------
|
||||
protected ParserMemo()
|
||||
{}
|
||||
|
||||
//-------------------------------------------------------------------
|
||||
// Initialize
|
||||
//-------------------------------------------------------------------
|
||||
public void init(Source src)
|
||||
{
|
||||
super.init(src);
|
||||
for (Cache c: caches) // Reset Cache objects
|
||||
c.reset();
|
||||
}
|
||||
|
||||
//-------------------------------------------------------------------
|
||||
// Set cache size.
|
||||
//-------------------------------------------------------------------
|
||||
public void setMemo(int m)
|
||||
{
|
||||
if (m<1 | m>9) throw new Error("m=" + m + " outside range 1-9");
|
||||
cacheSize = m;
|
||||
}
|
||||
|
||||
|
||||
//=====================================================================
|
||||
//
|
||||
// Methods called from parsing procedures
|
||||
//
|
||||
//=====================================================================
|
||||
//-------------------------------------------------------------------
|
||||
// If saved result found, use it, otherwise begin new procedure.
|
||||
// Version for Rule.
|
||||
//-------------------------------------------------------------------
|
||||
protected boolean saved(Cache c)
|
||||
{
|
||||
reuse = c.find();
|
||||
if (reuse!=null) // If found Phrase to reuse..
|
||||
return true; // .. return
|
||||
|
||||
begin(c.name,c.diag); // Otherwise push new Phrase
|
||||
c.save(current); // .. and cache it
|
||||
return false;
|
||||
}
|
||||
|
||||
//-------------------------------------------------------------------
|
||||
// If saved result found, use it, otherwise begin new procedure.
|
||||
// Version for Inner.
|
||||
//-------------------------------------------------------------------
|
||||
protected boolean savedInner(Cache c)
|
||||
{
|
||||
reuse = c.find();
|
||||
if (reuse!=null) // If found Phrase to reuse..
|
||||
return true; // .. return
|
||||
|
||||
begin("",c.diag); // Otherwise push new Phrase
|
||||
c.save(current); // .. and cache it
|
||||
return false;
|
||||
}
|
||||
|
||||
//-------------------------------------------------------------------
|
||||
// Reuse Rule
|
||||
//-------------------------------------------------------------------
|
||||
protected boolean reuse()
|
||||
{
|
||||
if (reuse.success)
|
||||
{
|
||||
pos = reuse.end; // Update position
|
||||
current.end = pos; // Update end of current
|
||||
current.rhs.add(reuse); // Attach p to rhs of current
|
||||
current.errMerge(reuse); // Merge error info with current
|
||||
return true;
|
||||
}
|
||||
else
|
||||
{
|
||||
current.errMerge(reuse); // Merge error info with current
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
//-------------------------------------------------------------------
|
||||
// Reuse Inner
|
||||
//-------------------------------------------------------------------
|
||||
protected boolean reuseInner()
|
||||
{
|
||||
if (reuse.success)
|
||||
{
|
||||
pos = reuse.end; // Update position
|
||||
current.end = pos; // Update end of current
|
||||
current.rhs.addAll(reuse.rhs); // Add rhs to rhs of current
|
||||
current.errMerge(reuse); // Merge error info with current
|
||||
return true;
|
||||
}
|
||||
else
|
||||
{
|
||||
current.errMerge(reuse); // Merge error info with current
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
//-------------------------------------------------------------------
|
||||
// Reuse predicate
|
||||
//-------------------------------------------------------------------
|
||||
protected boolean reusePred()
|
||||
{
|
||||
if (reuse.success)
|
||||
return true;
|
||||
else
|
||||
{
|
||||
current.errMerge(reuse); // Merge error info with current
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
//HHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHH
|
||||
//
|
||||
// Cache
|
||||
//
|
||||
//HHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHH
|
||||
|
||||
protected class Cache
|
||||
{
|
||||
public final String name;
|
||||
public final String diag;
|
||||
|
||||
Phrase[] cache;
|
||||
int last;
|
||||
|
||||
public Cache(final String name)
|
||||
{
|
||||
this.name = name;
|
||||
this.diag = name;
|
||||
}
|
||||
|
||||
public Cache(final String name, final String diag)
|
||||
{
|
||||
this.name = name;
|
||||
this.diag = diag;
|
||||
}
|
||||
|
||||
void reset()
|
||||
{
|
||||
cache = new Phrase[cacheSize];
|
||||
last = 0;
|
||||
}
|
||||
|
||||
void save(Phrase p)
|
||||
{
|
||||
last = (last+1)%cacheSize;
|
||||
cache[last] = p;
|
||||
}
|
||||
|
||||
Phrase find()
|
||||
{
|
||||
for (Phrase p: cache)
|
||||
if (p!=null && p.start==pos) return p;
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
|
@ -0,0 +1,526 @@
|
|||
//=========================================================================
|
||||
//
|
||||
// Part of PEG parser generator Mouse.
|
||||
//
|
||||
// Copyright (C) 2009, 2010, 2011
|
||||
// by Roman R. Redziejowski (www.romanredz.se).
|
||||
//
|
||||
// Licensed 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.
|
||||
//
|
||||
//-------------------------------------------------------------------------
|
||||
//
|
||||
// Change log
|
||||
// 090721 Created for Mouse 1.1.
|
||||
// Version 1.3
|
||||
// 100429 In error trace added name of the Phrase owning error info.
|
||||
// 100504 Added c.diag to arguments of begin in saved and savedInner.
|
||||
// 100504 In error trace changed current.name to current.diag.
|
||||
// 101127 Renamed 'startpos' to 'endpos' in tracing.
|
||||
// Version 1.4
|
||||
// 111004 Added methods to implement ^[s].
|
||||
// Version 1.5
|
||||
// 111105 Revised methods for ^[s] and ^[c].
|
||||
//
|
||||
//=========================================================================
|
||||
|
||||
package magic.grammar;
|
||||
|
||||
import java.util.BitSet;
|
||||
|
||||
|
||||
//HHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHH
|
||||
//
|
||||
// ParserTest
|
||||
//
|
||||
//HHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHH
|
||||
|
||||
public class ParserTest extends ParserMemo
|
||||
{
|
||||
//-------------------------------------------------------------------
|
||||
// Cache size.
|
||||
//-------------------------------------------------------------------
|
||||
int cacheSize = 1;
|
||||
|
||||
//-------------------------------------------------------------------
|
||||
// Trace switches.
|
||||
//-------------------------------------------------------------------
|
||||
public boolean traceRules; // Trace Rules
|
||||
public boolean traceInner; // Trace subexpressions
|
||||
public boolean traceError; // Trace error info
|
||||
|
||||
//-------------------------------------------------------------------
|
||||
// Constructor
|
||||
//-------------------------------------------------------------------
|
||||
protected ParserTest()
|
||||
{}
|
||||
|
||||
//-------------------------------------------------------------------
|
||||
// Set cache size.
|
||||
//-------------------------------------------------------------------
|
||||
public void setMemo(int m)
|
||||
{
|
||||
if (m<0 | m>9) throw new Error("m=" + m + " outside range 0-9");
|
||||
cacheSize = m;
|
||||
}
|
||||
|
||||
//-------------------------------------------------------------------
|
||||
// Set trace
|
||||
//-------------------------------------------------------------------
|
||||
public void setTrace(String trace)
|
||||
{
|
||||
super.setTrace(trace);
|
||||
traceRules = trace.indexOf('r')>=0;
|
||||
traceInner = trace.indexOf('i')>=0;
|
||||
traceError = trace.indexOf('e')>=0;
|
||||
}
|
||||
|
||||
//-------------------------------------------------------------------
|
||||
// Access to cache list
|
||||
//-------------------------------------------------------------------
|
||||
public Cache[] caches()
|
||||
{ return (Cache[])caches; }
|
||||
|
||||
//-------------------------------------------------------------------
|
||||
// Write trace
|
||||
//-------------------------------------------------------------------
|
||||
void trace(final String s)
|
||||
{ System.out.println(s); }
|
||||
|
||||
|
||||
//=====================================================================
|
||||
//
|
||||
// Methods called from parsing procedures
|
||||
//
|
||||
//=====================================================================
|
||||
//-------------------------------------------------------------------
|
||||
// If saved result found, use it, otherwise begin new procedure.
|
||||
// Version for Rule.
|
||||
//-------------------------------------------------------------------
|
||||
protected boolean saved(Cache c)
|
||||
{
|
||||
c.calls++;
|
||||
if (traceRules) trace(source.where(pos) + ": INIT " + c.name);
|
||||
reuse = c.find();
|
||||
if (reuse!=null)
|
||||
{
|
||||
c.reuse++;
|
||||
if (traceRules) trace("REUSE " + (reuse.success? "succ " : "fail "));
|
||||
return true;
|
||||
}
|
||||
|
||||
begin(c.name,c.diag);
|
||||
c.save(current);
|
||||
if (c.prevpos.get(pos)) c.rescan++;
|
||||
else c.prevpos.set(pos);
|
||||
return false;
|
||||
}
|
||||
|
||||
//-------------------------------------------------------------------
|
||||
// If saved result found, use it, otherwise begin new procedure.
|
||||
// Version for Inner.
|
||||
//-------------------------------------------------------------------
|
||||
protected boolean savedInner(Cache c)
|
||||
{
|
||||
c.calls++;
|
||||
if (traceInner) trace(source.where(pos) + ": INIT " + c.name);
|
||||
reuse = c.find();
|
||||
if (reuse!=null)
|
||||
{
|
||||
c.reuse++;
|
||||
if (traceInner) trace("REUSE " + (reuse.success? "succ " : "fail "));
|
||||
return true;
|
||||
}
|
||||
|
||||
begin("",c.diag);
|
||||
c.save(current);
|
||||
if (c.prevpos.get(pos)) c.rescan++;
|
||||
else c.prevpos.set(pos);
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
//-------------------------------------------------------------------
|
||||
// Accept Rule
|
||||
//-------------------------------------------------------------------
|
||||
protected boolean accept(Cache c)
|
||||
{
|
||||
super.accept();
|
||||
traceAccept(c,traceRules);
|
||||
return true;
|
||||
}
|
||||
|
||||
//-------------------------------------------------------------------
|
||||
// Accept Inner
|
||||
//-------------------------------------------------------------------
|
||||
protected boolean acceptInner(Cache c)
|
||||
{
|
||||
super.acceptInner();
|
||||
traceAccept(c,traceInner);
|
||||
return true;
|
||||
}
|
||||
|
||||
//-------------------------------------------------------------------
|
||||
// Accept And-predicate (argument was accepted)
|
||||
//-------------------------------------------------------------------
|
||||
protected boolean acceptAnd(Cache c)
|
||||
{
|
||||
super.acceptAnd();
|
||||
traceAccept(c,traceInner);
|
||||
return true;
|
||||
}
|
||||
|
||||
//-------------------------------------------------------------------
|
||||
// Accept Not-predicate (argument was rejected)
|
||||
//-------------------------------------------------------------------
|
||||
protected boolean acceptNot(Cache c)
|
||||
{
|
||||
super.acceptNot();
|
||||
traceAccept(c,traceInner);
|
||||
return true;
|
||||
}
|
||||
|
||||
//-------------------------------------------------------------------
|
||||
// Trace accept
|
||||
//-------------------------------------------------------------------
|
||||
private void traceAccept(Cache c, boolean cond)
|
||||
{
|
||||
if (cond)
|
||||
{
|
||||
trace(source.where(pos) + ": ACCEPT " + c.name);
|
||||
if (traceError) trace(current.diag + " --" + current.errMsg());
|
||||
}
|
||||
c.succ++;
|
||||
}
|
||||
|
||||
|
||||
//-------------------------------------------------------------------
|
||||
// Reject Rule
|
||||
//-------------------------------------------------------------------
|
||||
protected boolean reject(Cache c)
|
||||
{
|
||||
int endpos = pos;
|
||||
super.reject();
|
||||
traceReject(c,traceRules,endpos);
|
||||
return false;
|
||||
}
|
||||
|
||||
//-------------------------------------------------------------------
|
||||
// Reject Inner
|
||||
//-------------------------------------------------------------------
|
||||
protected boolean rejectInner(Cache c)
|
||||
{
|
||||
int endpos = pos;
|
||||
super.rejectInner();
|
||||
traceReject(c,traceInner,endpos);
|
||||
return false;
|
||||
}
|
||||
|
||||
//-------------------------------------------------------------------
|
||||
// Reject And-predicate (argument was rejected)
|
||||
//-------------------------------------------------------------------
|
||||
protected boolean rejectAnd(Cache c)
|
||||
{
|
||||
int endpos = pos;
|
||||
super.rejectAnd();
|
||||
traceReject(c,traceInner,endpos);
|
||||
return false;
|
||||
}
|
||||
|
||||
//-------------------------------------------------------------------
|
||||
// Reject Not-predicate (argument was accepted)
|
||||
//-------------------------------------------------------------------
|
||||
protected boolean rejectNot(Cache c)
|
||||
{
|
||||
int endpos = pos;
|
||||
super.rejectNot();
|
||||
traceReject(c,traceInner,endpos);
|
||||
return false;
|
||||
}
|
||||
|
||||
//-------------------------------------------------------------------
|
||||
// Trace reject
|
||||
//-------------------------------------------------------------------
|
||||
private void traceReject(Cache c, boolean cond, int endpos)
|
||||
{
|
||||
if (cond)
|
||||
{
|
||||
trace(source.where(endpos) + ": REJECT " + c.name);
|
||||
if (traceError) trace(current.diag + " --" + current.errMsg());
|
||||
}
|
||||
if (pos==endpos) c.fail++; // No backtrack
|
||||
else // Backtrack
|
||||
{
|
||||
int b = endpos-pos;
|
||||
c.back++;
|
||||
c.totback += b;
|
||||
if (b>c.maxback)
|
||||
{
|
||||
c.maxback = b;
|
||||
c.maxbpos = pos;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
//-------------------------------------------------------------------
|
||||
// Execute expression 'c'
|
||||
//-------------------------------------------------------------------
|
||||
protected boolean next(char ch,Cache c)
|
||||
{
|
||||
int endpos = pos;
|
||||
boolean succ = super.next(ch);
|
||||
return traceTerm(endpos,succ,c);
|
||||
}
|
||||
|
||||
//-------------------------------------------------------------------
|
||||
// Execute expression ^'c'
|
||||
//-------------------------------------------------------------------
|
||||
protected boolean nextNot(char ch,Cache c)
|
||||
{
|
||||
int endpos = pos;
|
||||
boolean succ = super.nextNot(ch);
|
||||
return traceTerm(endpos,succ,c);
|
||||
}
|
||||
|
||||
//-------------------------------------------------------------------
|
||||
// Execute expression &'c', !^'c'
|
||||
//-------------------------------------------------------------------
|
||||
protected boolean ahead(char ch,Cache c)
|
||||
{
|
||||
int endpos = pos;
|
||||
boolean succ = super.ahead(ch);
|
||||
return traceTerm(endpos,succ,c);
|
||||
}
|
||||
|
||||
protected boolean aheadNotNot(char ch,Cache c)
|
||||
{ return ahead(ch,c); }
|
||||
|
||||
//-------------------------------------------------------------------
|
||||
// Execute expression !'c', &^'c'
|
||||
//-------------------------------------------------------------------
|
||||
protected boolean aheadNot(char ch,Cache c)
|
||||
{
|
||||
int endpos = pos;
|
||||
boolean succ = super.aheadNot(ch);
|
||||
return traceTerm(endpos,succ,c);
|
||||
}
|
||||
|
||||
|
||||
//-------------------------------------------------------------------
|
||||
// Execute expression "s"
|
||||
//-------------------------------------------------------------------
|
||||
protected boolean next(String s,Cache c)
|
||||
{
|
||||
int endpos = pos;
|
||||
boolean succ = super.next(s);
|
||||
return traceTerm(endpos,succ,c);
|
||||
}
|
||||
|
||||
//-------------------------------------------------------------------
|
||||
// Execute expression &"s"
|
||||
//-------------------------------------------------------------------
|
||||
protected boolean ahead(String s,Cache c)
|
||||
{
|
||||
int endpos = pos;
|
||||
boolean succ = super.ahead(s);
|
||||
return traceTerm(endpos,succ,c);
|
||||
}
|
||||
|
||||
//-------------------------------------------------------------------
|
||||
// Execute expression !"s"
|
||||
//-------------------------------------------------------------------
|
||||
protected boolean aheadNot(String s,Cache c)
|
||||
{
|
||||
int endpos = pos;
|
||||
boolean succ = super.aheadNot(s);
|
||||
return traceTerm(endpos,succ,c);
|
||||
}
|
||||
|
||||
|
||||
//-------------------------------------------------------------------
|
||||
// Execute expression [s]
|
||||
//-------------------------------------------------------------------
|
||||
protected boolean nextIn(String s,Cache c)
|
||||
{
|
||||
int endpos = pos;
|
||||
boolean succ = super.nextIn(s);
|
||||
return traceTerm(endpos,succ,c);
|
||||
}
|
||||
|
||||
//-------------------------------------------------------------------
|
||||
// Execute expression ^[s]
|
||||
//-------------------------------------------------------------------
|
||||
protected boolean nextNotIn(String s,Cache c)
|
||||
{
|
||||
int endpos = pos;
|
||||
boolean succ = super.nextNotIn(s);
|
||||
return traceTerm(endpos,succ,c);
|
||||
}
|
||||
|
||||
//-------------------------------------------------------------------
|
||||
// Execute expression &[s], !^[s]
|
||||
//-------------------------------------------------------------------
|
||||
protected boolean aheadIn(String s,Cache c)
|
||||
{
|
||||
int endpos = pos;
|
||||
boolean succ = super.aheadIn(s);
|
||||
return traceTerm(endpos,succ,c);
|
||||
}
|
||||
|
||||
protected boolean aheadNotNotIn(String s,Cache c)
|
||||
{ return aheadIn(s,c); }
|
||||
|
||||
//-------------------------------------------------------------------
|
||||
// Execute expression ![s], &^[s]
|
||||
//-------------------------------------------------------------------
|
||||
protected boolean aheadNotIn(String s,Cache c)
|
||||
{
|
||||
int endpos = pos;
|
||||
boolean succ = super.aheadNotIn(s);
|
||||
return traceTerm(endpos,succ,c);
|
||||
}
|
||||
|
||||
|
||||
//-------------------------------------------------------------------
|
||||
// Execute expression [a-z]
|
||||
//-------------------------------------------------------------------
|
||||
protected boolean nextIn(char a, char z, Cache c)
|
||||
{
|
||||
int endpos = pos;
|
||||
boolean succ = super.nextIn(a,z);
|
||||
return traceTerm(endpos,succ,c);
|
||||
}
|
||||
|
||||
//-------------------------------------------------------------------
|
||||
// Execute expression &[a-z]
|
||||
//-------------------------------------------------------------------
|
||||
protected boolean aheadIn(char a, char z, Cache c)
|
||||
{
|
||||
int endpos = pos;
|
||||
boolean succ = super.aheadIn(a,z);
|
||||
return traceTerm(endpos,succ,c);
|
||||
}
|
||||
|
||||
//-------------------------------------------------------------------
|
||||
// Execute expression ![a-z]
|
||||
//-------------------------------------------------------------------
|
||||
protected boolean aheadNotIn(char a, char z, Cache c)
|
||||
{
|
||||
int endpos = pos;
|
||||
boolean succ = super.aheadNotIn(a,z);
|
||||
return traceTerm(endpos,succ,c);
|
||||
}
|
||||
|
||||
|
||||
//-------------------------------------------------------------------
|
||||
// Execute expression _
|
||||
//-------------------------------------------------------------------
|
||||
protected boolean next(Cache c)
|
||||
{
|
||||
int endpos = pos;
|
||||
boolean succ = super.next();
|
||||
return traceTerm(endpos,succ,c);
|
||||
}
|
||||
|
||||
//-------------------------------------------------------------------
|
||||
// Execute expression &_
|
||||
//-------------------------------------------------------------------
|
||||
protected boolean ahead(Cache c)
|
||||
{
|
||||
int endpos = pos;
|
||||
boolean succ = super.ahead();
|
||||
return traceTerm(endpos,succ,c);
|
||||
}
|
||||
|
||||
//-------------------------------------------------------------------
|
||||
// Execute expression !_
|
||||
//-------------------------------------------------------------------
|
||||
protected boolean aheadNot(Cache c)
|
||||
{
|
||||
int endpos = pos;
|
||||
boolean succ = super.aheadNot();
|
||||
return traceTerm(endpos,succ,c);
|
||||
}
|
||||
|
||||
|
||||
//-------------------------------------------------------------------
|
||||
// Trace term
|
||||
//-------------------------------------------------------------------
|
||||
private boolean traceTerm(int endpos, boolean succ, Cache c)
|
||||
{
|
||||
c.calls++;
|
||||
if (c.prevpos.get(endpos)) c.rescan++;
|
||||
else c.prevpos.set(endpos);
|
||||
if (succ) { c.succ++; return true; }
|
||||
else { c.fail++; return false; }
|
||||
}
|
||||
|
||||
|
||||
|
||||
//HHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHH
|
||||
//
|
||||
// Cache object
|
||||
//
|
||||
//HHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHH
|
||||
|
||||
public class Cache extends ParserMemo.Cache
|
||||
{
|
||||
public int calls ; // Total number of calls
|
||||
public int rescan ; // How many were rescans without reuse
|
||||
public int reuse ; // How many were rescans with reuse
|
||||
public int succ ; // How many resulted in success
|
||||
public int fail ; // How many resulted in failure, no backtrack
|
||||
public int back ; // How many resulted in backtrack
|
||||
public int totback; // Accumulated amount of backtrack
|
||||
public int maxback; // Maximum length of backtrack
|
||||
public int maxbpos; // Position of naximal backtrack
|
||||
BitSet prevpos ; // Scan history
|
||||
|
||||
|
||||
public Cache(final String name)
|
||||
{ super(name); }
|
||||
|
||||
public Cache(final String name,final String diag)
|
||||
{ super(name,diag); }
|
||||
|
||||
void save(Phrase p)
|
||||
{
|
||||
if (cacheSize==0) return;
|
||||
super.save(p);
|
||||
}
|
||||
|
||||
Phrase find()
|
||||
{
|
||||
if (cacheSize==0) return null;
|
||||
return super.find();
|
||||
}
|
||||
|
||||
void reset()
|
||||
{
|
||||
super.reset();
|
||||
calls = 0;
|
||||
rescan = 0;
|
||||
reuse = 0;
|
||||
succ = 0;
|
||||
fail = 0;
|
||||
back = 0;
|
||||
totback = 0;
|
||||
maxback = 0;
|
||||
maxbpos = 0;
|
||||
prevpos = new BitSet(60000);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
|
@ -0,0 +1,97 @@
|
|||
//=========================================================================
|
||||
//
|
||||
// Part of PEG parser generator Mouse.
|
||||
//
|
||||
// Copyright (C) 2009, 2011 by Roman R. Redziejowski (www.romanredz.se).
|
||||
//
|
||||
// Licensed 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.
|
||||
//
|
||||
//-------------------------------------------------------------------------
|
||||
//
|
||||
// Change log
|
||||
// 090701 License changed by the author to Apache v.2.
|
||||
// 090717 Removed unused import of java.util.Vector.
|
||||
// Version 1.4
|
||||
// 111004 Added method 'where'.
|
||||
// Version 1.5
|
||||
// 111104 Added methods 'rule' and 'isTerm'.
|
||||
//
|
||||
//=========================================================================
|
||||
|
||||
package magic.grammar;
|
||||
|
||||
|
||||
//HHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHH
|
||||
//
|
||||
// Phrase seen from Semantics
|
||||
//
|
||||
//HHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHH
|
||||
|
||||
public interface Phrase
|
||||
{
|
||||
//-------------------------------------------------------------------
|
||||
// Set value
|
||||
//-------------------------------------------------------------------
|
||||
void put(Object o);
|
||||
|
||||
//-------------------------------------------------------------------
|
||||
// Get value
|
||||
//-------------------------------------------------------------------
|
||||
Object get();
|
||||
|
||||
//-------------------------------------------------------------------
|
||||
// Get text
|
||||
//-------------------------------------------------------------------
|
||||
String text();
|
||||
|
||||
//-------------------------------------------------------------------
|
||||
// Get i-th character of text
|
||||
//-------------------------------------------------------------------
|
||||
char charAt(int i);
|
||||
|
||||
//-------------------------------------------------------------------
|
||||
// Is text empty?
|
||||
//-------------------------------------------------------------------
|
||||
boolean isEmpty();
|
||||
|
||||
//-------------------------------------------------------------------
|
||||
// Get name of rule that created this Phrase.
|
||||
//-------------------------------------------------------------------
|
||||
String rule();
|
||||
|
||||
//-------------------------------------------------------------------
|
||||
// Was this Phrase created by rule 'name'?
|
||||
//-------------------------------------------------------------------
|
||||
boolean isA(String name);
|
||||
|
||||
//-------------------------------------------------------------------
|
||||
// Was this Phrase created by a terminal?
|
||||
//-------------------------------------------------------------------
|
||||
boolean isTerm();
|
||||
|
||||
//-------------------------------------------------------------------
|
||||
// Get error message
|
||||
//-------------------------------------------------------------------
|
||||
String errMsg();
|
||||
|
||||
//-------------------------------------------------------------------
|
||||
// Clear error message
|
||||
//-------------------------------------------------------------------
|
||||
void errClear();
|
||||
|
||||
//-------------------------------------------------------------------
|
||||
// Describe position of i-th character of the Phrase in source text.
|
||||
//-------------------------------------------------------------------
|
||||
String where(int i);
|
||||
|
||||
}
|
|
@ -0,0 +1,106 @@
|
|||
//=========================================================================
|
||||
//
|
||||
// Part of PEG parser generator Mouse.
|
||||
//
|
||||
// Copyright (C) 2009 by Roman R. Redziejowski (www.romanredz.se).
|
||||
//
|
||||
// Licensed 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.
|
||||
//
|
||||
//-------------------------------------------------------------------------
|
||||
//
|
||||
// Change log
|
||||
// 090701 License changed by the author to Apache v.2.
|
||||
// 090717 Interface 'Parser' renamed to 'CurrentRule'.
|
||||
// 090810 Name changed from 'Semantics'.
|
||||
//
|
||||
//=========================================================================
|
||||
|
||||
package magic.grammar;
|
||||
|
||||
|
||||
|
||||
//HHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHH
|
||||
//
|
||||
// SemanticsBase
|
||||
//
|
||||
//HHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHH
|
||||
|
||||
public class SemanticsBase
|
||||
{
|
||||
//=====================================================================
|
||||
//
|
||||
// Fields set by the Parser.
|
||||
//
|
||||
//=====================================================================
|
||||
//-------------------------------------------------------------------
|
||||
// Reference to current rule in the Parser.
|
||||
// Set when Parser instantiates Semantics.
|
||||
//-------------------------------------------------------------------
|
||||
public CurrentRule rule;
|
||||
|
||||
//-------------------------------------------------------------------
|
||||
// String that you can use to trigger trace.
|
||||
// Set by applying method 'setTrace' to the Parser.
|
||||
//-------------------------------------------------------------------
|
||||
public String trace = "";
|
||||
|
||||
|
||||
//=====================================================================
|
||||
//
|
||||
// Initialization.
|
||||
//
|
||||
//=====================================================================
|
||||
//-------------------------------------------------------------------
|
||||
// Invoked at the beginning of each invocation of the Parser.
|
||||
// You can override it to perform your own initialization.
|
||||
//-------------------------------------------------------------------
|
||||
public void init()
|
||||
{}
|
||||
|
||||
|
||||
//=====================================================================
|
||||
//
|
||||
// Methods to be invoked from semantic actions.
|
||||
// They call back the parser to obtain details of the environment
|
||||
// in which the action was invoked.
|
||||
//
|
||||
//=====================================================================
|
||||
//-------------------------------------------------------------------
|
||||
// Returns the left-hand side Phrase object.
|
||||
//-------------------------------------------------------------------
|
||||
protected Phrase lhs()
|
||||
{ return rule.lhs(); }
|
||||
|
||||
//-------------------------------------------------------------------
|
||||
// Returns the number of Phrase objects on the right-hand side.
|
||||
//-------------------------------------------------------------------
|
||||
protected int rhsSize()
|
||||
{ return rule.rhsSize(); }
|
||||
|
||||
//-------------------------------------------------------------------
|
||||
// Returns the i-th right-hand side object, 0<=i<rhs<=rhsSize().
|
||||
// (The right-hand side objects are numbered starting with 0.)
|
||||
//-------------------------------------------------------------------
|
||||
protected Phrase rhs(int i)
|
||||
{ return rule.rhs(i); }
|
||||
|
||||
//-------------------------------------------------------------------
|
||||
// Returns as one String the text represented
|
||||
// by the right-hand side objects numbered i through j-1,
|
||||
// where 0<=i<j<=rhsSize().
|
||||
// (The right-hand side objects are numbered starting with 0.)
|
||||
//-------------------------------------------------------------------
|
||||
protected String rhsText(int i,int j)
|
||||
{ return rule.rhsText(i,j); }
|
||||
|
||||
}
|
|
@ -0,0 +1,73 @@
|
|||
//=========================================================================
|
||||
//
|
||||
// Part of PEG parser generator Mouse.
|
||||
//
|
||||
// Copyright (C) 2009, 2010 by Roman R. Redziejowski (www.romanredz.se).
|
||||
//
|
||||
// Licensed 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.
|
||||
//
|
||||
//-------------------------------------------------------------------------
|
||||
//
|
||||
// Change log
|
||||
// 090701 License changed by the author to Apache v.2.
|
||||
// 090810 Package name changed.
|
||||
//
|
||||
//=========================================================================
|
||||
|
||||
package magic.grammar;
|
||||
|
||||
|
||||
//HHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHH
|
||||
//
|
||||
// Interface to source text wrapper.
|
||||
// The generated parser accesses its input through a wrapper that
|
||||
// presents the input as a sequence of characters. These characters
|
||||
// can be individually accessed by specifying their position in the
|
||||
// sequence. The positions are numbered starting with 0.
|
||||
// For diagnostic purposes, the wrapper has the method 'where' that
|
||||
// describes a given position in terms compatible with the input
|
||||
// medium, for example, as line and column number for a file.
|
||||
//
|
||||
//HHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHH
|
||||
|
||||
public interface Source
|
||||
{
|
||||
//-------------------------------------------------------------------
|
||||
// Is the wrapper correctly initialized?
|
||||
// The wrapper's constructor may encounter errors that result
|
||||
// in the object not being properly initialized.
|
||||
// The method returns 'false' if this is the case.
|
||||
//-------------------------------------------------------------------
|
||||
boolean created();
|
||||
|
||||
//-------------------------------------------------------------------
|
||||
// Returns position of the last character plus 1
|
||||
// (= length of the sequence).
|
||||
//-------------------------------------------------------------------
|
||||
int end();
|
||||
|
||||
//-------------------------------------------------------------------
|
||||
// Returns character at position p.
|
||||
//-------------------------------------------------------------------
|
||||
char at(int p);
|
||||
|
||||
//-------------------------------------------------------------------
|
||||
// Returns characters at positions p through q-1.
|
||||
//-------------------------------------------------------------------
|
||||
String at(int p, int q);
|
||||
|
||||
//-------------------------------------------------------------------
|
||||
// Describes position p in user's terms.
|
||||
//-------------------------------------------------------------------
|
||||
String where(int p);
|
||||
}
|
|
@ -0,0 +1,175 @@
|
|||
//=========================================================================
|
||||
//
|
||||
// Part of PEG parser generator Mouse.
|
||||
//
|
||||
// Copyright (C) 2009, 2010, 2011
|
||||
// by Roman R. Redziejowski (www.romanredz.se).
|
||||
//
|
||||
// Licensed 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.
|
||||
//
|
||||
//-------------------------------------------------------------------------
|
||||
//
|
||||
// Change log
|
||||
// 090701 License changed by the author to Apache v.2.
|
||||
// 090810 Renamed from 'SourceString' and package name changed.
|
||||
// Version 1.2
|
||||
// 100413 Added method 'file'.
|
||||
// Version 1.3
|
||||
// 101130 Changed to default character encoding.
|
||||
// 101130 Changed 'catch' from 'Exception' to 'IOException'.
|
||||
// 101130 Maps file to String instead of CharBuffer.
|
||||
// Version 1.3.1
|
||||
// 110113 In 'where()': changed condition for return from <= < to < <=.
|
||||
// (Bug fix for endless loop if p = end of file.)
|
||||
//
|
||||
//=========================================================================
|
||||
|
||||
package magic.grammar;
|
||||
|
||||
import java.io.*;
|
||||
import java.nio.*;
|
||||
import java.nio.charset.*;
|
||||
import java.nio.channels.*;
|
||||
|
||||
|
||||
//HHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHH
|
||||
//
|
||||
// Wrapper for parser input in the form of a file.
|
||||
// Maps the entire file into a String using default character encoding.
|
||||
//
|
||||
//HHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHH
|
||||
|
||||
public class SourceFile implements Source
|
||||
{
|
||||
//=====================================================================
|
||||
//
|
||||
// Data.
|
||||
//
|
||||
//=====================================================================
|
||||
//-------------------------------------------------------------------
|
||||
// The file.
|
||||
//-------------------------------------------------------------------
|
||||
private File f;
|
||||
|
||||
//-------------------------------------------------------------------
|
||||
// Memory-mapped file.
|
||||
//-------------------------------------------------------------------
|
||||
private String text;
|
||||
|
||||
//-------------------------------------------------------------------
|
||||
// Character encoding assumed for the file.
|
||||
// To use encoding other than default, change as shown
|
||||
// in the commented-out example.
|
||||
//-------------------------------------------------------------------
|
||||
private static final Charset cs = Charset.defaultCharset();
|
||||
// static final Charset cs = Charset.forName("8859_1");
|
||||
|
||||
//-------------------------------------------------------------------
|
||||
// Success indicator.
|
||||
//-------------------------------------------------------------------
|
||||
private boolean created = false;
|
||||
|
||||
|
||||
//=====================================================================
|
||||
//
|
||||
// Constructor. Wraps the file identified by 'fileName'.
|
||||
//
|
||||
//=====================================================================
|
||||
public SourceFile(final String fileName)
|
||||
{
|
||||
try
|
||||
{
|
||||
// Get a Channel for the source file
|
||||
f = new File(fileName);
|
||||
FileInputStream fis = new FileInputStream(f);
|
||||
FileChannel fc = fis.getChannel();
|
||||
|
||||
// Get a CharBuffer from the source file
|
||||
ByteBuffer bb =
|
||||
fc.map(FileChannel.MapMode.READ_ONLY, 0, (int)fc.size());
|
||||
CharsetDecoder cd = cs.newDecoder();
|
||||
CharBuffer cb = cd.decode(bb);
|
||||
fis.close();
|
||||
|
||||
// Convert to String
|
||||
text = cb.toString();
|
||||
created = true;
|
||||
}
|
||||
catch (FileNotFoundException e)
|
||||
{ System.err.println("File '" + fileName + "' was not found."); }
|
||||
catch (IOException e)
|
||||
{ System.err.println("Error in file '" + fileName + "' " + e.getMessage()); }
|
||||
}
|
||||
|
||||
|
||||
//=====================================================================
|
||||
//
|
||||
// Interface methods.
|
||||
//
|
||||
//=====================================================================
|
||||
//-------------------------------------------------------------------
|
||||
// Is the wrapper correctly initialized?
|
||||
//-------------------------------------------------------------------
|
||||
public boolean created()
|
||||
{ return created; }
|
||||
|
||||
//-------------------------------------------------------------------
|
||||
// Returns end position.
|
||||
//-------------------------------------------------------------------
|
||||
public int end()
|
||||
{ return text.length(); }
|
||||
|
||||
//-------------------------------------------------------------------
|
||||
// Returns character at position p.
|
||||
//-------------------------------------------------------------------
|
||||
public char at(int p)
|
||||
{ return text.charAt(p); }
|
||||
|
||||
//-------------------------------------------------------------------
|
||||
// Returns characters at positions p through q-1.
|
||||
//-------------------------------------------------------------------
|
||||
public String at(int p, int q)
|
||||
{ return text.substring(p,q); }
|
||||
|
||||
//-------------------------------------------------------------------
|
||||
// Describes position p in terms of line and column number.
|
||||
// Lines and columns are numbered starting with 1.
|
||||
//-------------------------------------------------------------------
|
||||
public String where(int p)
|
||||
{
|
||||
int ln = 1; // Line number
|
||||
int ls = -1; // Line start (position of preceding newline)
|
||||
int nextnl; // Position of next newline or end
|
||||
|
||||
while (true)
|
||||
{
|
||||
nextnl = text.indexOf('\n',ls+1);
|
||||
if (nextnl<0) nextnl = text.length();
|
||||
if (ls<p && p<=nextnl)
|
||||
return ("line " + ln + " col. " + (p-ls));
|
||||
ls = nextnl;
|
||||
ln++;
|
||||
}
|
||||
}
|
||||
|
||||
//=====================================================================
|
||||
//
|
||||
// File-specific method.
|
||||
//
|
||||
//=====================================================================
|
||||
//-------------------------------------------------------------------
|
||||
// Returns the file object.
|
||||
//-------------------------------------------------------------------
|
||||
public File file()
|
||||
{ return f; }
|
||||
}
|
|
@ -0,0 +1,101 @@
|
|||
//=========================================================================
|
||||
//
|
||||
// Part of PEG parser generator Mouse.
|
||||
//
|
||||
// Copyright (C) 2009, 2010 by Roman R. Redziejowski (www.romanredz.se).
|
||||
//
|
||||
// Licensed 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.
|
||||
//
|
||||
//-------------------------------------------------------------------------
|
||||
//
|
||||
// Change log
|
||||
// 090701 License changed by the author to Apache v.2.
|
||||
// 090810 Renamed from 'SourceString' and package name changed.
|
||||
// Version 1.2
|
||||
// 091105 Modified where() to insert three dots.
|
||||
//
|
||||
//=========================================================================
|
||||
|
||||
package magic.grammar;
|
||||
|
||||
|
||||
//HHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHH
|
||||
//
|
||||
// Wrapper for parser input in the form of a string.
|
||||
//
|
||||
//HHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHH
|
||||
|
||||
public class SourceString implements Source
|
||||
{
|
||||
//=====================================================================
|
||||
//
|
||||
// Data.
|
||||
//
|
||||
//=====================================================================
|
||||
//-------------------------------------------------------------------
|
||||
// The String.
|
||||
// Note: it is the string given to the constructor, not a copy.
|
||||
//-------------------------------------------------------------------
|
||||
final String text;
|
||||
|
||||
//=====================================================================
|
||||
//
|
||||
// Constructor. Wraps the string 's'.
|
||||
//
|
||||
//=====================================================================
|
||||
public SourceString(final String s)
|
||||
{ text = s; }
|
||||
|
||||
|
||||
//=====================================================================
|
||||
//
|
||||
// Interface methods.
|
||||
//
|
||||
//=====================================================================
|
||||
//-------------------------------------------------------------------
|
||||
// Is the wrapper correctly initialized?
|
||||
//-------------------------------------------------------------------
|
||||
public boolean created()
|
||||
{ return true; }
|
||||
|
||||
//-------------------------------------------------------------------
|
||||
// Returns end position.
|
||||
//-------------------------------------------------------------------
|
||||
public int end()
|
||||
{ return text.length(); }
|
||||
|
||||
//-------------------------------------------------------------------
|
||||
// Returns character at position p.
|
||||
//-------------------------------------------------------------------
|
||||
public char at(int p)
|
||||
{ return text.charAt(p); }
|
||||
|
||||
//-------------------------------------------------------------------
|
||||
// Returns characters at positions p through q-1.
|
||||
//-------------------------------------------------------------------
|
||||
public String at(int p, int q)
|
||||
{ return text.substring(p,q); }
|
||||
|
||||
//-------------------------------------------------------------------
|
||||
// Describes position p in terms of preceding text.
|
||||
//-------------------------------------------------------------------
|
||||
public String where(int p)
|
||||
{
|
||||
if (p>15)
|
||||
return "After '... " + text.substring(p-15,p) + "'";
|
||||
else if (p>0)
|
||||
return "After '" + text.substring(0,p) + "'";
|
||||
else
|
||||
return "At start";
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue