Commit ebe17889 authored by Roberto Raggi's avatar Roberto Raggi
Browse files

Some refactoring of the preprocessor, it'll simplify my next commits.

parent f96d8ff9
......@@ -50,6 +50,8 @@
#include <Lexer.h>
#include <Token.h>
#include <Literals.h>
#include <QtDebug>
#include <algorithm>
......@@ -450,7 +452,8 @@ private:
Preprocessor::Preprocessor(Client *client, Environment &env)
: client(client),
env(env),
expand(env)
_expand(env),
_result(0)
{
resetIfLevel ();
}
......@@ -501,13 +504,23 @@ void Preprocessor::preprocess(const QByteArray &filename,
QByteArray *result)
{
const QByteArray previousFile = env.currentFile;
env.currentFile = filename;
env.currentFile = filename;
preprocess(source, result);
env.currentFile = previousFile;
}
void Preprocessor::expand(const QByteArray &source, QByteArray *result)
{
_expand(source, result);
}
void Preprocessor::expand(const char *first, const char *last, QByteArray *result)
{
const QByteArray source = QByteArray::fromRawData(first, last - first);
return expand(source, result);
}
Preprocessor::State Preprocessor::createStateFromSource(const QByteArray &source) const
{
State state;
......@@ -525,6 +538,9 @@ Preprocessor::State Preprocessor::createStateFromSource(const QByteArray &source
void Preprocessor::preprocess(const QByteArray &source, QByteArray *result)
{
QByteArray *previousResult = _result;
_result = result;
pushState(createStateFromSource(source));
const unsigned previousCurrentLine = env.currentLine;
......@@ -533,16 +549,16 @@ void Preprocessor::preprocess(const QByteArray &source, QByteArray *result)
while (true) {
if (env.currentLine != _dot->lineno) {
if (env.currentLine > _dot->lineno) {
result->append("\n# ");
result->append(QByteArray::number(_dot->lineno));
result->append(' ');
result->append('"');
result->append(env.currentFile);
result->append('"');
result->append('\n');
_result->append("\n# ");
_result->append(QByteArray::number(_dot->lineno));
_result->append(' ');
_result->append('"');
_result->append(env.currentFile);
_result->append('"');
_result->append('\n');
} else {
for (unsigned i = env.currentLine; i < _dot->lineno; ++i)
result->append('\n');
_result->append('\n');
}
env.currentLine = _dot->lineno;
}
......@@ -580,12 +596,12 @@ void Preprocessor::preprocess(const QByteArray &source, QByteArray *result)
} while (_dot->isNot(T_EOF_SYMBOL) && (_dot->joined || ! _dot->newline));
} else {
if (_dot->joined)
result->append("\\\n");
_result->append("\\\n");
else if (_dot->whitespace)
result->append(' ');
_result->append(' ');
if (_dot->isNot(T_IDENTIFIER)) {
result->append(tokenSpell(*_dot));
_result->append(tokenSpell(*_dot));
++_dot;
} else {
const TokenIterator identifierToken = _dot;
......@@ -599,7 +615,7 @@ void Preprocessor::preprocess(const QByteArray &source, QByteArray *result)
client->startExpandingMacro(identifierToken->offset,
trivial, spell);
expand(spell.constBegin(), spell.constEnd(), result);
expand(spell, _result);
if (client)
client->stopExpandingMacro(_dot->offset, trivial);
......@@ -609,7 +625,7 @@ void Preprocessor::preprocess(const QByteArray &source, QByteArray *result)
Macro *m = env.resolve(spell);
if (! m) {
result->append(spell);
_result->append(spell);
} else {
if (! m->isFunctionLike()) {
if (_dot->isNot(T_LPAREN)) {
......@@ -618,7 +634,7 @@ void Preprocessor::preprocess(const QByteArray &source, QByteArray *result)
*m, spell);
m->setHidden(true);
expand(m->definition(), result);
expand(m->definition(), _result);
m->setHidden(false);
if (client)
......@@ -650,7 +666,7 @@ void Preprocessor::preprocess(const QByteArray &source, QByteArray *result)
popState();
if (! m) {
result->append(tmp);
_result->append(tmp);
continue;
}
}
......@@ -659,7 +675,7 @@ void Preprocessor::preprocess(const QByteArray &source, QByteArray *result)
// collect the actual arguments
if (_dot->isNot(T_LPAREN)) {
// ### warnng expected T_LPAREN
result->append(m->name());
_result->append(m->name());
continue;
}
......@@ -689,7 +705,7 @@ void Preprocessor::preprocess(const QByteArray &source, QByteArray *result)
*m, text);
}
expand(beginOfText, endOfText, result);
expand(beginOfText, endOfText, _result);
if (client)
client->stopExpandingMacro(_dot->offset, *m);
......@@ -701,6 +717,7 @@ void Preprocessor::preprocess(const QByteArray &source, QByteArray *result)
popState();
env.currentLine = previousCurrentLine;
_result = previousResult;
}
const char *Preprocessor::startOfToken(const Token &token) const
......@@ -788,9 +805,8 @@ QVector<Token> Preprocessor::tokenize(const QByteArray &text) const
return tokens;
}
void Preprocessor::processInclude(bool,
TokenIterator firstToken, TokenIterator lastToken,
bool acceptMacros)
void Preprocessor::processInclude(bool, TokenIterator firstToken,
TokenIterator lastToken, bool acceptMacros)
{
RangeLexer tk(firstToken, lastToken);
++tk; // skip T_POUND
......@@ -1011,7 +1027,8 @@ void Preprocessor::processEndif(TokenIterator, TokenIterator)
}
void Preprocessor::processIfdef(bool checkUndefined,
TokenIterator firstToken, TokenIterator lastToken)
TokenIterator firstToken,
TokenIterator lastToken)
{
RangeLexer tk(firstToken, lastToken);
......@@ -1054,47 +1071,47 @@ void Preprocessor::resetIfLevel ()
_true_test[iflevel] = false;
}
Preprocessor::PP_DIRECTIVE_TYPE Preprocessor::classifyDirective (const QByteArray &__directive) const
Preprocessor::PP_DIRECTIVE_TYPE Preprocessor::classifyDirective(const QByteArray &directive) const
{
switch (__directive.size())
switch (directive.size())
{
case 2:
if (__directive[0] == 'i' && __directive[1] == 'f')
if (directive[0] == 'i' && directive[1] == 'f')
return PP_IF;
break;
case 4:
if (__directive[0] == 'e' && __directive == "elif")
if (directive[0] == 'e' && directive == "elif")
return PP_ELIF;
else if (__directive[0] == 'e' && __directive == "else")
else if (directive[0] == 'e' && directive == "else")
return PP_ELSE;
break;
case 5:
if (__directive[0] == 'i' && __directive == "ifdef")
if (directive[0] == 'i' && directive == "ifdef")
return PP_IFDEF;
else if (__directive[0] == 'u' && __directive == "undef")
else if (directive[0] == 'u' && directive == "undef")
return PP_UNDEF;
else if (__directive[0] == 'e' && __directive == "endif")
else if (directive[0] == 'e' && directive == "endif")
return PP_ENDIF;
break;
case 6:
if (__directive[0] == 'i' && __directive == "ifndef")
if (directive[0] == 'i' && directive == "ifndef")
return PP_IFNDEF;
else if (__directive[0] == 'i' && __directive == "import")
else if (directive[0] == 'i' && directive == "import")
return PP_IMPORT;
else if (__directive[0] == 'd' && __directive == "define")
else if (directive[0] == 'd' && directive == "define")
return PP_DEFINE;
break;
case 7:
if (__directive[0] == 'i' && __directive == "include")
if (directive[0] == 'i' && directive == "include")
return PP_INCLUDE;
break;
case 12:
if (__directive[0] == 'i' && __directive == "include_next")
if (directive[0] == 'i' && directive == "include_next")
return PP_INCLUDE_NEXT;
break;
......@@ -1117,7 +1134,7 @@ int Preprocessor::skipping() const
{ return _skipping[iflevel]; }
Value Preprocessor::evalExpression(TokenIterator firstToken, TokenIterator lastToken,
const QByteArray &source) const
const QByteArray &source) const
{
ExpressionEvaluator eval(&env);
const Value result = eval(firstToken, lastToken, source);
......
......@@ -60,174 +60,180 @@ namespace CPlusPlus {
namespace CPlusPlus {
struct Value
{
enum Kind {
Kind_Long,
Kind_ULong,
};
struct Value
{
enum Kind {
Kind_Long,
Kind_ULong,
};
Kind kind;
Kind kind;
union {
long l;
unsigned long ul;
};
union {
long l;
unsigned long ul;
};
Value()
: kind(Kind_Long), l(0)
{ }
Value()
: kind(Kind_Long), l(0)
{ }
inline bool is_ulong () const
{ return kind == Kind_ULong; }
inline bool is_ulong () const
{ return kind == Kind_ULong; }
inline void set_ulong (unsigned long v)
{
ul = v;
kind = Kind_ULong;
}
inline void set_ulong (unsigned long v)
{
ul = v;
kind = Kind_ULong;
}
inline void set_long (long v)
{
l = v;
kind = Kind_Long;
}
inline void set_long (long v)
{
l = v;
kind = Kind_Long;
}
inline bool is_zero () const
{ return l == 0; }
inline bool is_zero () const
{ return l == 0; }
#define PP_DEFINE_BIN_OP(name, op) \
inline Value operator op(const Value &other) const \
{ \
Value v = *this; \
if (v.is_ulong () || other.is_ulong ()) \
v.set_ulong (v.ul op other.ul); \
else \
v.set_long (v.l op other.l); \
return v; \
}
PP_DEFINE_BIN_OP(op_add, +)
PP_DEFINE_BIN_OP(op_sub, -)
PP_DEFINE_BIN_OP(op_mult, *)
PP_DEFINE_BIN_OP(op_div, /)
PP_DEFINE_BIN_OP(op_mod, %)
PP_DEFINE_BIN_OP(op_lhs, <<)
PP_DEFINE_BIN_OP(op_rhs, >>)
PP_DEFINE_BIN_OP(op_lt, <)
PP_DEFINE_BIN_OP(op_gt, >)
PP_DEFINE_BIN_OP(op_le, <=)
PP_DEFINE_BIN_OP(op_ge, >=)
PP_DEFINE_BIN_OP(op_eq, ==)
PP_DEFINE_BIN_OP(op_ne, !=)
PP_DEFINE_BIN_OP(op_bit_and, &)
PP_DEFINE_BIN_OP(op_bit_or, |)
PP_DEFINE_BIN_OP(op_bit_xor, ^)
PP_DEFINE_BIN_OP(op_and, &&)
PP_DEFINE_BIN_OP(op_or, ||)
inline Value operator op(const Value &other) const \
{ \
Value v = *this; \
if (v.is_ulong () || other.is_ulong ()) \
v.set_ulong (v.ul op other.ul); \
else \
v.set_long (v.l op other.l); \
return v; \
}
PP_DEFINE_BIN_OP(op_add, +)
PP_DEFINE_BIN_OP(op_sub, -)
PP_DEFINE_BIN_OP(op_mult, *)
PP_DEFINE_BIN_OP(op_div, /)
PP_DEFINE_BIN_OP(op_mod, %)
PP_DEFINE_BIN_OP(op_lhs, <<)
PP_DEFINE_BIN_OP(op_rhs, >>)
PP_DEFINE_BIN_OP(op_lt, <)
PP_DEFINE_BIN_OP(op_gt, >)
PP_DEFINE_BIN_OP(op_le, <=)
PP_DEFINE_BIN_OP(op_ge, >=)
PP_DEFINE_BIN_OP(op_eq, ==)
PP_DEFINE_BIN_OP(op_ne, !=)
PP_DEFINE_BIN_OP(op_bit_and, &)
PP_DEFINE_BIN_OP(op_bit_or, |)
PP_DEFINE_BIN_OP(op_bit_xor, ^)
PP_DEFINE_BIN_OP(op_and, &&)
PP_DEFINE_BIN_OP(op_or, ||)
#undef PP_DEFINE_BIN_OP
};
};
class CPLUSPLUS_EXPORT Preprocessor
{
public:
Preprocessor(Client *client, Environment &env);
QByteArray operator()(const QByteArray &filename,
const QByteArray &source);
class CPLUSPLUS_EXPORT Preprocessor
QByteArray operator()(const QByteArray &source);
private:
enum { MAX_LEVEL = 512 };
enum PP_DIRECTIVE_TYPE
{
Client *client;
Environment &env;
MacroExpander expand;
enum { MAX_LEVEL = 512 };
bool _skipping[MAX_LEVEL]; // ### move in state
bool _true_test[MAX_LEVEL]; // ### move in state
int iflevel; // ### move in state
enum PP_DIRECTIVE_TYPE
{
PP_UNKNOWN_DIRECTIVE,
PP_DEFINE,
PP_IMPORT,
PP_INCLUDE,
PP_INCLUDE_NEXT,
PP_ELIF,
PP_ELSE,
PP_ENDIF,
PP_IF,
PP_IFDEF,
PP_IFNDEF,
PP_UNDEF
};
typedef const CPlusPlus::Token *TokenIterator;
struct State {
QByteArray source;
QVector<CPlusPlus::Token> tokens;
TokenIterator dot;
};
QList<State> _savedStates;
State state() const;
void pushState(const State &state);
void popState();
QByteArray _source;
QVector<CPlusPlus::Token> _tokens;
TokenIterator _dot;
State createStateFromSource(const QByteArray &source) const;
public:
Preprocessor(Client *client, Environment &env);
QByteArray operator()(const QByteArray &filename,
const QByteArray &source);
QByteArray operator()(const QByteArray &source);
private:
void preprocess(const QByteArray &filename,
const QByteArray &source,
QByteArray *result);
void preprocess(const QByteArray &source,
QByteArray *result);
void resetIfLevel();
bool testIfLevel();
int skipping() const;
PP_DIRECTIVE_TYPE classifyDirective(const QByteArray &directive) const;
Value evalExpression(TokenIterator firstToken,
TokenIterator lastToken,
const QByteArray &source) const;
QVector<CPlusPlus::Token> tokenize(const QByteArray &text) const;
const char *startOfToken(const CPlusPlus::Token &token) const;
const char *endOfToken(const CPlusPlus::Token &token) const;
QByteArray tokenSpell(const CPlusPlus::Token &token) const;
QByteArray tokenText(const CPlusPlus::Token &token) const; // does a deep copy
void processDirective(TokenIterator dot, TokenIterator lastToken);
void processInclude(bool skipCurrentPath,
TokenIterator dot, TokenIterator lastToken,
bool acceptMacros = true);
void processDefine(TokenIterator dot, TokenIterator lastToken);
void processIf(TokenIterator dot, TokenIterator lastToken);
void processElse(TokenIterator dot, TokenIterator lastToken);
void processElif(TokenIterator dot, TokenIterator lastToken);
void processEndif(TokenIterator dot, TokenIterator lastToken);
void processIfdef(bool checkUndefined,
TokenIterator dot, TokenIterator lastToken);
void processUndef(TokenIterator dot, TokenIterator lastToken);
bool isQtReservedWord(const QByteArray &name) const;
PP_UNKNOWN_DIRECTIVE,
PP_DEFINE,
PP_IMPORT,
PP_INCLUDE,
PP_INCLUDE_NEXT,
PP_ELIF,
PP_ELSE,
PP_ENDIF,
PP_IF,
PP_IFDEF,
PP_IFNDEF,
PP_UNDEF
};
typedef const CPlusPlus::Token *TokenIterator;
struct State {
QByteArray source;
QVector<CPlusPlus::Token> tokens;
TokenIterator dot;
};
void preprocess(const QByteArray &filename,
const QByteArray &source,
QByteArray *result);
void preprocess(const QByteArray &source,
QByteArray *result);
void expand(const QByteArray &source, QByteArray *result);
void expand(const char *first, const char *last, QByteArray *result);
void resetIfLevel();
bool testIfLevel();
int skipping() const;
PP_DIRECTIVE_TYPE classifyDirective(const QByteArray &directive) const;
Value evalExpression(TokenIterator firstToken,
TokenIterator lastToken,
const QByteArray &source) const;
QVector<CPlusPlus::Token> tokenize(const QByteArray &text) const;
const char *startOfToken(const CPlusPlus::Token &token) const;
const char *endOfToken(const CPlusPlus::Token &token) const;
QByteArray tokenSpell(const CPlusPlus::Token &token) const;
QByteArray tokenText(const CPlusPlus::Token &token) const; // does a deep copy
void processDirective(TokenIterator dot, TokenIterator lastToken);
void processInclude(bool skipCurrentPath,
TokenIterator dot, TokenIterator lastToken,
bool acceptMacros = true);
void processDefine(TokenIterator dot, TokenIterator lastToken);
void processIf(TokenIterator dot, TokenIterator lastToken);
void processElse(TokenIterator dot, TokenIterator lastToken);
void processElif(TokenIterator dot, TokenIterator lastToken);
void processEndif(TokenIterator dot, TokenIterator lastToken);
void processIfdef(bool checkUndefined,
TokenIterator dot, TokenIterator lastToken);
void processUndef(TokenIterator dot, TokenIterator lastToken);
bool isQtReservedWord(const QByteArray &name) const;
State state() const;
void pushState(const State &state);
void popState();
State createStateFromSource(const QByteArray &source) const;
private:
Client *client;
Environment &env;
MacroExpander _expand;
bool _skipping[MAX_LEVEL]; // ### move in state
bool _true_test[MAX_LEVEL]; // ### move in state
int iflevel; // ### move in state
QList<State> _savedStates;
QByteArray _source;
QVector<CPlusPlus::Token> _tokens;
TokenIterator _dot;
QByteArray *_result;
};
} // namespace CPlusPlus
#endif // CPLUSPLUS_PP_ENGINE_H
......@@ -69,8 +69,14 @@ const QByteArray *MacroExpander::resolve_formal(const QByteArray &__name)
return 0;
}
const char *MacroExpander::operator () (const char *__first, const char *__last,
QByteArray *__result)
const char *MacroExpander::operator()(const char *first, const char *last,
QByteArray *result)
{
return expand(first, last, result);
}
const char *MacroExpander::expand(const char *__first, const char *__last,
QByteArray *__result)
{
generated_lines = 0;
__first = skip_blanks (__first, __last);
......
......@@ -88,6 +88,9 @@ namespace CPlusPlus {
QByteArray *result)
{ return operator()(source.constBegin(), source.constEnd(), result); }
const char *expand(const char *first, const char *last,
QByteArray *result);
const char *skip_argument_variadics (const QVector<QByteArray> &actuals,
Macro *macro,
const char *first, const char *last);
......
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment