| 2906 | function parseRule(input) { |
| 2907 | // 分析器 |
| 2908 | class Tokenizer { |
| 2909 | constructor(input) { |
| 2910 | this.input = input |
| 2911 | this.position = 0 |
| 2912 | this.tokens = [] |
| 2913 | } |
| 2914 | |
| 2915 | isWhitespace(char) { |
| 2916 | return /\s/.test(char) |
| 2917 | } |
| 2918 | |
| 2919 | isDelimiter(char) { |
| 2920 | return ['(', ')', ','].includes(char) |
| 2921 | } |
| 2922 | |
| 2923 | tokenize() { |
| 2924 | // console.log('=== 开始词法分析 ===') |
| 2925 | while (this.position < this.input.length) { |
| 2926 | let currentChar = this.input[this.position] |
| 2927 | |
| 2928 | if (this.isWhitespace(currentChar)) { |
| 2929 | this.position++ |
| 2930 | continue |
| 2931 | } |
| 2932 | |
| 2933 | if (currentChar === '(') { |
| 2934 | this.tokens.push({ type: 'LPAREN', value: '(' }) |
| 2935 | // console.log(`Token: LPAREN '(' at position ${this.position}`) |
| 2936 | this.position++ |
| 2937 | continue |
| 2938 | } |
| 2939 | |
| 2940 | if (currentChar === ')') { |
| 2941 | this.tokens.push({ type: 'RPAREN', value: ')' }) |
| 2942 | // console.log(`Token: RPAREN ')' at position ${this.position}`) |
| 2943 | this.position++ |
| 2944 | continue |
| 2945 | } |
| 2946 | |
| 2947 | if (currentChar === ',') { |
| 2948 | this.tokens.push({ type: 'COMMA', value: ',' }) |
| 2949 | // console.log(`Token: COMMA ',' at position ${this.position}`) |
| 2950 | this.position++ |
| 2951 | continue |
| 2952 | } |
| 2953 | |
| 2954 | // 收集单词 |
| 2955 | let start = this.position |
| 2956 | while ( |
| 2957 | this.position < this.input.length && |
| 2958 | !this.isWhitespace(this.input[this.position]) && |
| 2959 | !this.isDelimiter(this.input[this.position]) |
| 2960 | ) { |
| 2961 | this.position++ |
| 2962 | } |
| 2963 | let value = this.input.slice(start, this.position) |
| 2964 | this.tokens.push({ type: 'WORD', value }) |
| 2965 | // console.log(`Token: WORD '${value}' from position ${start} to ${this.position}`) |
nothing calls this directly
no outgoing calls
no test coverage detected