xiiregexbuilder

FPGA-Accelerated Regular Expression Matching Engine

golden.cpp (3177B)


#include <iostream>
#include <fstream>
#include <string>
#include <vector>
#include <regex>
#include <iomanip>
#include <algorithm>

std::string trim(const std::string& str) {
    size_t first = str.find_first_not_of(" \t\r\n");
    if (first == std::string::npos) return "";
    size_t last = str.find_last_not_of(" \t\r\n");
    return str.substr(first, (last - first + 1));
}

int main(int argc, char* argv[]) {
    if (argc < 3) {
        std::cerr << "Usage: " << argv[0] << " <regex_file> <test_strings_file> [output_file]" << std::endl;
        return 1;
    }

    std::string regexFilename = argv[1];
    std::string testFilename = argv[2];
    std::string outputFilename = (argc > 3) ? argv[3] : "expected_matches.txt";

    std::ifstream regexFile(regexFilename);
    if (!regexFile.is_open()) {
        std::cerr << "Failed to open " << regexFilename << std::endl;
        return 1;
    }

    std::vector<std::string> regexes;
    std::string line;
    while (std::getline(regexFile, line)) {
        std::string trimmed = trim(line);
        if (trimmed.empty() || trimmed[0] == '#') continue;
        regexes.push_back(trimmed);
    }
    regexFile.close();

    std::ifstream testFile(testFilename);
    if (!testFile.is_open()) {
        std::cerr << "Failed to open " << testFilename << std::endl;
        return 1;
    }

    std::vector<std::string> testStrings;
    while (std::getline(testFile, line)) {
        // Remove trailing \r\n
        size_t last = line.find_last_not_of("\r\n");
        std::string s = (last != std::string::npos) ? line.substr(0, last + 1) : (line.empty() ? "" : line);
        
        // Skip comments and blank lines if desired, but spec says "Each line is one test string"
        // Let's at least skip the comment headers if they start with #
        if (!s.empty() && s[0] == '#') continue;
        if (s.empty()) {
            // Check if it's truly a blank line (might be intentional empty string test)
            // For safety, let's only skip if the raw line was empty or just whitespace
            if (trim(line).empty()) continue;
        }

        testStrings.push_back(s);
    }
    testFile.close();

    std::ofstream outFile(outputFilename);
    if (!outFile.is_open()) {
        std::cerr << "Failed to open " << outputFilename << " for writing." << std::endl;
        return 1;
    }

    for (const auto& testStr : testStrings) {
        std::string mask = "";
        for (size_t i = 0; i < regexes.size(); ++i) {
            bool matches = false;
            try {
                // std::regex_match does full match.
                std::regex re(regexes[i]);
                matches = std::regex_match(testStr, re);
            } catch (const std::regex_error& e) {
                // Ignore syntax mismatch
            }
            mask += (matches ? "1" : "0");
        }
        // Reverse mask so bit 0 is on the right (Verilog convention)
        std::reverse(mask.begin(), mask.end());
        outFile << mask << "\n";
    }
    outFile.close();

    std::cout << "Golden reference generated: " << outputFilename << " (" << testStrings.size() << " test cases)" << std::endl;

    return 0;
}