28 #include <QCoreApplication>
35 #include <boost/bind.hpp>
36 #include <boost/function.hpp>
37 #include <boost/spirit/include/classic_if.hpp>
38 #include <boost/spirit/include/phoenix1_functions.hpp>
42 #define PREPROCESSLEXER_DEBUG
45 struct identity :
public std::unary_function<_Tp,_Tp> {
46 _Tp& operator()(_Tp& __x)
const {
return __x; }
47 const _Tp& operator()(
const _Tp& __x)
const {
return __x; }
51 struct tilde :
public std::unary_function<_Tp, _Tp> {
52 _Tp operator()(_Tp& __x)
const {
57 using namespace boost::spirit::classic;
61 using phoenix::construct_;
62 using phoenix::function;
65 SkipRule PreprocessLexer::m_SkipRule = nothing_p;
67 #if defined(KDEVELOP_BGPARSER)
73 static void yield() { msleep(0); }
76 inline void qthread_yield()
86 template <
typename ResultT >
87 struct result_closure : closure<result_closure<ResultT>, ResultT> {
88 typedef closure<result_closure<ResultT>, ResultT> base_t;
89 typename base_t::member1 result_;
93 struct constructQString_impl {
94 template <
typename _Arg1,
typename _Arg2>
99 template <
typename _Arg1,
typename _Arg2>
100 QString operator()(_Arg1
const& first, _Arg2
const& last) {
101 return QString(&*first, &*last - &*first);
108 grammar<identifier, result_closure<QString>::context_t> {
109 template <
typename ScannerT >
111 typedef rule<ScannerT> rule_t;
114 rule_t
const& start()
const {
118 definition(identifier
const&
self) {
120 ((alpha_p |
'_') >> *(alnum_p |
'_'))
128 grammar<operator_, result_closure<Token>::context_t> {
129 template <
typename ScannerT >
131 typedef rule<ScannerT, result_closure<int>::context_t> rule_t;
134 rule_t
const& start()
const {
138 definition(operator_
const&
self) {
142 | (str_p(
"<<=") |
">>=" |
"+=" |
"-=" |
"*=" |
"/=" |
"%=" |
"^=" |
"&=" |
"|=")[
main.result_ =
Token_assign]
155 [
self.result_ = construct_<Token>(
main.result_, arg1, arg2)];
161 grammar<charLiteral, result_closure<Token>::context_t> {
162 template <
typename ScannerT >
164 typedef rule<ScannerT, result_closure<int>::context_t> rule_t;
167 rule_t
const& start()
const {
171 definition(charLiteral
const&
self) {
173 (!ch_p(
'L') >> ch_p(
'\'')
181 struct numberLiteral :
182 grammar<numberLiteral, result_closure<Token>::context_t> {
183 template <
typename ScannerT >
185 typedef rule<ScannerT, result_closure<int>::context_t> rule_t;
188 rule_t
const& start()
const {
192 definition(numberLiteral
const&
self) {
194 (ch_p(
'0') >> ch_p(
'x') >> + xdigit_p | + digit_p)
202 struct DependencyClosure
203 : boost::spirit::classic::closure<DependencyClosure, QString, int> {
209 grammar<header, result_closure<Dependency>::context_t> {
210 template <
typename ScannerT >
212 typedef rule<ScannerT, DependencyClosure::context_t> rule_t;
215 rule_t
const& start()
const {
219 definition(header
const&
self) {
229 [
self.result_ = construct_<Dependency>(
main.m_word,
main.m_scope)]
244 return Token(type, start, end);
250 typedef QMap<QString, QString> Scope;
253 StaticChain staticChain;
257 staticChain.push_front(scope);
261 staticChain.pop_front();
264 void bind(
const QString& name,
const QString& value) {
265 Q_ASSERT(staticChain.size() > 0);
266 staticChain.front().insert(name, value);
269 bool hasBind(
const QString& name)
const {
270 StaticChain::ConstIterator it = staticChain.begin();
271 while (it != staticChain.end()) {
272 const Scope& scope = *it;
275 if (scope.contains(name))
282 QString apply(
const QString& name)
const {
283 StaticChain::ConstIterator it = staticChain.begin();
284 while (it != staticChain.end()) {
285 const Scope& scope = *it;
288 if (scope.contains(name))
289 return scope[ name ];
298 : m_data(new LexerData),
300 m_recordComments(false),
301 m_skipWordsEnabled(true),
302 m_preprocessorEnabled(true)
305 m_data->beginScope();
315 const QString& p_filename)
318 m_source.set_source(source, p_filename);
322 void PreprocessLexer::reset()
324 m_preprocessedString.clear();
326 m_preprocessor.reset();
329 void PreprocessLexer::Preprocessor::reset()
336 int PreprocessLexer::toInt(
const Token& token)
338 QString s = token.
text();
341 if (s[0] ==
'0' && (s[1] ==
'x' || s[1] ==
'X'))
342 return s.mid(2).toInt(0, 16);
345 while (i <
int(s.length()) && s[i].isDigit())
350 int i = s[0] ==
'L' ? 2 : 1;
353 int c = s[i+1].unicode();
366 return s[i].unicode();
373 int PreprocessLexer::evaluateMacro(
const QString &token)
376 uError() <<
"undefined macro" << token;
380 QString value = m.
body().trimmed();
382 lexer.setSource(value, token);
383 int result = lexer.macroExpression();
387 void PreprocessLexer::nextLine()
390 [boost::bind(&PreprocessLexer::output,
this, _1, _2)]);
391 QChar ch = m_source.currentChar();
392 if (ch.isNull() || ch.isSpace()) {
394 }
else if (m_source.parse(ch_p(
'#') >> *
gr_whiteSpace).hit) {
397 handleDirective(directive);
398 }
else if (m_preprocessor.inSkip()) {
403 while (!m_source.parse(eol_p).hit) {
406 if (tk.
type() != -1) {
407 m_preprocessedString += tk.
text();
411 m_preprocessedString += QLatin1Char(
';');
413 if (m_source.currentChar().isNull())
417 if (m_source.parse(eol_p).hit) {
418 m_preprocessedString +=
'\n';
422 void PreprocessLexer::nextToken(
Token& tk)
425 [boost::bind(&PreprocessLexer::output,
this, _1, _2)]);
426 QChar ch = m_source.currentChar();
427 if (ch.isNull() || ch.isSpace()) {
429 }
else if (m_source.parse
431 if_p(var(m_recordComments))
441 }
else if (ch.isLetter() || ch ==
'_') {
446 if (m_preprocessorEnabled && m_driver->
hasMacro(ide) &&
447 (k == -1 || !m_driver->
macro(ide).
body().isEmpty())) {
449 bool preproc = m_preprocessorEnabled;
450 m_preprocessorEnabled =
false;
452 m_data->beginScope();
462 if (m_source.parse(ch_p(
'(')).hit) {
463 Macro::ArgumentList::const_iterator l_it = m.
arguments().begin();
464 Macro::ArgumentList::const_iterator l_last = m.
arguments().end();
465 while (!m_source.currentChar().isNull() && l_it != l_last) {
468 QString argName = *l_it;
470 bool ellipsis = (argName ==
"...");
472 QString arg = readArgument();
475 m_data->bind(argName, arg);
479 if (m_source.parse(ch_p(
',')).hit) {
485 }
else if (m_source.currentChar() ==
')') {
489 if (m_source.parse(ch_p(
')')).hit) {
496 m_preprocessorEnabled = preproc;
501 Position argsEndAtPosition = currentPosition();
503 #if defined(KDEVELOP_BGPARSER)
506 m_preprocessedString += m.
body();
510 QString textToInsert;
512 while (!m_source.currentChar().isNull()
513 && m_source.currentChar() !=
'\n'
514 && m_source.currentChar() !=
'\r') {
518 bool stringify = !m_inPreproc && tok ==
'#';
520 if (stringify || merge)
524 QString tokText = tok.text();
525 QString str = (tok ==
Token_identifier && m_data->hasBind(tokText)) ? m_data->apply(tokText) : tokText;
531 textToInsert.append(QString::fromLatin1(
"\"") + str + QString::fromLatin1(
"\" "));
533 textToInsert.truncate(textToInsert.length() - 1);
534 textToInsert.append(str);
536 textToInsert.append(ellipsisArg);
538 textToInsert.append(str + QString::fromLatin1(
" "));
542 #if defined(KDEVELOP_BGPARSER)
545 m_preprocessedString += textToInsert;
548 m_preprocessorEnabled = preproc;
550 m_source.set_currentPosition(argsEndAtPosition);
551 }
else if (k != -1) {
552 tk = m_source.createToken(k, start);
553 }
else if (m_skipWordsEnabled) {
554 QMap< QString, QPair<SkipType, QString> >::Iterator pos = m_words.find(ide);
555 if (pos != m_words.end()) {
558 if (m_source.currentChar() ==
'(')
561 if (!(*pos).second.isEmpty()) {
562 #if defined(KDEVELOP_BGPARSER)
565 m_preprocessedString += QString(
" ") + (*pos).second + QString(
" ");
568 ide.endsWith(QLatin1String(
"EXPORT")) ||
569 (ide.startsWith(QLatin1String(
"Q_EXPORT")) && ide !=
"Q_EXPORT_INTERFACE") ||
570 ide.startsWith(QLatin1String(
"QM_EXPORT")) ||
571 ide.startsWith(QLatin1String(
"QM_TEMPLATE"))) {
574 if (m_source.currentChar() ==
'(')
576 }
else if (ide.startsWith(QLatin1String(
"K_TYPELIST_")) || ide.startsWith(QLatin1String(
"TYPELIST_"))) {
579 if (m_source.currentChar() ==
'(')
593 tk = m_source.createToken(ch.unicode(), l_ptr);
599 for (; p_first != p_last; ++p_first)
600 m_preprocessedString += *p_first;
606 void PreprocessLexer::dumpToFile()
608 QString tempPath = QDir::tempPath() + QString(
"/umbrello-%1").arg(QCoreApplication::applicationPid());
613 QString fileName = tempPath +
'/' + currentPosition().file.replace(QRegExp(
"[/:mn]"),
"-");
615 if (f.open(QIODevice::WriteOnly | QIODevice::Text)) {
617 out << m_preprocessedString;
626 if (currentPosition() == start) {
627 #ifdef PREPROCESSLEXER_DEBUG
630 uError() <<
"preprocess failed" << start;
634 if (m_source.currentChar().isNull())
639 m_preprocessedString += tk.
text();
645 m_words[ word ] = qMakePair(skipType, str);
648 void PreprocessLexer::skip(
int l,
int r)
650 Position svCurrentPosition = currentPosition();
654 while (!m_source.eof()) {
660 else if ((
int)tk == r)
667 m_source.set_currentPosition(svCurrentPosition);
670 QString PreprocessLexer::readArgument()
677 while (!m_source.currentChar().isNull()) {
680 QChar ch = m_source.currentChar();
682 if (ch.isNull() || (!count && (ch ==
',' || ch ==
')')))
689 }
else if (tk ==
')') {
694 arg += tk.
text() +
' ';
697 return arg.trimmed();
700 void PreprocessLexer::handleDirective(
const QString& directive)
704 bool skip = m_skipWordsEnabled;
705 bool preproc = m_preprocessorEnabled;
707 m_skipWordsEnabled =
false;
708 m_preprocessorEnabled =
false;
710 if (directive ==
"define") {
711 if (!m_preprocessor.inSkip())
713 }
else if (directive ==
"else") {
714 if (!m_preprocessor.empty())
715 m_preprocessor.processElse();
716 }
else if (directive ==
"elif") {
717 if (!m_preprocessor.empty())
718 m_preprocessor.processElif(macroExpression());
719 }
else if (directive ==
"endif") {
720 if (!m_preprocessor.empty())
721 m_preprocessor.decrement();
722 }
else if (directive ==
"if") {
723 m_preprocessor.processIf(macroExpression());
724 }
else if (directive ==
"ifdef") {
725 m_preprocessor.processIf(macroDefined());
726 }
else if (directive ==
"ifndef") {
727 m_preprocessor.processIf(!macroDefined());
728 }
else if (directive ==
"include") {
729 if (!m_preprocessor.inSkip())
732 [boost::bind(&PreprocessLexer::addDependence,
this, _1)]
734 }
else if (directive ==
"undef") {
735 if (!m_preprocessor.inSkip())
742 m_skipWordsEnabled = skip;
743 m_preprocessorEnabled = preproc;
748 bool PreprocessLexer::macroDefined()
755 struct push_back_c_impl {
756 template <
typename Container,
typename Item>
760 template <
typename Container,
typename Item>
761 void operator()(Container& c, Item
const& item)
const {
766 phoenix::function<push_back_c_impl>
const push_back_c = push_back_c_impl();
768 struct macroDefinition :
769 grammar<macroDefinition, result_closure<Macro>::context_t> {
770 template <
typename ScannerT >
772 typedef rule<ScannerT> rule_t;
775 rule<ScannerT, result_closure<QString>::context_t> ellipsis, argument;
777 rule_t
const& start()
const {
781 definition(macroDefinition
const&
self) {
793 macroName =
identifier_pg[
self.result_ = construct_<Macro>(arg1)];
795 ellipsis [assign_a(argument.result_)]
803 void PreprocessLexer::processDefine()
809 m_preprocessorEnabled =
true;
812 while (!m_source.currentChar().isNull()
813 && m_source.currentChar() !=
'\n'
814 && m_source.currentChar() !=
'\r') {
824 if (tk.
type() != -1) {
825 body +=
'"' + tk.
text() +
'"';
828 else if (tk.
type() != -1) {
829 QString s = tk.
text();
840 void PreprocessLexer::processUndef()
848 int PreprocessLexer::macroPrimary()
852 if (m_source.parse(ch_p(
'(')).hit) {
853 result = macroExpression();
854 bool l_hit = m_source.parse(ch_p(
')')).hit;
859 boost::function < int (int) > l_op = identity<int>();
860 if (m_source.parse(ch_p(
'+')
861 | ch_p(
'-')[var(l_op) = std::negate<int>()]
862 | ch_p(
'!')[var(l_op) = std::logical_not<int>()]
863 | ch_p(
'~')[var(l_op) = tilde<int>()]
865 result = l_op(macroPrimary());
866 }
else if (m_source.parse(str_p(
"defined")).hit) {
869 result = macroPrimary();
874 boost::bind(&PreprocessLexer::evaluateMacro, boost::ref(*
this), _1))]
877 boost::bind(&PreprocessLexer::toInt, _1))]
880 boost::bind(&PreprocessLexer::toInt, _1))]
887 int PreprocessLexer::macroMultiplyDivide()
889 int result = macroPrimary();
895 ch_p(
'*')[var(op) = 0]
897 (ch_p(
'/') >> eps_p(anychar_p -
'*' -
'/'))
899 | ch_p(
'%')[var(op) = 2]
901 iresult = macroPrimary();
904 result = (result * iresult);
907 result = (iresult == 0 ? 0 : (result / iresult));
910 result = (iresult == 0) ? 0 : (result % iresult);
918 int PreprocessLexer::macroAddSubtract()
920 int result = macroMultiplyDivide();
924 while (m_source.parse(
925 ch_p(
'+')[var(ad) =
true] | ch_p(
'-')[var(ad) =
false]
928 iresult = macroMultiplyDivide();
929 result = ad ? (result + iresult) : (result - iresult);
934 int PreprocessLexer::macroRelational()
936 int result = macroAddSubtract();
938 boost::function < bool (int, int) > l_op;
939 while (m_source.parse(
940 str_p(
"<=")[var(l_op) = less_equal<int>()]
941 | ch_p(
'<')[var(l_op) = less<int>()]
942 | str_p(
">=")[var(l_op) = greater_equal<int>()]
943 | ch_p(
'>')[var(l_op) = greater<int>()]
946 int iresult = macroAddSubtract();
947 result = l_op(result, iresult);
952 int PreprocessLexer::macroEquality()
954 int result = macroRelational();
956 boost::function < bool(int, int) > l_op;
957 while (m_source.parse(str_p(
"==")[var(l_op) = equal_to<int>()]
958 | str_p(
"!=")[var(l_op) = not_equal_to<int>()]
960 result = l_op(result, macroRelational());
965 int PreprocessLexer::macroBoolAnd()
967 int result = macroEquality();
969 while (m_source.parse(ch_p(
'&') >> eps_p(anychar_p -
'&')).hit)
970 result &= macroEquality();
974 int PreprocessLexer::macroBoolXor()
976 int result = macroBoolAnd();
978 while (m_source.parse(ch_p(
'^')).hit)
979 result ^= macroBoolAnd();
983 int PreprocessLexer::macroBoolOr()
985 int result = macroBoolXor();
987 while (m_source.parse(ch_p(
'|') >> eps_p(anychar_p -
'|')).hit)
988 result |= macroBoolXor();
992 int PreprocessLexer::macroLogicalAnd()
994 int result = macroBoolOr();
996 while (m_source.parse(str_p(
"&&")).hit)
997 result = macroBoolOr() && result;
1001 int PreprocessLexer::macroLogicalOr()
1003 int result = macroLogicalAnd();
1005 while (m_source.parse(str_p(
"||")).hit)
1006 result = macroLogicalAnd() || result;
1010 int PreprocessLexer::macroExpression()
1013 return macroLogicalOr();
PreprocessLexer(Driver *driver)
PreprocessLexer::CharRule gr_skipTillEol
virtual void removeMacro(const QString ¯oName)
int main(int argc, char *argv[])
PreprocessLexer::CharRule gr_escapeSequence
void setSource(const QString &source, const QString &p_filename)
std::pair< QString, int > Dependency
PreprocessLexer::CharRule gr_lineComment
charLiteral charLiteral_pg
PreprocessLexer::CharRule gr_octalDigit
PreprocessLexer::CharRule gr_digit
ArgumentList const & arguments() const
PreprocessLexer::CharRule gr_octalEscapeSequence
QString currentFileName() const
phoenix::function< push_back_c_impl > const push_back_c
static int find(const struct HashTable *table, const QString &s)
Find an entry in the table, and return its value (i.e.
Macro & macro(const QString &name)
PreprocessLexer::CharRule gr_whiteSpace
QString const & name() const
void setBody(const QString &body)
macroDefinition macroDefinition_pg
PreprocessLexer::CharRule gr_hexDigit
numberLiteral numberLiteral_pg
void addSkipWord(const QString &word, SkipType skipType=SkipWord, const QString &str=QString())
bool hasArguments() const
PreprocessLexer::CharRule gr_hexEscapeSequence
bool hasMacro(const QString &name) const
const function< constructQString_impl > constructQString
void setFileName(const QString &fileName)
PreprocessLexer::CharRule gr_stringLiteral
rule< scanner< CharIterator > > SkipRule
QString const & text() const
rule< scanner< CharIterator, CharPolicies > > CharRule
virtual void addMacro(const Macro ¯o)
PreprocessLexer::CharRule gr_multiLineComment
PreprocessLexer::CharRule gr_simpleEscapeSequence
static const struct HashTable keyword