Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
12 changes: 10 additions & 2 deletions src/compiler/lex/char_class.h
Original file line number Diff line number Diff line change
Expand Up @@ -4,10 +4,18 @@
#include "core.h"

namespace rat::cc {
inline B32 isIdentStart(C8 c) {
constexpr B32 isIdentStart(C8 c) {
return c == '_' || (c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z');
}
inline B32 isIdentCont(C8 c) { return isIdentStart(c) || (c >= '0' && c <= '9'); }
struct IdentContTable {
U8 v[256] = {};
constexpr IdentContTable() {
for(U32 c = 0; c < 256; ++c)
v[c] = isIdentStart((C8)c) || (c >= '0' && c <= '9');
}
};
inline constexpr IdentContTable kIdentCont;
inline B32 isIdentCont(C8 c) { return kIdentCont.v[(U8)c]; }
inline B32 isDigit(C8 c) { return c >= '0' && c <= '9'; }
inline B32 isOctalDigit(C8 c) { return c >= '0' && c <= '7'; }
inline B32 isHexDigit(C8 c) {
Expand Down
36 changes: 21 additions & 15 deletions src/compiler/lex/preprocess.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -113,7 +113,7 @@ namespace rat::cc {
String found;
String content;
for(const String& p : tries) {
if(readFile(p, content)) {
if(fileToks.count(p) || readFile(p, content)) {
found = p;
break;
}
Expand All @@ -128,8 +128,11 @@ namespace rat::cc {
fail("#include nesting too deep");
return;
}
auto it = fileToks.find(found);
if(it == fileToks.end())
it = fileToks.emplace(found, lexFragment(content, intern(found))).first;
++includeDepth;
runFile(found, content);
runTokens(found, it->second);
--includeDepth;
}

Expand Down Expand Up @@ -229,15 +232,15 @@ namespace rat::cc {
List<PpToken> Preprocessor::applyPragmaOperators(List<PpToken>& toks, const String& path) {
B32 any = false;
for(const PpToken& t : toks)
if(t.kind == Pk::Id && *t.text == "_Pragma") {
if(t.kind == Pk::Id && t.text == idPragma) {
any = true;
break;
}
if(!any)
return std::move(toks);
List<PpToken> out;
for(U64 i = 0; i < toks.size();) {
if(toks[i].kind == Pk::Id && *toks[i].text == "_Pragma" && i + 3 < toks.size() &&
if(toks[i].kind == Pk::Id && toks[i].text == idPragma && i + 3 < toks.size() &&
isPunct(toks[i + 1], "(") && toks[i + 2].kind == Pk::Str && isPunct(toks[i + 3], ")")) {
List<PpToken> body = lexFragment(destringize(*toks[i + 2].text), intern(path));
doPragma(PpSpan(body), path);
Expand All @@ -250,18 +253,17 @@ namespace rat::cc {
return out;
}

void Preprocessor::flush(List<PpToken>& textBuf) {
if(textBuf.empty())
void Preprocessor::flush(PpSpan text) {
if(text.empty())
return;
List<PpToken> e = expand(PpSpan(textBuf));
List<PpToken> e = expand(text);
e = applyPragmaOperators(e, fileName);
for(PpToken& t : e) {
// report lines through any #line adjustment
I64 adj = (I64)t.line + lineDelta;
t.line = adj >= 1 ? (U32)adj : 1;
out.push_back(std::move(t));
}
textBuf.clear();
}

B32 Preprocessor::condActive(const List<Cond>& stack) {
Expand Down Expand Up @@ -354,6 +356,10 @@ namespace rat::cc {
return;

List<PpToken> toks = lexFragment(source, intern(path));
runTokens(path, toks);
}

void Preprocessor::runTokens(const String& path, const List<PpToken>& toks) {
if(!ok)
return;

Expand All @@ -363,7 +369,7 @@ namespace rat::cc {
fileName = path;

List<Cond> stack;
List<PpToken> textBuf;
U64 textStart = 0;

U64 i = 0, n = toks.size();
while(i < n && ok) {
Expand All @@ -374,13 +380,12 @@ namespace rat::cc {
i = j;

const PpToken& first = toks[start];
if(!isPunct(first, "#") || !first.bol) {
if(condActive(stack))
textBuf.insert(textBuf.end(), toks.begin() + start, toks.begin() + j);
if(!isPunct(first, "#") || !first.bol)
continue;
}

flush(textBuf);
if(condActive(stack))
flush(PpSpan(toks.data() + textStart, toks.data() + start));
textStart = j;
if(start + 1 == j) // null directive
continue;
U32 phys = j < n ? toks[j].line : toks[start + 1].line + 1;
Expand All @@ -390,7 +395,8 @@ namespace rat::cc {
if(ok && !stack.empty())
fail(path + ": unterminated #if");

flush(textBuf);
if(condActive(stack))
flush(PpSpan(toks.data() + textStart, toks.data() + n));

lineDelta = savedDelta;
fileName = savedFile;
Expand Down
39 changes: 22 additions & 17 deletions src/compiler/lex/preprocess_detail.h
Original file line number Diff line number Diff line change
Expand Up @@ -20,32 +20,30 @@ namespace rat::cc {

// string pool: equal spellings share one const String*, compare by pointer
struct Interner {
struct Slot {
U64 hash = 0;
const String* str = nullptr;
};
std::deque<String> store;
Map<std::string_view, const String*> pool;

const String* intern(std::string_view s) {
auto it = pool.find(s);
if(it != pool.end())
return it->second;
store.emplace_back(s);
const String* p = &store.back();
pool.emplace(std::string_view(*p), p);
return p;
}
List<Slot> slots = List<Slot>(4096);
U64 count = 0;

const String* intern(std::string_view s);
void grow();
};

struct HideSet {
List<const String*> names;
};

struct PpToken {
Pk kind = Pk::Eof;
const String* text = nullptr; // interned spelling
B32 spaceBefore = false; // had white space before it
B32 bol = false; // first token on its logical line
U32 line = 0;
const String* text = nullptr; // interned spelling
const String* file = nullptr; // interned file name
const HideSet* hide = nullptr; // interned hide set
U32 line = 0;
Pk kind = Pk::Eof;
U8 spaceBefore = false; // had white space before it
U8 bol = false; // first token on its logical line
};

constexpr U32 kMaxIncludeDepth = 200;
Expand Down Expand Up @@ -75,6 +73,10 @@ namespace rat::cc {
U64 decodeTrigraph(const String& src, U64 p, C8& c);
U64 newlineLen(const String& s, U64 i);

// 0x80 in each byte of w equal to b, 0 elsewhere
constexpr U64 kBytes1 = 0x0101010101010101ull;
U64 bytesEq(U64 w, C8 b);

// trigraph + splice + newline norm in one copy; sparse LineMarks
void splice(const String& src, String& out, List<LineMark>& marks);

Expand Down Expand Up @@ -183,6 +185,7 @@ namespace rat::cc {
Map<const String*, Macro> macros;
List<PpToken> out;
Set<String> pragmaOnce;
Map<String, List<PpToken>> fileToks;
struct SavedMacro {
B32 defined;
Macro macro;
Expand All @@ -209,6 +212,7 @@ namespace rat::cc {
const String* idAlias = interner.intern("alias");
const String* idAlias2 = interner.intern("__alias__");
const String* idAliasMark = interner.intern("__rat_alias__");
const String* idPragma = interner.intern("_Pragma");
String err;
B32 ok = true;
I64 lineDelta = 0;
Expand Down Expand Up @@ -278,7 +282,7 @@ namespace rat::cc {
void doPragma(PpSpan rest, const String& path);
String destringize(const String& lit);
List<PpToken> applyPragmaOperators(List<PpToken>& toks, const String& path);
void flush(List<PpToken>& textBuf);
void flush(PpSpan text);
static B32 condActive(const List<Cond>& stack);
void pushCond(const String& name, PpSpan rest, List<Cond>& stack);
B32 handleConditional(const String& name, PpSpan rest, List<Cond>& stack);
Expand All @@ -287,6 +291,7 @@ namespace rat::cc {
// driver
B32 run(const String& path, const String& source, String& errOut);
void runFile(const String& path, const String& source);
void runTokens(const String& path, const List<PpToken>& toks);
void installBuiltins();
void applyCommandLine();
String serialize();
Expand Down
57 changes: 54 additions & 3 deletions src/compiler/lex/preprocess_lex.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -4,8 +4,45 @@

#include <cstring>

#include "hash.h"

namespace rat::cc {
namespace detail {
const String* Interner::intern(std::string_view s) {
U64 h = kFnvBasis;
for(C8 c : s)
hashMix(h, (U8)c);
U64 mask = slots.size() - 1;
for(U64 i = h & mask;; i = (i + 1) & mask) {
Slot& sl = slots[i];
if(!sl.str) {
store.emplace_back(s);
sl.hash = h;
sl.str = &store.back();
const String* p = sl.str;
if(++count * 2 > slots.size())
grow();
return p;
}
if(sl.hash == h && std::string_view(*sl.str) == s)
return sl.str;
}
}

void Interner::grow() {
List<Slot> old = std::move(slots);
slots = List<Slot>(old.size() * 2);
U64 mask = slots.size() - 1;
for(const Slot& sl : old) {
if(!sl.str)
continue;
U64 i = sl.hash & mask;
while(slots[i].str)
i = (i + 1) & mask;
slots[i] = sl;
}
}

String unquote(const String& s) { return s.size() >= 2 ? s.substr(1, s.size() - 2) : s; }

B32 isAbsPath(const String& s) {
Expand Down Expand Up @@ -70,6 +107,12 @@ namespace rat::cc {
return i + 1 < s.size() && s[i] == '\r' && s[i + 1] == '\n' ? 2 : 0;
}

U64 bytesEq(U64 w, C8 b) {
constexpr U64 lo = 0x7F7F7F7F7F7F7F7Full;
U64 x = w ^ ((U64)(U8)b * kBytes1);
return ~(((x & lo) + lo) | x | lo);
}

// trigraph + splice + newline norm in one pass
void splice(const String& src, String& out, List<LineMark>& marks) {
U32 line = 1;
Expand All @@ -79,6 +122,14 @@ namespace rat::cc {
while(i < n) {
// fast path: bulk-copy a run with no splice/trigraph/CR triggers
U64 start = i;
while(i + 8 <= n) {
U64 w;
std::memcpy(&w, data + i, 8);
if(bytesEq(w, '\\') | bytesEq(w, '\r') | bytesEq(w, '?'))
break;
line += (U32)(((bytesEq(w, '\n') >> 7) * kBytes1) >> 56);
i += 8;
}
while(i < n) {
C8 c = data[i];
if(c == '\\' || c == '\r' || c == '?')
Expand Down Expand Up @@ -223,10 +274,10 @@ namespace rat::cc {

U64 PpLexer::wordEnd(U64 j) const {
for(;;) {
if(U64 u = ucnLen(s, j))
j += u;
else if(j < s.size() && isIdentCont(s[j]))
if(j < s.size() && isIdentCont(s[j]))
++j;
else if(U64 u = ucnLen(s, j))
j += u;
else
return j;
}
Expand Down
1 change: 1 addition & 0 deletions src/compiler/lex/preprocess_macro.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -425,6 +425,7 @@ namespace rat::cc {
for(U64 k = in.size(); k > 0; --k)
work.push_back(in[k - 1]);
List<PpToken> os;
os.reserve(in.size());
while(!work.empty()) {
PpToken t = work.back();
work.pop_back();
Expand Down
Loading