export type Cpp14PolicySeverity = "error" | "warning" | "hint"; export type Cpp14PolicyIssue = { id: string; severity: Cpp14PolicySeverity; message: string; detail: string; line: number; column: number; endLine: number; endColumn: number; }; type RegexRule = { id: string; severity: Cpp14PolicySeverity; pattern: RegExp; message: string; detail: string; }; const REGEX_RULES: RegexRule[] = [ { id: "cpp17-header", severity: "error", pattern: /#\s*include\s*<\s*(optional|variant|any|string_view|filesystem|charconv|execution)\s*>/g, message: "检测到 C++17+ 头文件", detail: "福建 CSP-J/S 环境通常以 C++14 为准,建议改为 C++14 可用写法。", }, { id: "if-constexpr", severity: "error", pattern: /\bif\s+constexpr\b/g, message: "检测到 if constexpr(C++17)", detail: "请改用普通条件分支或模板特化方案。", }, { id: "structured-binding", severity: "error", pattern: /\b(?:const\s+)?auto(?:\s*&|\s*&&)?\s*\[[^\]\n]+\]\s*=/g, message: "检测到结构化绑定(C++17)", detail: "可改为 pair.first/second 或自定义结构体字段。", }, { id: "cpp17-stdlib", severity: "error", pattern: /\bstd::(optional|variant|any|string_view|filesystem|byte|clamp|gcd|lcm)\b/g, message: "检测到 C++17+ 标准库符号", detail: "请替换为 C++14 可用实现,避免提交到老版本 GCC 报 CE。", }, { id: "void-main", severity: "error", pattern: /\bvoid\s+main\s*\(/g, message: "main 函数返回类型不规范", detail: "请使用 int main(),并在末尾 return 0;", }, { id: "windows-i64d", severity: "warning", pattern: /%I64d/g, message: "检测到 %I64d(Windows 特有)", detail: "Linux 评测机请使用 %lld 读写 long long。", }, { id: "windows-int64", severity: "warning", pattern: /\b__int64\b/g, message: "检测到 __int64(非标准)", detail: "建议改为标准类型 long long。", }, { id: "bits-header", severity: "warning", pattern: /#\s*include\s*<\s*bits\/stdc\+\+\.h\s*>/g, message: "检测到 ", detail: "福建实战建议优先使用标准头文件,提升环境兼容性。", }, ]; export const CSP_CPP14_TIPS: string[] = [ "编译标准固定为 C++14(建议按 -std=gnu++14 习惯编码),不要使用 C++17+ 特性。", "main 必须是 int main(),结尾写 return 0;。", "long long 的 scanf/printf 请使用 %lld,不要使用 %I64d。", "命名/提交包按考场须知执行:题目目录与源码名使用英文小写。", "福建二轮常见要求是文件读写(freopen),赛前请按官方样例再核对一次。", ]; function buildLineStarts(text: string): number[] { const starts = [0]; for (let i = 0; i < text.length; i += 1) { if (text[i] === "\n") starts.push(i + 1); } return starts; } function offsetToPosition(lineStarts: number[], offset: number): { line: number; column: number } { let lo = 0; let hi = lineStarts.length - 1; while (lo <= hi) { const mid = (lo + hi) >> 1; if (lineStarts[mid] <= offset) lo = mid + 1; else hi = mid - 1; } const lineIdx = Math.max(0, hi); return { line: lineIdx + 1, column: offset - lineStarts[lineIdx] + 1, }; } function pushIssue( issues: Cpp14PolicyIssue[], id: string, severity: Cpp14PolicySeverity, message: string, detail: string, line: number, column: number, endLine: number, endColumn: number ) { issues.push({ id, severity, message, detail, line, column, endLine, endColumn }); } export function analyzeCpp14Policy(code: string): Cpp14PolicyIssue[] { const text = (code ?? "").replace(/\r\n?/g, "\n"); if (!text.trim()) return []; const issues: Cpp14PolicyIssue[] = []; const lineStarts = buildLineStarts(text); for (const rule of REGEX_RULES) { const matcher = new RegExp(rule.pattern.source, rule.pattern.flags); let match = matcher.exec(text); while (match) { const start = match.index; const end = start + Math.max(1, match[0].length); const p1 = offsetToPosition(lineStarts, start); const p2 = offsetToPosition(lineStarts, end); pushIssue( issues, rule.id, rule.severity, rule.message, rule.detail, p1.line, p1.column, p2.line, p2.column ); if (matcher.lastIndex === match.index) matcher.lastIndex += 1; match = matcher.exec(text); } } if (/\bint\s+main\s*\(/.test(text) && !/\breturn\s+0\s*;/.test(text)) { const idx = text.search(/\bint\s+main\s*\(/); const pos = offsetToPosition(lineStarts, Math.max(0, idx)); pushIssue( issues, "main-return-zero", "warning", "建议在 main 末尾显式 return 0;", "部分考场与评测环境会严格检查主函数返回行为。", pos.line, pos.column, pos.line, pos.column + 3 ); } if (/\blong\s+long\b/.test(text) && /\b(?:scanf|printf)\s*\(/.test(text) && !/%lld/.test(text)) { const idx = text.search(/\b(?:scanf|printf)\s*\(/); const pos = offsetToPosition(lineStarts, Math.max(0, idx)); pushIssue( issues, "ll-format", "warning", "检测到 long long + scanf/printf,建议确认格式符为 %lld", "Linux 评测环境不支持 %I64d。", pos.line, pos.column, pos.line, pos.column + 6 ); } return issues; }