From 74b983c74e4d2c72ef2db0f7a7df2a381e10f053 Mon Sep 17 00:00:00 2001 From: sxg <840309695@qq.com> Date: Mon, 31 Aug 2026 10:24:13 +0800 Subject: [PATCH] =?UTF-8?q?c++=E8=A7=A3=E9=87=8A=E5=99=A8=E4=BF=AE?= =?UTF-8?q?=E6=94=B9?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../src/components/stage-cpp/cpp-parser.js | 220 ++++++++++++------ 1 file changed, 150 insertions(+), 70 deletions(-) diff --git a/scratch-gui/src/components/stage-cpp/cpp-parser.js b/scratch-gui/src/components/stage-cpp/cpp-parser.js index 028b22aa..2448e465 100644 --- a/scratch-gui/src/components/stage-cpp/cpp-parser.js +++ b/scratch-gui/src/components/stage-cpp/cpp-parser.js @@ -821,8 +821,8 @@ export class CppCodeExecutor { statements.push(whileLoop); i = whileLoop.endIndex; } else { - // 检查是否是break或continue语句 - if (line === 'break;' || line === 'continue;') { + // 检查是否是break或continue或return语句 + if (line === 'break;' || line === 'continue;' || line.startsWith('return')) { statements.push({ type: 'control', subtype: line === 'break;' ? 'break' : 'continue', @@ -866,21 +866,27 @@ export class CppCodeExecutor { let braceCount = 0; let bodyStart = startIndex + 1; let bodyEnd = startIndex + 1; + let hasBrace = false; for (let i = startIndex; i < lines.length; i++) { const line = lines[i]; debugLog(`🔍 检查行 ${i}: "${line.trim()}" (大括号计数: ${braceCount})`); - if (line.includes('{')) braceCount++; + if (line.includes('{')) { braceCount++; hasBrace = true; } if (line.includes('}')) braceCount--; - if (braceCount === 0 && i > startIndex) { + if (hasBrace && braceCount === 0 && i > startIndex) { bodyEnd = i; debugLog(`🔍 找到循环体结束位置: ${bodyEnd}`); break; } + if (!hasBrace && i > startIndex && line.trim() && !line.trim().startsWith('//')) { + bodyEnd = i + 1; + debugLog(`🔍 找到无大括号循环体结束位置: ${bodyEnd}`); + break; + } } // 如果没有找到结束大括号,可能是格式问题 - if (bodyEnd === startIndex + 1) { + if (hasBrace && bodyEnd === startIndex + 1) { debugLog(`⚠️ 警告:没有找到循环体结束大括号,检查代码格式`); debugLog(`⚠️ 当前所有行内容:`); lines.forEach((line, index) => { @@ -914,7 +920,7 @@ export class CppCodeExecutor { increment, body: bodyStatements, lineNumber: isMainFunction ? this.getActualLineNumber(startIndex) : startIndex + 1, - endIndex: bodyEnd + 1 + endIndex: hasBrace ? bodyEnd + 1 : bodyEnd }; } @@ -935,11 +941,26 @@ export class CppCodeExecutor { const condition = ifMatch[1]; + // 最小化修改:如果if同行包含执行语句,把它拆分拆到下一行 + const afterIf = ifLine.substring(ifMatch.index + ifMatch[0].length).trim(); + if (afterIf && afterIf !== '{') { + if (afterIf.startsWith('{')) { + lines[startIndex] = ifLine.substring(0, ifLine.lastIndexOf(afterIf)) + '{'; + const afterBrace = afterIf.substring(1).trim(); + if (afterBrace) lines.splice(startIndex + 1, 0, afterBrace); + } else { + lines[startIndex] = ifLine.substring(0, ifLine.lastIndexOf(afterIf)).trim(); + lines.splice(startIndex + 1, 0, afterIf); + } + } + + // 找到if语句体 let braceCount = 0; let bodyStart = startIndex + 1; let bodyEnd = startIndex + 1; let ifClosingLine = ''; // 保存if语句的结束行,可能包含else + let hasBrace = false; for (let i = startIndex; i < lines.length; i++) { const line = lines[i]; @@ -954,15 +975,31 @@ export class CppCodeExecutor { break; } - if (line.includes('{')) braceCount++; + if (line.includes('{')) { braceCount++; hasBrace = true; } if (line.includes('}')) braceCount--; - if (braceCount === 0 && i > startIndex) { + + if (hasBrace && braceCount === 0 && i > startIndex) { // 普通的}结束 bodyEnd = i; ifClosingLine = trimmedLine; debugLog(`🔍 if语句结束位置: 行${i}, 内容: "${ifClosingLine}", 是否包含else: ${ifClosingLine.includes('else')}`); break; } + + if (!hasBrace && i > startIndex && trimmedLine && !trimmedLine.startsWith('//')) { + bodyEnd = i + 1; + // 尝试寻找后续的else + for (let j = i + 1; j < lines.length; j++) { + const nextLine = lines[j].trim(); + if (!nextLine || nextLine.startsWith('//')) continue; + if (nextLine.startsWith('else')) { + ifClosingLine = nextLine; + debugLog(`🔍 无大括号单行语句后发现else: 行${j}, 内容: "${ifClosingLine}"`); + } + break; + } + break; + } } let bodyLines = lines.slice(bodyStart, bodyEnd); @@ -984,7 +1021,7 @@ export class CppCodeExecutor { // 解析else if 和 else 分支 const elseIfBranches = []; let elseStatements = []; - let currentIndex = bodyEnd + 1; + let currentIndex = hasBrace ? bodyEnd + 1 : bodyEnd; // 首先检查if结束行是否包含else(处理 } else { 的情况) if (ifClosingLine.includes('else')) { @@ -1110,15 +1147,20 @@ export class CppCodeExecutor { let elseIfBraceCount = 0; let elseIfBodyStart = currentIndex + 1; let elseIfBodyEnd = currentIndex + 1; + let elseIfHasBrace = false; for (let i = currentIndex; i < lines.length; i++) { const line = lines[i]; - if (line.includes('{')) elseIfBraceCount++; + if (line.includes('{')) { elseIfBraceCount++; elseIfHasBrace = true; } if (line.includes('}')) elseIfBraceCount--; - if (elseIfBraceCount === 0 && i > currentIndex) { + if (elseIfHasBrace && elseIfBraceCount === 0 && i > currentIndex) { elseIfBodyEnd = i; break; } + if (!elseIfHasBrace && i > currentIndex && line.trim() && !line.trim().startsWith('//')) { + elseIfBodyEnd = i + 1; + break; + } } const elseIfBodyLines = lines.slice(elseIfBodyStart, elseIfBodyEnd); @@ -1131,7 +1173,7 @@ export class CppCodeExecutor { debugLog(`🔍 解析else if语句体,条件: ${elseIfCondition}, 行数: ${elseIfBodyLines.length}, 语句数: ${elseIfStatements.length}`); - currentIndex = elseIfBodyEnd + 1; + currentIndex = elseIfHasBrace ? elseIfBodyEnd + 1 : elseIfBodyEnd; continue; } @@ -1143,15 +1185,20 @@ export class CppCodeExecutor { let elseBraceCount = 0; let elseBodyStart = currentIndex + 1; let elseBodyEnd = currentIndex + 1; + let elseHasBrace = false; for (let i = currentIndex; i < lines.length; i++) { const line = lines[i]; - if (line.includes('{')) elseBraceCount++; + if (line.includes('{')) { elseBraceCount++; elseHasBrace = true; } if (line.includes('}')) elseBraceCount--; - if (elseBraceCount === 0 && i > currentIndex) { + if (elseHasBrace && elseBraceCount === 0 && i > currentIndex) { elseBodyEnd = i; break; } + if (!elseHasBrace && i > currentIndex && line.trim() && !line.trim().startsWith('//')) { + elseBodyEnd = i + 1; + break; + } } let elseBodyLines = lines.slice(elseBodyStart, elseBodyEnd); @@ -1173,7 +1220,7 @@ export class CppCodeExecutor { debugLog(`🔍 解析else语句体,行数: ${elseBodyLines.length}, 语句数: ${elseStatements.length}`); - currentIndex = elseBodyEnd + 1; + currentIndex = elseHasBrace ? elseBodyEnd + 1 : elseBodyEnd; break; // else分支是最后一个,不再继续 } @@ -1208,15 +1255,20 @@ export class CppCodeExecutor { let braceCount = 0; let bodyStart = startIndex + 1; let bodyEnd = startIndex + 1; + let hasBrace = false; for (let i = startIndex; i < lines.length; i++) { const line = lines[i]; - if (line.includes('{')) braceCount++; + if (line.includes('{')) { braceCount++; hasBrace = true; } if (line.includes('}')) braceCount--; - if (braceCount === 0 && i > startIndex) { + if (hasBrace && braceCount === 0 && i > startIndex) { bodyEnd = i; break; } + if (!hasBrace && i > startIndex && line.trim() && !line.trim().startsWith('//')) { + bodyEnd = i + 1; + break; + } } let bodyLines = lines.slice(bodyStart, bodyEnd); @@ -1239,7 +1291,7 @@ export class CppCodeExecutor { condition, body: bodyStatements, lineNumber: isMainFunction ? this.getActualLineNumber(startIndex) : startIndex + 1, - endIndex: bodyEnd + 1 + endIndex: hasBrace ? bodyEnd + 1 : bodyEnd }; } @@ -1259,7 +1311,7 @@ export class CppCodeExecutor { // 高亮当前执行行 if (this.setHighlightedLine) { - // this.setHighlightedLine(statement.lineNumber); + this.setHighlightedLine(statement.lineNumber); } await new Promise(resolve => setTimeout(resolve, 0)); @@ -1282,6 +1334,9 @@ export class CppCodeExecutor { await this.executeFunctionCall(statement); break; case 'control': + if (statement.content.startsWith('return')) { + throw new Error('RETURN_INTERRUPT'); + } // break和continue在各自的循环中处理,这里只记录 debugLog(`🔄 控制语句: ${statement.subtype}`); break; @@ -1792,8 +1847,12 @@ export class CppCodeExecutor { }); try { - // 创建函数作用域(保存当前变量状态) - const savedVariables = new Map(this.variables); + // 最小改动:防递归数据污染,只备份会被覆盖的同名参数变量 + const savedParams = new Map(); + for (let i = 0; i < functionInfo.parameters.length; i++) { + const pName = functionInfo.parameters[i].name; + if (this.variables.has(pName)) savedParams.set(pName, this.variables.get(pName)); + } // 设置函数参数变量 for (let i = 0; i < functionInfo.parameters.length; i++) { @@ -1808,32 +1867,42 @@ export class CppCodeExecutor { } // 执行函数体中的所有语句 - for (const functionStatement of functionInfo.body) { - if (this.shouldStop()) break; - - // 使用预先计算好的精确行号,如果没有则计算行号 - let adjustedStatement; - if (functionStatement.exactLineNumber) { - adjustedStatement = { - ...functionStatement, - lineNumber: functionStatement.exactLineNumber - }; - console.log(`🎯 使用函数内精确行号: "${functionStatement.content}" -> 第${functionStatement.exactLineNumber}行 (函数: ${functionName})`); - } else { - // 需要更精确地计算函数内语句的实际行号 - const actualLineNumber = this.calculateActualLineNumber(functionName, functionStatement); - adjustedStatement = { - ...functionStatement, - lineNumber: actualLineNumber - }; + try { + for (const functionStatement of functionInfo.body) { + if (this.shouldStop()) break; + + // 使用预先计算好的精确行号,如果没有则计算行号 + let adjustedStatement; + if (functionStatement.exactLineNumber) { + adjustedStatement = { + ...functionStatement, + lineNumber: functionStatement.exactLineNumber + }; + console.log(`🎯 使用函数内精确行号: "${functionStatement.content}" -> 第${functionStatement.exactLineNumber}行 (函数: ${functionName})`); + } else { + // 需要更精确地计算函数内语句的实际行号 + const actualLineNumber = this.calculateActualLineNumber(functionName, functionStatement); + adjustedStatement = { + ...functionStatement, + lineNumber: actualLineNumber + }; + } + + await this.executeStatement(adjustedStatement); } - - await this.executeStatement(adjustedStatement); + } catch (e) { + if (e.message !== 'RETURN_INTERRUPT') throw e; } - // 恢复函数调用前的变量状态(简单的作用域实现) - // 注意:这是简化版本,实际C++的作用域更复杂 - this.variables = savedVariables; + // 最小改动:仅恢复递归调用前的参数状态,保留全局变量的修改 + for (let i = 0; i < functionInfo.parameters.length; i++) { + const pName = functionInfo.parameters[i].name; + if (savedParams.has(pName)) { + this.variables.set(pName, savedParams.get(pName)); + } else { + this.variables.delete(pName); + } + } console.log(`✅ 函数${functionName}执行完成`); @@ -2332,28 +2401,10 @@ export class CppCodeExecutor { // 处理一元运算符(负号) expr = this.handleUnaryOperators(expr); - // 按运算优先级解析:乘法、除法和模运算优先 - if (expr.includes('*') || expr.includes('/') || expr.includes('%')) { - return this.parseMultiplicationDivision(expr); - } - - // 然后处理加法和减法 - if (expr.includes('+') || expr.includes('-')) { - return this.parseAdditionSubtraction(expr); - } - - // 如果是单个值 - if (/^-?\d+$/.test(expr)) { - return parseInt(expr); - } - - // 变量查找 - if (this.variables.has(expr)) { - return this.variables.get(expr); - } - - debugLog(`⚠️ 无法识别的表达式: ${expr}, 返回默认值 0`); - return 0; + // 按正确的运算优先级解析: + // 加法和减法是最低优先级,因此在此处最先切分。 + // 切分后的每一项将交给 parseAdditionSubtraction,在其中处理更高级别的乘除法。 + return this.parseAdditionSubtraction(expr); } catch (error) { debugLog(`⚠️ 表达式解析错误: ${expr}, 错误: ${error.message}`); @@ -2490,20 +2541,49 @@ export class CppCodeExecutor { // 计算单个标记的值 evaluateToken(token) { token = token.trim(); + if (!token) return 0; + + // 如果包含乘除法或模运算,交给乘除法解析器处理 + if (token.includes('*') || token.includes('/') || token.includes('%')) { + return this.parseMultiplicationDivision(token); + } + + // 布尔常量 + if (token === 'true') return 1; + if (token === 'false') return 0; // 数字 if (/^-?\d+$/.test(token)) { return parseInt(token); } - // 变量 + // 变量查找 if (this.variables.has(token)) { return this.variables.get(token); } - // 如果包含乘除法或模运算,递归处理 - if (token.includes('*') || token.includes('/') || token.includes('%')) { - return this.parseMultiplicationDivision(token); + // 对象属性访问 (如 pos.x, pos.y, pos.z) + if (token.includes('.')) { + const [objName, propName] = token.split('.'); + if (this.variables.has(objName)) { + const obj = this.variables.get(objName); + if (obj && typeof obj === 'object' && obj[propName] !== undefined) { + return obj[propName]; + } + } + } + + // 游戏API调用 + if (token.includes('player_data(')) { + const match = token.match(/player_data\s*\(\s*"(.+?)"\s*\)/); + if (match) return window.cppGameAPI.player_data(match[1]); + } + if (token.includes('player_position(')) { + const match = token.match(/player_position\s*\(\s*"(.+?)"\s*\)/); + if (match) return window.cppGameAPI.player_position(match[1]); + } + if (token.includes('vehicle_position()')) { + return window.cppGameAPI.vehicle_position(); } debugLog(`⚠️ 无法解析标记: ${token}`);