Files
msproj/data/SGF.g

215 lines
6.1 KiB
Plaintext

grammar SGF;
@header {package net.woodyfolsom.msproj.sgf;}
@lexer::header {package net.woodyfolsom.msproj.sgf;}
collection returns [SGFNodeCollection sgfNodeCollection]
@init {
$sgfNodeCollection = new SGFNodeCollection();
}
: (gameTree{$sgfNodeCollection.add($gameTree.sgfGameTree);})+
;
gameTree returns [SGFGameTree sgfGameTree]
@init {
$sgfGameTree = new SGFGameTree();
}
: LPAREN sequence{$sgfGameTree.setNodeSequence($sequence.nodeSequence);} (gameTree{$sgfGameTree.addSubTree(sgfGameTree);})* RPAREN
;
sequence returns [List<SGFNode> nodeSequence]
@init {
$nodeSequence = new ArrayList<SGFNode>();
}
: (node{$nodeSequence.add($node.sgfNode);})+;
node returns [SGFNode sgfNode]
@init {
$sgfNode = new SGFNode();
}
: SEMICOLON (property{$sgfNode.addProperty($property.sgfProperty);})*;
property returns [SGFProperty sgfProperty]
@init {
$sgfProperty = new SGFProperty();
}
: (numIdent{$sgfProperty.setIdentifier($numIdent.sgfIdent);}) ((LBRACKET numValue RBRACKET){$sgfProperty.addValue($numValue.sgfValue);})+
//an empty coord is a pass move
| (playerIdent{$sgfProperty.setIdentifier($playerIdent.sgfPlayer);}) ((LBRACKET RBRACKET){sgfProperty.addValue(SGFValue.EMPTY);})+
| (playerIdent{$sgfProperty.setIdentifier($playerIdent.sgfPlayer);}) ((LBRACKET coordValue RBRACKET){sgfProperty.addValue(new SGFValue<SGFCoord>($coordValue.sgfCoord));})+
// 2 rules here because the disambiguating semantic pred. for 'player' would throw NPE
| (strIdent{$sgfProperty.setIdentifier($strIdent.sgfIdent);}) ((LBRACKET RBRACKET){$sgfProperty.addValue(SGFValue.EMPTY);})
| (strIdent{$sgfProperty.setIdentifier($strIdent.sgfIdent);}) ((LBRACKET strValue RBRACKET){$sgfProperty.addValue(new SGFValue<String>($strValue.text));})+
| (result{$sgfProperty.setIdentifier(SGFIdentifier.RESULT);}) ((LBRACKET strValue RBRACKET){$sgfProperty.addValue(new SGFValue<SGFResult>(new SGFResult($strValue.text)));})+
| (komi{$sgfProperty.setIdentifier(SGFIdentifier.KOMI);}) ((LBRACKET realValue RBRACKET){$sgfProperty.addValue(new SGFValue<Double>(Double.parseDouble($realValue.text)));})+
| (coordIdent{$sgfProperty.setIdentifier($coordIdent.sgfIdent);})((LBRACKET coordValue RBRACKET){$sgfProperty.addValue(new SGFValue<SGFCoord>(new SGFCoord($coordValue.text)));})+
;
//playerIdent is a disambiguating rule
playerIdent returns [SGFIdentifier sgfPlayer]
: {(input.LT(1).getText().equals("W"))}? strIdent {$sgfPlayer = $strIdent.sgfIdent;}
| {(input.LT(1).getText().equals("B"))}? strIdent {$sgfPlayer = $strIdent.sgfIdent;}
| {(input.LT(1).getText().equals("White"))}? strIdent {$sgfPlayer = $strIdent.sgfIdent;}
| {(input.LT(1).getText().equals("Black"))}? strIdent {$sgfPlayer = $strIdent.sgfIdent;}
;
strIdent returns [SGFIdentifier sgfIdent]
: charEnc{$sgfIdent = SGFIdentifier.CHARSET;}
| source{$sgfIdent = SGFIdentifier.SOURCE;}
| blackCountry{$sgfIdent = SGFIdentifier.COUNTRY_BLACK;}
| whiteCountry{$sgfIdent = SGFIdentifier.COUNTRY_WHITE;}
| event{$sgfIdent = SGFIdentifier.EVENT;}
| playerBlack{$sgfIdent = SGFIdentifier.PLAYER_BLACK;}
| playerWhite{$sgfIdent = SGFIdentifier.PLAYER_WHITE;}
| blackRank{$sgfIdent = SGFIdentifier.RANK_BLACK;}
| whiteRank{$sgfIdent = SGFIdentifier.RANK_WHITE;}
| rules{$sgfIdent = SGFIdentifier.RULES;}
| place{$sgfIdent = SGFIdentifier.PLACE;}
| application{$sgfIdent = SGFIdentifier.APPLICATION;}
| copyright
| username
| date{$sgfIdent = SGFIdentifier.DATE;}
| 'Black'{$sgfIdent = SGFIdentifier.MOVE_BLACK;}
| 'White'{$sgfIdent = SGFIdentifier.MOVE_WHITE;}
| 'B'{$sgfIdent = SGFIdentifier.MOVE_BLACK;}
| 'W'{$sgfIdent = SGFIdentifier.MOVE_WHITE;}
| view{$sgfIdent = SGFIdentifier.VIEW;} //this is not really a strIdent, but is a placeholder since I don't use this info
| comment{$sgfIdent = SGFIdentifier.COMMENT;}
//SGF grammar proper allows extensions, but this reader does not
; //if this is matched from rule playerIdent, the value is thrown away - this rule alone
//lack the context to disambiguate the single-character player movement IDs.
coordIdent returns [SGFIdentifier sgfIdent]
: addBlack{$sgfIdent = $addBlack.sgfIdent;}
| addWhite{$sgfIdent = $addWhite.sgfIdent;}
;
numIdent returns [SGFIdentifier sgfIdent]
: fileFormat{$sgfIdent = SGFIdentifier.FILE_FORMAT;}
| game{$sgfIdent = SGFIdentifier.GAME;}
| size{$sgfIdent = SGFIdentifier.SIZE;}
| time{$sgfIdent = SGFIdentifier.TIME;};
numValue returns [SGFValue<Integer> sgfValue]
: (STRVALUE){$sgfValue = new SGFValue<Integer>(Integer.parseInt($numValue.text));};
realIdent
: komi;
realValue
: STRVALUE;
coordValue returns [SGFCoord sgfCoord]
: STRVALUE {$sgfCoord = new SGFCoord($coordValue.text);}
;
fileFormat
: 'FF';
game : 'GM' | 'GaMe';
size : 'SZ' | 'SiZe';
view : 'VW' | 'VieW';
charEnc : 'CA';
source : 'SO';
blackCountry
: 'BC';
whiteCountry
: 'WC';
event : 'EV' | 'EVent';
playerBlack
: 'PB' | 'PlayerBlack';
playerWhite
: 'PW' | 'PlayerWhite';
blackRank
: 'BR';
whiteRank
: 'WR';
komi : 'KM';
result : 'RE'
| 'REsult'
;
rules : 'RU';
place : 'PC' | 'PlaCe';
application
: 'AP';
time : 'TM';
date : 'DT' | 'DaTe';
addBlack returns [SGFIdentifier sgfIdent]
: 'AB'{$sgfIdent = SGFIdentifier.ADD_BLACK;}
;
addWhite returns [SGFIdentifier sgfIdent]
: 'AW'{$sgfIdent = SGFIdentifier.ADD_WHITE;}
;
copyright
: 'CP';
username: 'US';
comment : 'C';
strValue
: (STRVALUE)+;
SPACE : ' ';
fragment DIGIT : '0'..'9';
COLON : ':';
MINUS : '-';
fragment PERIOD : '.';
COMMA : ',';
PLUS : '+';
SLASH : '/';
STRVALUE : (UCLETTER | LCLETTER | MINUS | DIGIT | SPACE | PERIOD | COMMA | PLUS | SLASH | COLON )+;
LPAREN : '(' ;
SEMICOLON : ';' ;
fragment UCLETTER : 'A'..'Z';
fragment LCLETTER : 'a'..'z';
LBRACKET
: '[';
RBRACKET
: ']';
RPAREN : ')';
//CR : '\r'{$channel=HIDDEN;};
//NEWLINE : '\n'{$channel=HIDDEN;};