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 nodeSequence] @init { $nodeSequence = new ArrayList(); } : (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($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($strValue.text));})+ | (result{$sgfProperty.setIdentifier(SGFIdentifier.RESULT);}) ((LBRACKET resValue RBRACKET){$sgfProperty.addValue(new SGFValue(new SGFResult($resValue.text)));})+ | (komi{$sgfProperty.setIdentifier(SGFIdentifier.KOMI);}) ((LBRACKET realValue RBRACKET){$sgfProperty.addValue(new SGFValue(Double.parseDouble($realValue.text)));})+ | (coordIdent{$sgfProperty.setIdentifier($coordIdent.sgfIdent);})((LBRACKET coordValue RBRACKET){$sgfProperty.addValue(new SGFValue(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;} ; strIdent returns [SGFIdentifier sgfIdent] : charEnc{$sgfIdent = SGFIdentifier.CHARSET;} | source | blackCountry | whiteCountry | event | playerBlack | playerWhite | blackRank | whiteRank | result | rules | place | application | copyright | username | date | 'B'{$sgfIdent = SGFIdentifier.MOVE_BLACK;} | 'W'{$sgfIdent = SGFIdentifier.MOVE_WHITE;} //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 sgfValue] : (DIGIT+){$sgfValue = new SGFValue(Integer.parseInt($numValue.text));}; realIdent : komi; resValue //'R' is resign : playerIdent PLUS ('R' | realValue); realValue : DIGIT+ PERIOD DIGIT+; coordValue returns [SGFCoord sgfCoord] : LCLETTER LCLETTER {$sgfCoord = new SGFCoord($text);} ; fileFormat : 'FF'; game : 'GM'; size : 'SZ'; charEnc : 'CA'; source : 'SO'; blackCountry : 'BC'; whiteCountry : 'WC'; event : 'EV'; playerBlack : 'PB'; playerWhite : 'PW'; blackRank : 'BR'; whiteRank : 'WR'; komi : 'KM'; result : 'RE'; rules : 'RU'; place : 'PC'; application : 'AP'; time : 'TM'; date : 'DT'; addBlack returns [SGFIdentifier sgfIdent] : 'AB'{$sgfIdent = SGFIdentifier.ADD_BLACK;} ; addWhite returns [SGFIdentifier sgfIdent] : 'AW'{$sgfIdent = SGFIdentifier.ADD_WHITE;} ; copyright : 'CP'; username: 'US'; strValue : (UCLETTER | LCLETTER | MINUS | DIGIT | SPACE | PERIOD | COMMA | PLUS | SLASH | COLON)+; LPAREN : '(' ; SEMICOLON : ';' ; UCLETTER : 'A'..'Z'; LCLETTER : 'a'..'z'; DIGIT : '0'..'9'; LBRACKET : '['; RBRACKET : ']'; RPAREN : ')'; COLON : ':'; MINUS : '-'; SPACE : ' '; PERIOD : '.'; COMMA : ','; PLUS : '+'; SLASH : '/'; CR : '\r'{$channel=HIDDEN;}; NEWLINE : '\n'{$channel=HIDDEN;};