1
1
#include " DefineFinder.h"
2
2
3
- #include < clang/Basic/IdentifierTable.h>
4
- #include < clang/Lex/LiteralSupport.h>
5
- #include < clang/Lex/MacroInfo.h>
6
3
#include < llvm/ADT/APInt.h>
7
- #include < llvm/ADT/APSInt.h>
8
4
9
5
DefineFinder::DefineFinder (IR &ir, const clang::CompilerInstance &compiler,
10
6
clang::Preprocessor &pp)
@@ -20,55 +16,80 @@ void DefineFinder::MacroDefined(const clang::Token ¯oNameTok,
20
16
* Ignore function-like definitions because they usually are meaningful
21
17
* only inside C functions. */
22
18
23
- const clang::Token *token = expandDefine (*md);
24
- if (!token ) {
19
+ std::vector< clang::Token> *tokens = expandDefine (*md);
20
+ if (!tokens ) { // there was function-like macro
25
21
return ;
26
22
}
27
23
std::string macroName = macroNameTok.getIdentifierInfo ()->getName ();
28
24
29
- if (token->isLiteral ()) {
30
- /* might be converted directly to Scala code */
31
- std::string literal (token->getLiteralData (), token->getLength ());
32
- if (token->getKind () == clang::tok::numeric_constant) {
33
- addNumericConstantDefine (macroName, literal, token);
34
- } else if (token->getKind () == clang::tok::string_literal) {
35
- ir.addLiteralDefine (macroName, " c" + literal, " native.CString" );
36
- } else {
37
- llvm::errs () << " Warning: type of literal " << token->getName ()
38
- << " is unsupported\n " ;
39
- llvm::errs ().flush ();
40
- }
41
- } else if (token->isAnyIdentifier ()) {
42
- // TODO: save identifier and get its type in ScalaFrontendAction
25
+ if (tokens->size () == 1 &&
26
+ (*tokens)[0 ].getKind () == clang::tok::numeric_constant) {
27
+ clang::Token numberToken = (*tokens)[0 ];
28
+ std::string literal (numberToken.getLiteralData (),
29
+ numberToken.getLength ());
30
+ addNumericConstantDefine (macroName, literal, numberToken);
31
+ } else if (tokens->size () == 2 &&
32
+ (*tokens)[0 ].getKind () == clang::tok::minus &&
33
+ (*tokens)[1 ].getKind () == clang::tok::numeric_constant) {
34
+ clang::Token numberToken = (*tokens)[1 ];
35
+ std::string literal (numberToken.getLiteralData (),
36
+ numberToken.getLength ());
37
+ addNumericConstantDefine (macroName, literal, numberToken, false );
38
+ } else if (tokens->size () == 1 &&
39
+ (*tokens)[0 ].getKind () == clang::tok::string_literal) {
40
+ clang::Token stringToken = (*tokens)[0 ];
41
+ std::string literal (stringToken.getLiteralData (),
42
+ stringToken.getLength ());
43
+ ir.addLiteralDefine (macroName, " c" + literal, " native.CString" );
43
44
}
45
+ std::free (tokens);
44
46
}
45
47
}
46
48
47
49
/* *
48
- * Follows simple chain of defines.
49
- *
50
- * @return token that is not a define
50
+ * @return array of tokens. Non of the returned tokens is a macro.
51
51
*/
52
- const clang::Token *
52
+ std::vector< clang::Token> *
53
53
DefineFinder::expandDefine (const clang::MacroDirective &md) {
54
+ auto *expandedTokens = new std::vector<clang::Token>();
54
55
clang::ArrayRef<clang::Token> tokens = md.getMacroInfo ()->tokens ();
55
- if (tokens.size () != 1 ) {
56
- /* process only simple definitions that contain 1 token */
57
- return nullptr ;
58
- }
59
- clang::Token token = tokens[0 ];
60
- if (!(token.isAnyIdentifier () || token.isLiteral ())) {
61
- /* unsupported */
62
- return nullptr ;
63
- }
64
- if (token.isLiteral () || !token.getIdentifierInfo ()->hasMacroDefinition ()) {
65
- return &(tokens[0 ]);
56
+ for (const auto &token : tokens) {
57
+ if (isMacro (token)) {
58
+ if (isFunctionLikeMacro (token)) {
59
+ /* function-like macros are unsupported */
60
+ return nullptr ;
61
+ }
62
+ std::vector<clang::Token> *newTokens = expandDefine (
63
+ *pp.getLocalMacroDirective (token.getIdentifierInfo ()));
64
+ if (!newTokens) {
65
+ std::free (expandedTokens);
66
+ return nullptr ;
67
+ }
68
+ for (const auto &newToken : *newTokens) {
69
+ (*expandedTokens).push_back (newToken);
70
+ }
71
+ std::free (newTokens);
72
+ } else {
73
+ (*expandedTokens).push_back (token);
74
+ }
66
75
}
67
- return expandDefine (*pp.getLocalMacroDirective (token.getIdentifierInfo ()));
76
+ return expandedTokens;
77
+ }
78
+
79
+ bool DefineFinder::isMacro (const clang::Token &token) {
80
+ return token.isAnyIdentifier () &&
81
+ token.getIdentifierInfo ()->hasMacroDefinition ();
82
+ }
83
+
84
+ bool DefineFinder::isFunctionLikeMacro (const clang::Token &token) {
85
+ clang::MacroDirective *md =
86
+ pp.getLocalMacroDirective (token.getIdentifierInfo ());
87
+ return md->getMacroInfo ()->isFunctionLike ();
68
88
}
69
89
70
90
void DefineFinder::MacroUndefined (const clang::Token ¯oNameTok,
71
- const clang::MacroDefinition &md) {
91
+ const clang::MacroDefinition &md,
92
+ const clang::MacroDirective *undef) {
72
93
clang::SourceManager &sm = compiler.getSourceManager ();
73
94
if (sm.isWrittenInMainFile (macroNameTok.getLocation ()) &&
74
95
!md.getMacroInfo ()->isFunctionLike ()) {
@@ -79,8 +100,9 @@ void DefineFinder::MacroUndefined(const clang::Token ¯oNameTok,
79
100
80
101
void DefineFinder::addNumericConstantDefine (const std::string ¯oName,
81
102
std::string literal,
82
- const clang::Token *token) {
83
- clang::NumericLiteralParser parser (literal, token->getLocation (), pp);
103
+ const clang::Token &token,
104
+ bool positive) {
105
+ clang::NumericLiteralParser parser (literal, token.getLocation (), pp);
84
106
std::string type;
85
107
if (parser.isIntegerLiteral ()) {
86
108
std::replace (literal.begin (), literal.end (), ' l' , ' L' );
@@ -98,50 +120,63 @@ void DefineFinder::addNumericConstantDefine(const std::string ¯oName,
98
120
* is a long value.
99
121
* Therefore we need to check that value fits into certain number
100
122
* of bits. */
101
- getTypeOfIntLiteralWithoutEnding (parser, literal, type);
123
+ getTypeOfIntLiteralWithoutEnding (parser, literal, type, positive );
102
124
}
103
125
} else {
104
- if (parser.isFloat ) {
105
- type = " native.CFloat " ;
126
+ if (parser.isFloatingLiteral () ) {
127
+ type = " native.CDouble " ;
106
128
// TODO: distinguish between float and double
107
129
}
108
130
}
109
131
if (!type.empty ()) {
132
+ if (!positive) {
133
+ literal = " -" + literal;
134
+ }
110
135
ir.addLiteralDefine (macroName, literal, type);
111
136
}
112
137
}
113
138
114
- /* *
115
- * Check if literal without `l` or `ll` ending fits into int or long variable.
116
- * Supports only non-negative numbers
117
- *
118
- * Set `literal` and `type` parameters.
119
- */
120
139
void DefineFinder::getTypeOfIntLiteralWithoutEnding (
121
- clang::NumericLiteralParser parser, std::string &literal,
122
- std::string &type ) {
140
+ clang::NumericLiteralParser parser, std::string &literal, std::string &type,
141
+ bool positive ) {
123
142
124
- llvm::APInt intValue (4 * 8 - 1 , 0 , false );
125
- /* check if abs value fits into 4 * 8 - 1 bits */
126
- if (!parser.GetIntegerValue (intValue)) {
143
+ if (fitsIntoType<int , uint>(parser, positive)) {
127
144
type = " native.CInt" ;
145
+ } else if (fitsIntoType<long , ulong>(parser, positive)) {
146
+ type = " native.CLong" ;
147
+ literal = literal + " L" ;
128
148
} else {
129
- llvm::APInt longValue (8 * 8 - 1 , 0 , false );
130
- if (!parser.GetIntegerValue (longValue)) {
131
- type = " native.CLong" ;
132
- literal = literal + " L" ;
133
- } else {
134
- llvm::errs () << " Waring: integer value does not fit into 8 bytes: "
135
- << literal << " \n " ;
136
- llvm::errs ().flush ();
137
- /* *
138
- * `long long` value has mostly the same size as `long`.
139
- * Moreover in Scala Native the type is represented as `Long`:
140
- * @code
141
- * type CLongLong = Long
142
- * @endcode
143
- * Therefore the case of `long long` is not considered here.
144
- */
145
- }
149
+ llvm::errs () << " Waring: integer value does not fit into 8 bytes: "
150
+ << literal << " \n " ;
151
+ llvm::errs ().flush ();
152
+ /* *
153
+ * `long long` value has mostly the same size as `long`.
154
+ * Moreover in Scala Native the type is represented as `Long`:
155
+ * @code
156
+ * type CLongLong = Long
157
+ * @endcode
158
+ * Therefore the case of `long long` is not considered here.
159
+ */
160
+ }
161
+ }
162
+
163
+ template <typename signedT, typename unsignedT>
164
+ bool DefineFinder::fitsIntoType (clang::NumericLiteralParser parser,
165
+ bool positive) {
166
+ /* absolute value of minimum negative number will not fit
167
+ * into (sizeof(signedT) * 8 - 1) bits */
168
+ llvm::APInt uintValue (sizeof (signedT) * 8 , 0 , false );
169
+ if (parser.GetIntegerValue (uintValue)) {
170
+ /* absolute value of the number does not fit into (sizeof(signedT) * 8)
171
+ * bits */
172
+ return false ;
173
+ }
174
+ auto uval = static_cast <unsignedT>(uintValue.getZExtValue ());
175
+ if (positive) {
176
+ return uval <=
177
+ static_cast <unsignedT>(std::numeric_limits<signedT>::max ());
178
+ } else {
179
+ return uval <=
180
+ static_cast <unsignedT>(-std::numeric_limits<signedT>::min ());
146
181
}
147
182
}
0 commit comments