// The top-level full expression recognizer. // // expression // : assignment_expression COMMA assignment_expression COMMA assignment_expression ... // bool HlslGrammar::acceptExpression(TIntermTyped*& node) { // assignment_expression if (! acceptAssignmentExpression(node)) return false; if (! peekTokenClass(EHTokComma)) return true; do { // ... COMMA TSourceLoc loc = token.loc; advanceToken(); // ... assignment_expression TIntermTyped* rightNode = nullptr; if (! acceptAssignmentExpression(rightNode)) { expected("assignment expression"); return false; } node = intermediate.addComma(node, rightNode, loc); if (! peekTokenClass(EHTokComma)) return true; } while (true); }
// Accept a binary expression, for binary operations that // associate left-to-right. This is, it is implicit, for example // // ((a op b) op c) op d // // binary_expression // : expression op expression op expression ... // // where 'expression' is the next higher level in precedence. // bool HlslGrammar::acceptBinaryExpression(TIntermTyped*& node, PrecedenceLevel precedenceLevel) { if (precedenceLevel > PlMul) return acceptUnaryExpression(node); // assignment_expression if (! acceptBinaryExpression(node, (PrecedenceLevel)(precedenceLevel + 1))) return false; TOperator op = HlslOpMap::binary(peek()); PrecedenceLevel tokenLevel = HlslOpMap::precedenceLevel(op); if (tokenLevel < precedenceLevel) return true; do { // ... op TSourceLoc loc = token.loc; advanceToken(); // ... expression TIntermTyped* rightNode = nullptr; if (! acceptBinaryExpression(rightNode, (PrecedenceLevel)(precedenceLevel + 1))) { expected("expression"); return false; } node = intermediate.addBinaryMath(op, node, rightNode, loc); if (! peekTokenClass(EHTokComma)) return true; } while (true); }
// Accept an assignment expression, where assignment operations // associate right-to-left. This is, it is implicit, for example // // a op (b op (c op d)) // // assigment_expression // : binary_expression op binary_expression op binary_expression ... // bool HlslGrammar::acceptAssignmentExpression(TIntermTyped*& node) { if (! acceptBinaryExpression(node, PlLogicalOr)) return false; TOperator assignOp = HlslOpMap::assignment(peek()); if (assignOp == EOpNull) return true; // ... op TSourceLoc loc = token.loc; advanceToken(); // ... binary_expression // But, done by recursing this function, which automatically // gets the right-to-left associativity. TIntermTyped* rightNode = nullptr; if (! acceptAssignmentExpression(rightNode)) { expected("assignment expression"); return false; } node = intermediate.addAssign(assignOp, node, rightNode, loc); if (! peekTokenClass(EHTokComma)) return true; return true; }
// Only process the next token if it is an identifier. // Return true if it was an identifier. bool HlslGrammar::acceptIdentifier(HlslToken& idToken) { if (peekTokenClass(EHTokIdentifier)) { idToken = token; advanceToken(); return true; } return false; }
// declaration // : SEMICOLON // : fully_specified_type SEMICOLON // | fully_specified_type identifier SEMICOLON // | fully_specified_type identifier = expression SEMICOLON // | fully_specified_type identifier function_parameters SEMICOLON // function prototype // | fully_specified_type identifier function_parameters COLON semantic compound_statement // function definition // // 'node' could get created if the declaration creates code, like an initializer // or a function body. // bool HlslGrammar::acceptDeclaration(TIntermNode*& node) { node = nullptr; // fully_specified_type TType type; if (! acceptFullySpecifiedType(type)) return false; // identifier HlslToken idToken; if (acceptIdentifier(idToken)) { // = expression TIntermTyped* expressionNode = nullptr; if (acceptTokenClass(EHTokEqual)) { if (! acceptExpression(expressionNode)) { expected("initializer"); return false; } } // SEMICOLON if (acceptTokenClass(EHTokSemicolon)) { node = parseContext.declareVariable(idToken.loc, *idToken.string, type, 0, expressionNode); return true; } // function_parameters TFunction* function = new TFunction(idToken.string, type); if (acceptFunctionParameters(*function)) { // COLON semantic acceptSemantic(); // compound_statement if (peekTokenClass(EHTokLeftBrace)) return acceptFunctionDefinition(*function, node); // SEMICOLON if (acceptTokenClass(EHTokSemicolon)) return true; return false; } } // SEMICOLON if (acceptTokenClass(EHTokSemicolon)) return true; return true; }
// compilationUnit // : list of externalDeclaration // bool HlslGrammar::acceptCompilationUnit() { TIntermNode* unitNode = nullptr; while (! peekTokenClass(EHTokNone)) { // externalDeclaration TIntermNode* declarationNode; if (! acceptDeclaration(declarationNode)) return false; // hook it up unitNode = intermediate.growAggregate(unitNode, declarationNode); } // set root of AST intermediate.setTreeRoot(unitNode); return true; }
// postfix_expression // : LEFT_PAREN expression RIGHT_PAREN // | literal // | constructor // | identifier // | function_call // | postfix_expression LEFT_BRACKET integer_expression RIGHT_BRACKET // | postfix_expression DOT IDENTIFIER // | postfix_expression INC_OP // | postfix_expression DEC_OP // bool HlslGrammar::acceptPostfixExpression(TIntermTyped*& node) { // Not implemented as self-recursive: // The logical "right recursion" is done with an loop at the end // idToken will pick up either a variable or a function name in a function call HlslToken idToken; // LEFT_PAREN expression RIGHT_PAREN if (acceptTokenClass(EHTokLeftParen)) { if (! acceptExpression(node)) { expected("expression"); return false; } if (! acceptTokenClass(EHTokRightParen)) { expected("right parenthesis"); return false; } } else if (acceptLiteral(node)) { // literal (nothing else to do yet), go on to the } else if (acceptConstructor(node)) { // constructor (nothing else to do yet) } else if (acceptIdentifier(idToken)) { // identifier or function_call name if (! peekTokenClass(EHTokLeftParen)) { node = parseContext.handleVariable(idToken.loc, idToken.symbol, token.string); } else if (acceptFunctionCall(idToken, node)) { // function_call (nothing else to do yet) } else { expected("function call arguments"); return false; } } do { TSourceLoc loc = token.loc; TOperator postOp = HlslOpMap::postUnary(peek()); // Consume only a valid post-unary operator, otherwise we are done. switch (postOp) { case EOpIndexDirectStruct: case EOpIndexIndirect: case EOpPostIncrement: case EOpPostDecrement: advanceToken(); break; default: return true; } // We have a valid post-unary operator, process it. switch (postOp) { case EOpIndexDirectStruct: // todo break; case EOpIndexIndirect: { TIntermTyped* indexNode = nullptr; if (! acceptExpression(indexNode) || ! peekTokenClass(EHTokRightBracket)) { expected("expression followed by ']'"); return false; } // todo: node = intermediate.addBinaryMath( } case EOpPostIncrement: case EOpPostDecrement: node = intermediate.addUnaryMath(postOp, node, loc); break; default: assert(0); break; } } while (true); }