1 //=== LexHLSLRootSignature.cpp - Lex Root Signature -----------------------===// 2 // 3 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 4 // See https://llvm.org/LICENSE.txt for license information. 5 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 6 // 7 //===----------------------------------------------------------------------===// 8 9 #include "clang/Lex/LexHLSLRootSignature.h" 10 11 namespace clang { 12 namespace hlsl { 13 14 using TokenKind = RootSignatureToken::Kind; 15 16 // Lexer Definitions 17 18 static bool isNumberChar(char C) { 19 return isdigit(C) // integer support 20 || C == '.' // float support 21 || C == 'e' || C == 'E' || C == '-' || C == '+' // exponent support 22 || C == 'f' || C == 'F'; // explicit float support 23 } 24 25 RootSignatureToken RootSignatureLexer::lexToken() { 26 // Discard any leading whitespace 27 advanceBuffer(Buffer.take_while(isspace).size()); 28 29 if (isEndOfBuffer()) 30 return RootSignatureToken(TokenKind::end_of_stream, LocOffset); 31 32 // Record where this token is in the text for usage in parser diagnostics 33 RootSignatureToken Result(LocOffset); 34 35 char C = Buffer.front(); 36 37 // Punctuators 38 switch (C) { 39 #define PUNCTUATOR(X, Y) \ 40 case Y: { \ 41 Result.TokKind = TokenKind::pu_##X; \ 42 advanceBuffer(); \ 43 return Result; \ 44 } 45 #include "clang/Lex/HLSLRootSignatureTokenKinds.def" 46 default: 47 break; 48 } 49 50 // Number literal 51 if (isdigit(C) || C == '.') { 52 Result.NumSpelling = Buffer.take_while(isNumberChar); 53 54 // If all values are digits then we have an int literal 55 bool IsInteger = Result.NumSpelling.find_if_not(isdigit) == StringRef::npos; 56 57 Result.TokKind = 58 IsInteger ? TokenKind::int_literal : TokenKind::float_literal; 59 advanceBuffer(Result.NumSpelling.size()); 60 return Result; 61 } 62 63 // All following tokens require at least one additional character 64 if (Buffer.size() <= 1) { 65 Result = RootSignatureToken(TokenKind::invalid, LocOffset); 66 return Result; 67 } 68 69 // Peek at the next character to deteremine token type 70 char NextC = Buffer[1]; 71 72 // Registers: [tsub][0-9+] 73 if ((C == 't' || C == 's' || C == 'u' || C == 'b') && isdigit(NextC)) { 74 // Convert character to the register type. 75 switch (C) { 76 case 'b': 77 Result.TokKind = TokenKind::bReg; 78 break; 79 case 't': 80 Result.TokKind = TokenKind::tReg; 81 break; 82 case 'u': 83 Result.TokKind = TokenKind::uReg; 84 break; 85 case 's': 86 Result.TokKind = TokenKind::sReg; 87 break; 88 default: 89 llvm_unreachable("Switch for an expected token was not provided"); 90 } 91 92 advanceBuffer(); 93 94 // Lex the integer literal 95 Result.NumSpelling = Buffer.take_while(isNumberChar); 96 advanceBuffer(Result.NumSpelling.size()); 97 98 return Result; 99 } 100 101 // Keywords and Enums: 102 StringRef TokSpelling = 103 Buffer.take_while([](char C) { return isalnum(C) || C == '_'; }); 104 105 // Define a large string switch statement for all the keywords and enums 106 auto Switch = llvm::StringSwitch<TokenKind>(TokSpelling); 107 #define KEYWORD(NAME) Switch.CaseLower(#NAME, TokenKind::kw_##NAME); 108 #define ENUM(NAME, LIT) Switch.CaseLower(LIT, TokenKind::en_##NAME); 109 #include "clang/Lex/HLSLRootSignatureTokenKinds.def" 110 111 // Then attempt to retreive a string from it 112 Result.TokKind = Switch.Default(TokenKind::invalid); 113 advanceBuffer(TokSpelling.size()); 114 return Result; 115 } 116 117 RootSignatureToken RootSignatureLexer::consumeToken() { 118 // If we previously peeked then just return the previous value over 119 if (NextToken && NextToken->TokKind != TokenKind::end_of_stream) { 120 RootSignatureToken Result = *NextToken; 121 NextToken = std::nullopt; 122 return Result; 123 } 124 return lexToken(); 125 } 126 127 RootSignatureToken RootSignatureLexer::peekNextToken() { 128 // Already peeked from the current token 129 if (NextToken) 130 return *NextToken; 131 132 NextToken = lexToken(); 133 return *NextToken; 134 } 135 136 } // namespace hlsl 137 } // namespace clang 138