move parser code from grammar to src/magic/grammar

master
melvin 2012-12-13 14:12:53 +08:00
parent e6f09e1d07
commit 6acc44d88a
14 changed files with 6814 additions and 2 deletions

View File

@ -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

View File

@ -1,4 +1,6 @@
import mouse.runtime.SourceString;
package magic.grammar;
import magic.grammar.SourceString;
import java.util.Scanner;
class Check {

View File

@ -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

View File

@ -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();

View File

@ -1,3 +1,5 @@
package magic.grammar;
import java.util.List;
import java.util.LinkedList;

View File

@ -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;
}
}
}
}
}

View File

@ -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;
}
}
}

View File

@ -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);
}
}
}

View File

@ -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);
}

View File

@ -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); }
}

View File

@ -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);
}

View File

@ -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; }
}

View File

@ -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";
}
}