commit 9fb3f273ed339b048202b5ea54b7a03a8f900964
parent 9741d4d3bc2f88f84a674202d63f15008f1cd2b0
Author: Achuthan TM <achuthantm05@gmail.com>
Date: Thu, 23 Apr 2026 17:21:25 +0530
Week 6: C++ compiler core updates, emitter logic, and PII FPGA wrapper (Part 2: Core logic)
Diffstat:
3 files changed, 62 insertions(+), 85 deletions(-)
diff --git a/src/lexer.h b/src/lexer.h
@@ -14,6 +14,8 @@ enum class TokenType {
PIPE,
LPAREN,
RPAREN,
+ LBRACKET,
+ RBRACKET,
END_OF_INPUT
};
diff --git a/src/main.cpp b/src/main.cpp
@@ -18,14 +18,21 @@ std::string trim(const std::string& str) {
}
int main(int argc, char* argv[]) {
- if (argc < 2) {
- std::cerr << "Usage: " << argv[0] << " <regex_file> [test_strings_file] [output_dir]" << std::endl;
+ bool isPII = false;
+ int argOffset = 1;
+ if (argc > 1 && std::string(argv[1]) == "--pii") {
+ isPII = true;
+ argOffset = 2;
+ }
+
+ if (argc < argOffset + 1) {
+ std::cerr << "Usage: " << argv[0] << " [--pii] <regex_file> [test_strings_file] [output_dir]" << std::endl;
return 1;
}
- std::string regexFilename = argv[1];
- std::string testFilename = (argc > 2) ? argv[2] : "";
- std::string outputDir = (argc > 3) ? argv[3] : "output";
+ std::string regexFilename = argv[argOffset];
+ std::string testFilename = (argc > argOffset + 1) ? argv[argOffset + 1] : "";
+ std::string outputDir = (argc > argOffset + 2) ? argv[argOffset + 2] : "output";
if (testFilename == "-" || testFilename == "none") {
testFilename = "";
@@ -110,7 +117,7 @@ int main(int argc, char* argv[]) {
std::cout << "Generated " << nfas.size() << " NFAs. Emitting Verilog..." << std::endl;
try {
- Emitter::emit(nfas, outputDir, testStrings, expectedMatches);
+ Emitter::emit(nfas, outputDir, testStrings, expectedMatches, isPII);
std::cout << "Pipeline complete. Verilog files emitted to '" << outputDir << "/'" << std::endl;
} catch (const std::exception& e) {
std::cerr << "Error during Verilog emission: " << e.what() << std::endl;
diff --git a/src/nfa.cpp b/src/nfa.cpp
@@ -43,9 +43,9 @@ std::unique_ptr<NFA> NFABuilder::build(ASTNode* root, int regexIdx) {
// 1. Linearization (assign positions to symbols)
int localPosCounter = 1;
- std::map<int, unsigned char> posToChar;
+ std::map<int, std::set<unsigned char>> posToChars;
std::set<int> dotPositions;
- linearize(root, localPosCounter, posToChar, dotPositions);
+ linearize(root, localPosCounter, posToChars, dotPositions);
int numPositions = localPosCounter - 1;
// 2. Compute nullable, firstpos, lastpos
@@ -82,8 +82,9 @@ std::unique_ptr<NFA> NFABuilder::build(ASTNode* root, int regexIdx) {
nfa->addTransition(localToGlobal[0], static_cast<unsigned char>(val), localToGlobal[p]);
}
} else {
- unsigned char c = posToChar[p];
- nfa->addTransition(localToGlobal[0], c, localToGlobal[p]);
+ for (unsigned char c : posToChars[p]) {
+ nfa->addTransition(localToGlobal[0], c, localToGlobal[p]);
+ }
}
}
@@ -95,8 +96,9 @@ std::unique_ptr<NFA> NFABuilder::build(ASTNode* root, int regexIdx) {
nfa->addTransition(localToGlobal[p], static_cast<unsigned char>(val), localToGlobal[q]);
}
} else {
- unsigned char c = posToChar[q];
- nfa->addTransition(localToGlobal[p], c, localToGlobal[q]);
+ for (unsigned char c : posToChars[q]) {
+ nfa->addTransition(localToGlobal[p], c, localToGlobal[q]);
+ }
}
}
}
@@ -104,13 +106,13 @@ std::unique_ptr<NFA> NFABuilder::build(ASTNode* root, int regexIdx) {
return nfa;
}
-void NFABuilder::linearize(ASTNode* node, int& posCounter, std::map<int, unsigned char>& posToChar, std::set<int>& dotPositions) {
+void NFABuilder::linearize(ASTNode* node, int& posCounter, std::map<int, std::set<unsigned char>>& posToChars, std::set<int>& dotPositions) {
if (!node) return;
switch (node->type) {
case ASTNodeType::LITERAL: {
auto n = static_cast<LiteralNode*>(node);
n->position = posCounter++;
- posToChar[n->position] = static_cast<unsigned char>(n->value);
+ posToChars[n->position] = {static_cast<unsigned char>(n->value)};
break;
}
case ASTNodeType::DOT: {
@@ -119,51 +121,48 @@ void NFABuilder::linearize(ASTNode* node, int& posCounter, std::map<int, unsigne
dotPositions.insert(n->position);
break;
}
+ case ASTNodeType::CHAR_CLASS: {
+ auto n = static_cast<CharClassNode*>(node);
+ n->position = posCounter++;
+ posToChars[n->position] = n->characters;
+ break;
+ }
case ASTNodeType::CONCATENATION: {
auto n = static_cast<ConcatenationNode*>(node);
- linearize(n->left.get(), posCounter, posToChar, dotPositions);
- linearize(n->right.get(), posCounter, posToChar, dotPositions);
+ linearize(n->left.get(), posCounter, posToChars, dotPositions);
+ linearize(n->right.get(), posCounter, posToChars, dotPositions);
break;
}
case ASTNodeType::UNION: {
auto n = static_cast<UnionNode*>(node);
- linearize(n->left.get(), posCounter, posToChar, dotPositions);
- linearize(n->right.get(), posCounter, posToChar, dotPositions);
- break;
- }
- case ASTNodeType::STAR: {
- auto n = static_cast<StarNode*>(node);
- linearize(n->inner.get(), posCounter, posToChar, dotPositions);
- break;
- }
- case ASTNodeType::PLUS: {
- auto n = static_cast<PlusNode*>(node);
- linearize(n->inner.get(), posCounter, posToChar, dotPositions);
+ linearize(n->left.get(), posCounter, posToChars, dotPositions);
+ linearize(n->right.get(), posCounter, posToChars, dotPositions);
break;
}
+ case ASTNodeType::STAR:
+ case ASTNodeType::PLUS:
case ASTNodeType::OPTIONAL: {
- auto n = static_cast<OptionalNode*>(node);
- linearize(n->inner.get(), posCounter, posToChar, dotPositions);
+ auto n = static_cast<StarNode*>(node);
+ linearize(n->inner.get(), posCounter, posToChars, dotPositions);
break;
}
+ default: break;
}
}
void NFABuilder::computeNullableFirstLast(ASTNode* node) {
if (!node) return;
switch (node->type) {
- case ASTNodeType::LITERAL: {
- auto n = static_cast<LiteralNode*>(node);
- n->nullable = false;
- n->firstpos = {n->position};
- n->lastpos = {n->position};
- break;
- }
- case ASTNodeType::DOT: {
- auto n = static_cast<DotNode*>(node);
- n->nullable = false;
- n->firstpos = {n->position};
- n->lastpos = {n->position};
+ case ASTNodeType::LITERAL:
+ case ASTNodeType::DOT:
+ case ASTNodeType::CHAR_CLASS: {
+ node->nullable = false;
+ int pos = -1;
+ if (node->type == ASTNodeType::LITERAL) pos = static_cast<LiteralNode*>(node)->position;
+ else if (node->type == ASTNodeType::DOT) pos = static_cast<DotNode*>(node)->position;
+ else pos = static_cast<CharClassNode*>(node)->position;
+ node->firstpos = {pos};
+ node->lastpos = {pos};
break;
}
case ASTNodeType::CONCATENATION: {
@@ -171,16 +170,10 @@ void NFABuilder::computeNullableFirstLast(ASTNode* node) {
computeNullableFirstLast(n->left.get());
computeNullableFirstLast(n->right.get());
n->nullable = n->left->nullable && n->right->nullable;
-
n->firstpos = n->left->firstpos;
- if (n->left->nullable) {
- n->firstpos.insert(n->right->firstpos.begin(), n->right->firstpos.end());
- }
-
+ if (n->left->nullable) n->firstpos.insert(n->right->firstpos.begin(), n->right->firstpos.end());
n->lastpos = n->right->lastpos;
- if (n->right->nullable) {
- n->lastpos.insert(n->left->lastpos.begin(), n->left->lastpos.end());
- }
+ if (n->right->nullable) n->lastpos.insert(n->left->lastpos.begin(), n->left->lastpos.end());
break;
}
case ASTNodeType::UNION: {
@@ -188,38 +181,24 @@ void NFABuilder::computeNullableFirstLast(ASTNode* node) {
computeNullableFirstLast(n->left.get());
computeNullableFirstLast(n->right.get());
n->nullable = n->left->nullable || n->right->nullable;
-
n->firstpos = n->left->firstpos;
n->firstpos.insert(n->right->firstpos.begin(), n->right->firstpos.end());
-
n->lastpos = n->left->lastpos;
n->lastpos.insert(n->right->lastpos.begin(), n->right->lastpos.end());
break;
}
- case ASTNodeType::STAR: {
- auto n = static_cast<StarNode*>(node);
- computeNullableFirstLast(n->inner.get());
- n->nullable = true;
- n->firstpos = n->inner->firstpos;
- n->lastpos = n->inner->lastpos;
- break;
- }
- case ASTNodeType::PLUS: {
- auto n = static_cast<PlusNode*>(node);
- computeNullableFirstLast(n->inner.get());
- n->nullable = n->inner->nullable;
- n->firstpos = n->inner->firstpos;
- n->lastpos = n->inner->lastpos;
- break;
- }
+ case ASTNodeType::STAR:
+ case ASTNodeType::PLUS:
case ASTNodeType::OPTIONAL: {
- auto n = static_cast<OptionalNode*>(node);
+ auto n = static_cast<StarNode*>(node);
computeNullableFirstLast(n->inner.get());
- n->nullable = true;
+ n->nullable = (node->type != ASTNodeType::PLUS) || n->inner->nullable;
+ if (node->type == ASTNodeType::STAR || node->type == ASTNodeType::OPTIONAL) n->nullable = true;
n->firstpos = n->inner->firstpos;
n->lastpos = n->inner->lastpos;
break;
}
+ default: break;
}
}
@@ -230,25 +209,14 @@ void NFABuilder::computeFollowpos(ASTNode* node, std::map<int, std::set<int>>& f
auto n = static_cast<ConcatenationNode*>(node);
computeFollowpos(n->left.get(), followpos);
computeFollowpos(n->right.get(), followpos);
- for (int p : n->left->lastpos) {
- followpos[p].insert(n->right->firstpos.begin(), n->right->firstpos.end());
- }
- break;
- }
- case ASTNodeType::STAR: {
- auto n = static_cast<StarNode*>(node);
- computeFollowpos(n->inner.get(), followpos);
- for (int p : n->inner->lastpos) {
- followpos[p].insert(n->inner->firstpos.begin(), n->inner->firstpos.end());
- }
+ for (int p : n->left->lastpos) followpos[p].insert(n->right->firstpos.begin(), n->right->firstpos.end());
break;
}
+ case ASTNodeType::STAR:
case ASTNodeType::PLUS: {
- auto n = static_cast<PlusNode*>(node);
+ auto n = static_cast<StarNode*>(node);
computeFollowpos(n->inner.get(), followpos);
- for (int p : n->inner->lastpos) {
- followpos[p].insert(n->inner->firstpos.begin(), n->inner->firstpos.end());
- }
+ for (int p : n->inner->lastpos) followpos[p].insert(n->inner->firstpos.begin(), n->inner->firstpos.end());
break;
}
case ASTNodeType::UNION: {