/* * Parser and Lexer for Standard Audio Orchestra Language (SAOL) * as defined in ISO/IEC 14496-3:1999(E) * * Author: Ross Bencina * * Version 1.0 - 29th August 2000 * - initial release * * * Thanks to: * - Eric Scheirer for the ISO reference YACC grammar * - Terrence Parr and the ANTLR crew for their example grammars * which made writing this ANTLR SAOL grammar (relatively) easy. * - Sinan Karasu and Mike Barnett for helping with the * productions for parsing maplists * * Compiles with ANTLR 2.7.0, see http://www.antlr.org/ * * * * This grammar is in the PUBLIC DOMAIN */ options { language="Cpp"; } //---------------------------------------------------------------------------- // The SAOL parser //---------------------------------------------------------------------------- class SaolParser extends Parser; options { k=2; exportVocab=SAOL; buildAST=true; } tokens{ // imaginary tokens BUSS; BUSSES; INSTRUMENT; INSTRUMENTS; PFIELDS; PARAMS; DECLS; BLOCK; TEMPLATEVARS; MAPLIST; } orchestra : (globalBlock | instrDef | opcodeDef | templateDecl)* EOF! ; globalBlock : GLOBAL^ LCURLY! (globalStatement)* RCURLY! ; globalStatement : globalParam | globalVarDecl | routeStatement | sendStatement | sequenceSpec ; globalParam : SRATE^ NUM_INT SEMI! | KRATE^ NUM_INT SEMI! | INCHANNELS^ NUM_INT SEMI! | OUTCHANNELS^ NUM_INT SEMI! | INTERP^ NUM_INT SEMI! ; routeStatement! : ROUTE LPAREN a:IDENT COMMA b:identlist RPAREN SEMI { #routeStatement = #(ROUTE, #a, #([INSTRUMENTS], #b) ); } ; sendStatement! : SEND LPAREN a:IDENT SEMI (b:exprList)? SEMI c:identlist RPAREN SEMI { #sendStatement = #(SEND, #a, #([PFIELDS], #b), #([BUSSES], #c) ); } ; sequenceSpec : SEQUENCE^ LPAREN! identlist RPAREN! SEMI! ; instrDef! : INSTR a:IDENT LPAREN b:identlist RPAREN (PRESET c:presetlist )? LCURLY d:instrVarDecls e:instrBlock RCURLY { #instrDef = #(INSTR, #a, #([PFIELDS], #b), #([PRESET], #c), #([DECLS], #d), #([BLOCK], #e)); } ; opcodeDef! : a:opcodeRate b:IDENT LPAREN c:formalParamList RPAREN LCURLY d:opcodeVarDecls e:opcodeBlock RCURLY { #opcodeDef = #([OPCODE], #a, #b, #([PARAMS], #c), #([DECLS], #d), #([BLOCK], #e)); } ; templateDecl : TEMPLATE LT_ identlist GT (PRESET LT_ intlist (GT COMMA LT_ intlist)* GT)? LPAREN identlist RPAREN MAP LCURLY identlist RCURLY WITH LCURLY LT_ exprList (GT COMMA LT_ exprList)* GT RCURLY LCURLY instrVarDecls instrBlock RCURLY ; intlist : ( NUM_INT (COMMA! NUM_INT)* )? ; presetlist : (NUM_INT)+ ; identlist : ( IDENT (COMMA! IDENT)* )? ; formalParamList : ( formalParam (COMMA! formalParam)* )? ; globalVarDecl : ( IVAR^ | KSIG^ ) namelist SEMI! | tableDecl ; instrVarDecls : (instrVarDecl)* ; instrVarDecl : ( IVAR^ | KSIG^ | ASIG^ ) namelist SEMI! | sharingTag ( ( ( IVAR^ | KSIG^ ) namelist) | (TABLE^ identlist) ) SEMI! | tableDecl | OPARRAY^ IDENT LBRACK! arrayLength RBRACK! SEMI! | tablemapDecl ; opcodeVarDecls : (opcodeVarDecl)* ; opcodeVarDecl : instrVarDecl | XSIG^ namelist SEMI! ; sharingTag : IMPORTS (EXPORTS)? | EXPORTS ; tableDecl! : TABLE a:IDENT LPAREN b:IDENT COMMA c:expr d:(COMMA exprStrList)? RPAREN SEMI { #tableDecl = #( TABLE, #a, #b, #c, #([PARAMS], #d)); } ; tablemapDecl : TABLEMAP^ IDENT LPAREN! identlist RPAREN! SEMI! ; arrayLength : ( NUM_INT | INCHANNELS | OUTCHANNELS ) ; formalParam : ( ASIG^ | KSIG^ | IVAR^ | XSIG^ ) name | TABLE^ IDENT ; namelist : name (COMMA! name)* ; name : IDENT^ (LBRACK! ( NUM_INT | INCHANNELS | OUTCHANNELS ) RBRACK!)? ; opcodeRate : ( AOPCODE | KOPCODE | IOPCODE | OPCODE ) ; instrBlock : (instrStatement)* ; instrStatement : instrAndOpcodeStatement | IF^ LPAREN^ expr RPAREN! LCURLY^ instrBlock RCURLY! (ELSE! LCURLY^ instrBlock RCURLY!)? | WHILE^ LPAREN^ expr RPAREN! LCURLY^ instrBlock RCURLY! ; opcodeBlock : (opcodeStatement)* ; opcodeStatement : instrAndOpcodeStatement | IF^ LPAREN^ expr RPAREN! LCURLY^ opcodeBlock RCURLY! (ELSE! LCURLY^ opcodeBlock RCURLY!)? | WHILE^ LPAREN^ expr RPAREN! LCURLY^ opcodeBlock RCURLY! | RETURN^ LPAREN! exprList RPAREN! SEMI! ; instrAndOpcodeStatement : (lvalue ASSIGN)=> lvalue ASSIGN^ expr SEMI! | expr SEMI! | INSTR^ IDENT LPAREN! exprList RPAREN! SEMI! | OUTPUT^ LPAREN! exprList RPAREN! SEMI! | SPATIALIZE^ LPAREN! exprList RPAREN! SEMI! | OUTBUS^ LPAREN! IDENT COMMA! exprList RPAREN! SEMI! | EXTEND^ LPAREN! expr RPAREN! SEMI! | TURNOFF^ SEMI! ; lvalue : IDENT (LBRACK^ expr RBRACK!)? ; exprStrList : (expr | STRING_LITERAL) (COMMA! (expr | STRING_LITERAL))* ; exprList : expr (COMMA! expr)* ; expr : conditionalExpr ; conditionalExpr : logicalOrExpr (QUESTION^ expr COLON! conditionalExpr)? ; logicalOrExpr : logicalAndExpr ( OR^ logicalAndExpr)* ; logicalAndExpr : equalityExpr ( AND^ equalityExpr)* ; equalityExpr : relationalExpr ( (EQUAL^ | NOT_EQUAL^) relationalExpr )* ; // right recursion is necessary here to handle maplists correctly // eg: { < 1 > 3 > 4 > 5, 6 > 7 >, < 1 > } relationalExpr : additiveExpr (((LT_^|GT^|LEQ^|GEQ^) additiveExpr)=> ((LT_^|GT^|LEQ^|GEQ^) relationalExpr) )? ; additiveExpr : multExpr ( (PLUS^ | MINUS^) multExpr)* ; multExpr : unaryExpr ( (STAR^ | SLASH^) unaryExpr)* ; unaryExpr : MINUS^ unaryExpr | NOT^ unaryExpr | primaryExpr ; primaryExpr : IDENT^ (LBRACK^ expr RBRACK!)? (LPAREN^ (exprList)? RPAREN!)? // ident, array loopkup, opcode call or oparray call | LPAREN^ expr RPAREN! // paren grouping | SASBF^ LPAREN! exprList RPAREN! | numericConstant ; numericConstant : NUM_INT | NUM_FLOAT ; //---------------------------------------------------------------------------- // The SAOL scanner //---------------------------------------------------------------------------- class SaolLexer extends Lexer; options { exportVocab=SAOL; k=3; charVocabulary='\3'..'\377'; testLiterals=false; } tokens{ AOPCODE = "aopcode" ; ASIG = "asig" ; ELSE = "else" ; EXPORTS = "exports" ; EXTEND = "extend" ; GLOBAL = "global" ; IF = "if" ; IMPORTS = "imports" ; INCHANNELS = "inchannels" ; INSTR = "instr" ; INTERP = "interp" ; IOPCODE = "iopcode" ; IVAR = "ivar" ; KOPCODE = "kopcode" ; KRATE = "krate" ; KSIG = "ksig" ; MAP = "map" ; OPARRAY = "oparray" ; OPCODE = "opcode" ; OUTBUS = "outbus" ; OUTCHANNELS = "outchannels" ; OUTPUT = "output" ; PRESET = "preset" ; RETURN = "return" ; ROUTE = "route" ; SEND = "send" ; SEQUENCE = "sequence" ; SASBF = "sasbf" ; SPATIALIZE = "spatialize" ; SRATE = "srate" ; TABLE = "table" ; TABLEMAP = "tablemap" ; TEMPLATE = "template" ; TURNOFF = "turnoff" ; WHILE = "while" ; WITH = "with" ; XSIG = "xsig" ; } // Whitespace -- ignored WS : ( ' ' | '\t' | '\f' // handle newlines | ( "\r\n" // Evil DOS | '\r' // Macintosh | '\n' // Unix (the right way) ) { newline(); } ) { _ttype = antlr::Token::SKIP; } ; // Single line comment COMMENT : ( "//" (~('\n'|'\r'))* ('\n'|'\r'('\n')?) ) { _ttype = antlr::Token::SKIP; newline(); } ; AND options { paraphrase="&&"; } : "&&" ; OR options { paraphrase="||"; } : "||" ; GEQ options { paraphrase=">="; } : ">=" ; LEQ options { paraphrase="<="; } : "<=" ; NOT_EQUAL options { paraphrase="!="; } : "!=" ; EQUAL options { paraphrase="=="; } : "==" ; MINUS options { paraphrase="-"; } : '-' ; STAR options { paraphrase="*"; } : '*' ; SLASH options { paraphrase="/"; } : '/' ; PLUS options { paraphrase="+"; } : '+' ; LT_ options { paraphrase="<"; } : '<' ; GT options { paraphrase=">"; } : '>' ; QUESTION options { paraphrase="?"; } : '?' ; COLON options { paraphrase=":"; } : ':' ; LPAREN options { paraphrase="("; } : '(' ; RPAREN options { paraphrase=")"; } : ')' ; LCURLY options { paraphrase="{"; } : '{' ; RCURLY options { paraphrase="}"; } : '}' ; LBRACK options { paraphrase="["; } : '[' ; RBRACK options { paraphrase="]"; } : ']' ; SEMI options { paraphrase=";"; } : ';' ; COMMA options { paraphrase=","; } : ',' ; NOT options { paraphrase="!"; } : '!' ; ASSIGN options { paraphrase="="; } : '=' ; IDENT options { paraphrase="an identifier"; testLiterals=true; } : ('a'..'z'|'A'..'Z'|'_') ('a'..'z'|'A'..'Z'|'_'|'0'..'9')* ; STRING_LITERAL options { paraphrase="a string literal"; } : '"' ( ('\\' '\"') | ~'"' )* '"' ; NUM_INT options { paraphrase="a number"; } : '.' ('0'..'9')+ (EXPONENT)? { _ttype = NUM_FLOAT; } | ( '0' // special case for just '0' | ('1'..'9') ('0'..'9')* // non-zero int ) ( ( '.' ('0'..'9')* (EXPONENT)? | EXPONENT ) { _ttype = NUM_FLOAT; } )? ; protected EXPONENT : 'e' ('+'|'-')? ('0'..'9')+ ;