如何修复JavaScript Lexer将浮点数拆分为标识符与数字的问题?
修复Lexer浮点数识别问题的方案
问题根源
你的Lexer当前先检查字符是否属于字母数字(正则[a-zA-Z0-9]包含数字),所以当遇到浮点数的整数部分(比如7.24里的7)时,会优先进入字母数字处理分支,把7单独识别为数字/标识符,剩下的.24会被拆分为dot和number,导致浮点数被拆分。
修复步骤
1. 调整判断顺序:数字逻辑优先于字母数字逻辑
把数字识别的代码块移到字母数字识别的前面,确保数字开头的字符(包括带小数点的)先被处理。
2. 修正数字处理逻辑,避免单独小数点误判
在数字处理分支里,要确保:
- 如果第一个字符是小数点,后面必须跟数字,否则抛出错误或者识别为单独的dot
- 限制小数点只能出现一次
3. 保留单独小数点处理分支
合法浮点数的小数点由数字逻辑处理,单独的小数点(比如对象属性访问场景)仍由专门分支处理,避免冲突。
修改后的完整代码
function lexer(input) { const tokens = []; const keywords = new Set(['let', 'var', 'const', 'def', 'float', 'floater', 'double', 'int', 'integer', 'bool', 'boolean', 'string', 'char']); const alphaNumericRegex = /[a-zA-Z0-9]/; const digitRegex = /\d/; let current = 0; const length = input.length; while (current < length) { let char = input[current]; // 跳过空白符 if (char === ' ' || char === '\n') { current++; continue; } // 优先处理数字(包括浮点数) if (digitRegex.test(char) || (char === '.' && digitRegex.test(input[current + 1]))) { let numStart = current; let hasDecimal = false; while (digitRegex.test(char) || (!hasDecimal && char === '.')) { if (char === '.') { hasDecimal = true; // 确保小数点后有数字,否则报错 if (!digitRegex.test(input[current + 1])) { throw new SyntaxError("Invalid number: trailing decimal point"); } } char = input[++current]; } const numStr = input.slice(numStart, current); const num = parseFloat(numStr); if (isNaN(num)) { throw new SyntaxError("Invalid number"); } tokens.push({ type: Number.isInteger(num) ? 'integer' : 'float', value: num }); continue; } // 处理字母数字(关键字/标识符) if (alphaNumericRegex.test(char)) { const wordStart = current; while (alphaNumericRegex.test(char)) { char = input[++current]; } const word = input.slice(wordStart, current); if (keywords.has(word)) { tokens.push({ type: 'keyword', value: word }); } else { tokens.push({ type: 'identifier', value: word }); } continue; } // 处理字符串 if (char === '"') { const strStart = ++current; while (input[current] !== '"') { if (++current >= length) throw new SyntaxError("Unterminated string literal"); } const str = input.slice(strStart, current++); tokens.push({ type: 'string', value: str }); continue; } // 处理字符字面量 if (char === '\'') { const charValue = input[++current]; if (input[++current] === '\'') { tokens.push({ type: 'char', value: charValue }); current++; } else { throw new SyntaxError("Invalid character literal"); } continue; } // 处理赋值符号 if (char === '=') { tokens.push({ type: 'assign' }); current++; continue; } // 处理分号 if (char === ';') { tokens.push({ type: 'semicolon' }); current++; continue; } // 处理单独的小数点(比如对象属性访问的点) if (char === '.') { tokens.push({ type: 'dot' }); current++; continue; } // 未知字符跳过(可改为抛出错误) current++; } return tokens; } const code = `let value = 7.24; var count = 5; const pi = 3.14; bool isTrue = true; string message = "Hello"; char initial = 'A';`; console.log(JSON.stringify(lexer(code), null, 2));
关键修改说明
- 数字逻辑前置:确保
7.24这类字符串会被完整识别,而不会被拆分为整数和小数点+小数两部分。 - 小数点合法性校验:避免单独的
.被误判为浮点数,同时防止出现7.这类不合法的数字格式。 - 区分数值类型:将原统一的
number类型拆分为integer和float,让token类型更精准(不需要的话可改回number)。
内容的提问来源于stack exchange,提问作者TheBestestJSCppMaker
相关产品推荐
相关产品推荐

