31 struct ci_char_traits :
public std::char_traits<char>
35 static bool eq(
char c1,
char c2) {
return toupper(c1) == toupper(c2); }
36 static bool ne(
char c1,
char c2) {
return toupper(c1) != toupper(c2); }
37 static bool lt(
char c1,
char c2) {
return toupper(c1) < toupper(c2); }
38 static bool gt(
char c1,
char c2) {
return toupper(c1) > toupper(c2); }
39 static int compare(
const char *s1,
const char *s2, std::size_t n)
53 static const char *find(
const char *s,
int n,
char a)
55 while (n-- > 0 && toupper(*s) != toupper(a))
63 typedef std::basic_string<char, ci_char_traits>
ci_string;
82 TOK_DOXYGEN_COMMENT = -7,
84 TOK_STRING_LITERAL = -100,
85 TOK_NUMBER_LITERAL = -102,
91 CMakeLexer(std::istream &is) : _lastChar(
' '), _is(is), _line(1), _col(1) {}
95 while (isspace(_lastChar) && _lastChar !=
'\r' && _lastChar !=
'\n')
97 _lastChar = getChar();
100 if (isalpha(_lastChar) || _lastChar ==
'_')
102 _identifier = _lastChar;
103 while (isalnum(_lastChar = getChar()) || _lastChar ==
'-' || _lastChar ==
'_')
105 _identifier += _lastChar;
108 if (_identifier ==
"set")
110 if (_identifier ==
"function")
112 if (_identifier ==
"macro")
114 if (_identifier ==
"endfunction")
115 return TOK_ENDFUNCTION;
116 if (_identifier ==
"endmacro")
118 return TOK_IDENTIFIER;
121 if (isdigit(_lastChar))
124 _identifier = _lastChar;
125 while (isalnum(_lastChar = getChar()) || _lastChar ==
'.' || _lastChar ==
',')
127 _identifier += _lastChar;
129 return TOK_NUMBER_LITERAL;
132 if (_lastChar ==
'#')
134 _lastChar = getChar();
135 if (_lastChar ==
'!')
140 _lastChar = getChar();
141 while (_lastChar != EOF && _lastChar !=
'\n' && _lastChar !=
'\r')
143 _identifier += _lastChar;
144 _lastChar = getChar();
146 return TOK_DOXYGEN_COMMENT;
150 while (_lastChar != EOF && _lastChar !=
'\n' && _lastChar !=
'\r')
152 _lastChar = getChar();
156 if (_lastChar ==
'"')
158 _lastChar = getChar();
160 while (_lastChar != EOF && _lastChar !=
'"')
162 _identifier += _lastChar;
163 _lastChar = getChar();
167 _lastChar = getChar();
168 return TOK_STRING_LITERAL;
172 if (_lastChar == EOF)
176 if (_lastChar ==
'\r' || _lastChar ==
'\n')
178 if (_lastChar ==
'\r')
179 _lastChar = getChar();
180 if (_lastChar ==
'\n')
181 _lastChar = getChar();
186 int thisChar = _lastChar;
187 _lastChar = getChar();
191 std::string getIdentifier()
const {
return std::string(_identifier.c_str()); }
192 int curLine()
const {
return _line; }
193 int curCol()
const {
return _col; }
202 void updateLoc(
int c)
204 if (c ==
'\n' || c ==
'\r')
215 ci_string _identifier;
230 CMakeParser(std::istream &is, std::ostream &os)
231 : _is(is), _os(os), _lexer(is), _curToken(CMakeLexer::TOK_EOF), _lastToken(CMakeLexer::TOK_EOF)
235 int curToken() {
return _curToken; }
238 _lastToken = _curToken;
239 _curToken = _lexer.getToken();
240 while (_curToken == CMakeLexer::TOK_EOL)
244 _curToken = _lexer.getToken();
258 void handleFunction()
260 if (!parseFunction())
270 if (_lastToken != CMakeLexer::TOK_DOXYGEN_COMMENT)
275 else if (!parseSet())
282 void handleDoxygenComment()
284 _os <<
"///" << _lexer.getIdentifier();
288 void handleTopLevelExpression()
295 void printError(
const char *str)
297 std::cerr <<
"Error: " << str <<
" (at line " << _lexer.curLine() <<
", col " << _lexer.curCol() <<
")";
302 if (nextToken() !=
'(')
304 printError(
"Expected '(' after MACRO");
309 std::string macroName = _lexer.getIdentifier();
310 if (curToken() != CMakeLexer::TOK_IDENTIFIER || macroName.empty())
312 printError(
"Expected macro name");
316 _os << macroName <<
'(';
317 if (nextToken() == CMakeLexer::TOK_IDENTIFIER)
319 _os << _lexer.getIdentifier();
320 while (nextToken() == CMakeLexer::TOK_IDENTIFIER)
322 _os <<
", " << _lexer.getIdentifier();
326 if (curToken() !=
')')
328 printError(
"Missing expected ')'");
342 if (nextToken() !=
'(')
344 printError(
"Expected '(' after SET");
349 std::string variableName = _lexer.getIdentifier();
350 if (curToken() != CMakeLexer::TOK_IDENTIFIER || variableName.empty())
352 printError(
"Expected variable name");
356 _os <<
"CMAKE_VARIABLE " << variableName;
359 while ((curToken() == CMakeLexer::TOK_IDENTIFIER) || (curToken() == CMakeLexer::TOK_STRING_LITERAL) ||
360 (curToken() == CMakeLexer::TOK_NUMBER_LITERAL))
365 if (curToken() !=
')')
367 printError(
"Missing expected ')'");
381 if (nextToken() !=
'(')
383 printError(
"Expected '(' after FUNCTION");
388 std::string funcName = _lexer.getIdentifier();
389 if (curToken() != CMakeLexer::TOK_IDENTIFIER || funcName.empty())
391 printError(
"Expected function name");
395 _os << funcName <<
'(';
396 if (nextToken() == CMakeLexer::TOK_IDENTIFIER)
398 _os << _lexer.getIdentifier();
399 while (nextToken() == CMakeLexer::TOK_IDENTIFIER)
401 _os <<
", " << _lexer.getIdentifier();
405 if (curToken() !=
')')
407 printError(
"Missing expected ')'");
427 #define STRINGIFY(a) #a
428 #define DOUBLESTRINGIFY(a) STRINGIFY(a)
430 int main(
int argc,
char **argv)
434 for (
int i = 1; i < argc; ++i)
436 std::ifstream ifs(argv[i]);
437 std::ostream &os = std::cout;
443 CMakeParser parser(ifs, os);
447 switch (parser.curToken())
449 case CMakeLexer::TOK_EOF:
451 case CMakeLexer::TOK_MACRO:
452 parser.handleMacro();
454 case CMakeLexer::TOK_FUNCTION:
455 parser.handleFunction();
457 case CMakeLexer::TOK_SET:
460 case CMakeLexer::TOK_DOXYGEN_COMMENT:
461 parser.handleDoxygenComment();
464 parser.handleTopLevelExpression();
int main(int argc, char **argv)
std::basic_string< char, ci_char_traits > ci_string
#define DOUBLESTRINGIFY(a)
bool compare(std::pair< double, int > i, std::pair< double, int > j)