js 如何用函数的方式解析if表达式?
我有一个表达式:
( a || b && c ) && ( d || e )
a
、b
、c
、d
、e
都是之后会进行解析的函数,类型是() => boolean
,这个可以不用管
我想把这个表达式解析成一个变量,这样我可以用函数调用的形式来得到这个表达式的结果。
目前我想到的变量格式是这样的:
interface Expression {
type: 'and' | 'or',
children: Array<Expression>
}
const res: Expression = {
type: 'and',
children: [
{
type: 'or',
children: [
{ type: 'and', children: [a] }
{ type: 'and', children: [b, c] }
]
},
{
type: 'or',
children: [d, e]
}
]
}
type
为'and'
的表达式children
中的每个嵌套表达式都要为true
,此时这个表达式才是true
type
为'or'
的表达式则是children
里只要有一个为true
就行
现在我遇到的主要问题是括号没想到啥好办法去处理,因为我想要的表达式变量格式是按实际运算顺序排列的,但是原始的表达式是从左到右按书写顺序排列的
或者有啥更好的方式能做到说用函数的方式解析if表达式(不要eval
、new Function
)
回复
1个回答

test
2024-07-15
简单的二元表达式解析,在线地址, evaluator我就不写了具体可以看一下我的这个项目代码
const text = "( a || b && c ) && ( d || e )";
enum TokenType {
Identifier = "Identifier",
And = "And",
OR = "OR",
LPAREN = "LPAREN",
RPAREN = "RPAREN",
EOF = "EOF"
}
class Token {
constructor(
public readonly type: TokenType,
public readonly literal: string
) {}
}
type Expression = Token | BinaryExpression;
class BinaryExpression {
constructor(
public readonly left: Expression,
public readonly operator,
public readonly right: Expression
) {}
}
const lexer = (s: string): Token[] => {
const tokens: Token[] = [];
const n = s.length;
let idx = 0;
const isLetter = (c: string) => {
if ((c >= "a" && c <= "z") || (c >= "A" && c <= "Z")) {
return true;
}
return false;
};
const readIdent = (): string => {
let start = idx;
while (isLetter(s[idx])) {
++idx;
}
return s.slice(start, idx);
};
while (idx < n) {
const c = s[idx];
switch (c) {
case " ":
case "\t":
case "\r":
case "\n":
++idx;
break;
case "(":
tokens.push(new Token(TokenType.LPAREN, "("));
++idx;
break;
case ")":
tokens.push(new Token(TokenType.RPAREN, ")"));
++idx;
break;
case "|":
++idx;
if (s[idx] === "|") {
tokens.push(new Token(TokenType.OR, "||"));
++idx;
} else {
throw new Error(`lexer: Bad character '${s[idx]}' at index ${idx}`);
}
break;
case "&":
++idx;
if (s[idx] === "&") {
tokens.push(new Token(TokenType.And, "&&"));
++idx;
} else {
throw new Error(`lexer: Bad character '${s[idx]}' at index ${idx}`);
}
break;
default: {
if (isLetter(c)) {
const ident = readIdent();
tokens.push(new Token(TokenType.Identifier, ident));
}
}
}
}
tokens.push(new Token(TokenType.EOF, ""));
return tokens;
};
const parser = (tokens: Token[]): Expression => {
let idx = 0;
const matchToken = (type: TokenType): Token => {
if (tokens[idx].type !== type) {
throw new Error(
`expected SyntaxType ${type}, got=${tokens[idx].type} at index ${idx}`
);
}
const token = tokens[idx];
++idx;
return token;
};
const getBinaryOperatorPrecedence = (token: Token): number => {
switch (token.type) {
case TokenType.OR:
return 1;
case TokenType.And:
return 2;
default:
return 0;
}
};
const parsePrimaryExpression = (): Expression => {
const token = tokens[idx];
switch (token.type) {
case TokenType.Identifier:
++idx;
return token;
case TokenType.LPAREN: {
++idx;
const expr = parseBinaryExpression(0);
matchToken(TokenType.RPAREN);
return expr;
}
default:
throw new Error(`ParseExpression: unexpected NodeType '${token.type}'`);
}
};
const parseBinaryExpression = (parentPrecedence: number): Expression => {
let left = parsePrimaryExpression();
while (true) {
const operator = tokens[idx];
const precedence = getBinaryOperatorPrecedence(operator);
if (precedence <= parentPrecedence) {
break;
}
++idx;
const right = parseBinaryExpression(precedence);
left = new BinaryExpression(left, operator, right);
}
return left;
};
return parseBinaryExpression(0);
};
const tokens = lexer(text);
const ast = parser(tokens);
console.log(ast);
回复

适合作为回答的
- 经过验证的有效解决办法
- 自己的经验指引,对解决问题有帮助
- 遵循 Markdown 语法排版,代码语义正确
不该作为回答的
- 询问内容细节或回复楼层
- 与题目无关的内容
- “赞”“顶”“同问”“看手册”“解决了没”等毫无意义的内容