From 08cbd2b9ec4721d9fb171b5926b9e43d48ee8b49 Mon Sep 17 00:00:00 2001 From: Yingdi Zhao <1357157312@qq.com> Date: Sat, 17 May 2025 15:38:41 +0000 Subject: [PATCH 1/3] Fix: negative number recognition issue --- src/observer/sql/parser/lex_sql.l | 4 ++-- src/observer/sql/parser/yacc_sql.y | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/src/observer/sql/parser/lex_sql.l b/src/observer/sql/parser/lex_sql.l index fecff9b5f..2b9258ba8 100644 --- a/src/observer/sql/parser/lex_sql.l +++ b/src/observer/sql/parser/lex_sql.l @@ -78,8 +78,8 @@ QUOTE [\'\"] {WHITE_SPACE} // ignore whitespace \n ; -[\-]?{DIGIT}+ yylval->number=atoi(yytext); RETURN_TOKEN(NUMBER); -[\-]?{DIGIT}+{DOT}{DIGIT}+ yylval->floats=(float)(atof(yytext)); RETURN_TOKEN(FLOAT); +{DIGIT}+ yylval->number=atoi(yytext); RETURN_TOKEN(NUMBER); +{DIGIT}+{DOT}{DIGIT}+ yylval->floats=(float)(atof(yytext)); RETURN_TOKEN(FLOAT); ";" RETURN_TOKEN(SEMICOLON); {DOT} RETURN_TOKEN(DOT); diff --git a/src/observer/sql/parser/yacc_sql.y b/src/observer/sql/parser/yacc_sql.y index 3eeaa4520..83a909bb3 100644 --- a/src/observer/sql/parser/yacc_sql.y +++ b/src/observer/sql/parser/yacc_sql.y @@ -189,7 +189,7 @@ UnboundAggregateExpr *create_aggregate_expression(const char *aggregate_name, %left '+' '-' %left '*' '/' -%nonassoc UMINUS +%right UMINUS %% commands: command_wrapper opt_semicolon //commands or sqls. parser starts here. From b013e72b8b7c5e938c0730c3bde93ed18de3a0ad Mon Sep 17 00:00:00 2001 From: CubeLov <1357157312@qq.com> Date: Mon, 19 May 2025 12:25:21 +0800 Subject: [PATCH 2/3] Add docs for negative numbers --- docs/docs/design/miniob-sql-expression.md | 23 +++++++++++++---------- 1 file changed, 13 insertions(+), 10 deletions(-) diff --git a/docs/docs/design/miniob-sql-expression.md b/docs/docs/design/miniob-sql-expression.md index 23d05c258..0ed8cfac4 100644 --- a/docs/docs/design/miniob-sql-expression.md +++ b/docs/docs/design/miniob-sql-expression.md @@ -116,13 +116,13 @@ expression 的规则会比较简单,加减乘除,以及负号取反。这里 %left '*' '/' ``` -%left 表示左结合,就是遇到指定的符号,先跟左边的符号结合。而定义的顺序就是优先级的顺序,越靠后的优先级越高。 +%left 表示左结合,就是遇到指定的符号,先跟左边的符号结合,比如 `1+2+3` 会被解析为 `(1+2)+3`。而定义的顺序就是优先级的顺序,越靠后的优先级越高。 负号运算符的特殊性除了它的优先级,还有它的结合性。普通的运算,比如 `1+2`,是两个数字即两个表达式,一个运算符。而负号的表示形式是 `-(1+2)`,即一个符号,一个表达式。 ```yacc -%nonassoc UMINUS +%right UMINUS ``` -表示 `UMINUS` 是一个一元运算符,没有结合性。在.y中,放到了 `%left '*' '/'` 的后面,说明优先级比乘除运算符高。 +表示 `UMINUS` 是一个一元运算符,%right 表示右结合,作用与左结合类似,保证 `- -5` 等类似表达式可以被正确识别为 `-(-5)`。在.y中,放到了 `%left '*' '/'` 的后面,说明优先级比乘除运算符高。 expression 的规则如下: ```yacc @@ -163,10 +163,13 @@ expression '+' expression { 这些表达式的定义已经在expression.h中定义,但是没有在语法解析中体现。更完善的做法是在 select 的属性列表、where 条件、insert 的 values等语句中,都使用表达式来表示。 -## '-' 缺陷 -由于在词法分析中,负号'-'与数字放在一起时,会被认为是一个负值数字,作为一个完整的token返回给语法分析,所以当前的语法分析无法正确的解析下面的表达式: -``` -1 -2; -``` -这个表达式的结果应该是 -1,但是当前的语法分析会认为是两个表达式,一个是1,一个是-2,这样就无法正确的计算出结果。 -当前修复此问题的成本较高,需要修改词法分析的规则,所以暂时不做处理。 \ No newline at end of file +## ~~'-' 缺陷~~ (已修复) +在先前版本,当负号 '-' 与数字放在一起时,会被词法分析认为是一个负值数字,作为一个完整的token返回给语法分析。故语法分析无法正确的解析类似 `1 -2` 的表达式,会将其识别为 `1` 和 `-2` 两个数字。 + +### 解决方案 +在词法分析中删除 "负数" 规则,将 '-' digits 解析为 "负号+表达式(数字)" 两个token,应用 `UMINUS` 的优先级,以实现正确区分一元负号和二元减号运算符。这样在处理类似 `1-2` 的表达式时,会将 `1`、`-`、`2` 识别为三个独立的token,以正确匹配减法规则。 + +### 优先级分析 +1. ​​二元运算符​​:乘除 > 加减 +2. ​一元负号​​:高于所有二元运算符 +3. ​括号​​:通过语法层级隐式最高 \ No newline at end of file From fa5779cf0605f43b61dcaa933476dca9d14f20b4 Mon Sep 17 00:00:00 2001 From: CubeLov <1357157312@qq.com> Date: Mon, 19 May 2025 15:53:07 +0800 Subject: [PATCH 3/3] Update docs --- docs/docs/design/miniob-sql-expression.md | 13 +------------ 1 file changed, 1 insertion(+), 12 deletions(-) diff --git a/docs/docs/design/miniob-sql-expression.md b/docs/docs/design/miniob-sql-expression.md index 0ed8cfac4..6f1e4778f 100644 --- a/docs/docs/design/miniob-sql-expression.md +++ b/docs/docs/design/miniob-sql-expression.md @@ -161,15 +161,4 @@ expression '+' expression { ## 抽象表达式类型 上面语法分析中描述的都是算术表达式,但是真实的SQL语句中,像字段名、常量、比较运算、函数、子查询等都是表达式。我们需要定义一个基类,然后派生出各种表达式类型。 -这些表达式的定义已经在expression.h中定义,但是没有在语法解析中体现。更完善的做法是在 select 的属性列表、where 条件、insert 的 values等语句中,都使用表达式来表示。 - -## ~~'-' 缺陷~~ (已修复) -在先前版本,当负号 '-' 与数字放在一起时,会被词法分析认为是一个负值数字,作为一个完整的token返回给语法分析。故语法分析无法正确的解析类似 `1 -2` 的表达式,会将其识别为 `1` 和 `-2` 两个数字。 - -### 解决方案 -在词法分析中删除 "负数" 规则,将 '-' digits 解析为 "负号+表达式(数字)" 两个token,应用 `UMINUS` 的优先级,以实现正确区分一元负号和二元减号运算符。这样在处理类似 `1-2` 的表达式时,会将 `1`、`-`、`2` 识别为三个独立的token,以正确匹配减法规则。 - -### 优先级分析 -1. ​​二元运算符​​:乘除 > 加减 -2. ​一元负号​​:高于所有二元运算符 -3. ​括号​​:通过语法层级隐式最高 \ No newline at end of file +这些表达式的定义已经在expression.h中定义,但是没有在语法解析中体现。更完善的做法是在 select 的属性列表、where 条件、insert 的 values等语句中,都使用表达式来表示。 \ No newline at end of file