Skip to content

Commit f9a4cfa

Browse files
committed
operator precedence is now strictly as per c++ reference
It had a few fallout and some good side effect as well. Fallout have been handled too.
1 parent 0f91d00 commit f9a4cfa

40 files changed

+639
-260
lines changed

.vscode/launch.json

+21
Original file line numberDiff line numberDiff line change
@@ -31,5 +31,26 @@
3131
"ignoreFailures": true
3232
}
3333
]
34+
},
35+
{
36+
"name": "Run unit test",
37+
"type": "cppdbg",
38+
"request": "launch",
39+
"program": "${workspaceFolder}/build/cppparserunittest",
40+
"args": [
41+
"vardecl-or-expr-ambiguity"
42+
],
43+
"stopAtEntry": false,
44+
"cwd": "${workspaceFolder}/build/",
45+
"preLaunchTask": "BuildAll",
46+
"externalConsole": false,
47+
"MIMode": "gdb",
48+
"setupCommands": [
49+
{
50+
"description": "Enable pretty-printing for gdb",
51+
"text": "-enable-pretty-printing",
52+
"ignoreFailures": true
53+
}
54+
]
3455
}
3556
]

CMakeLists.txt

+4-2
Original file line numberDiff line numberDiff line change
@@ -121,12 +121,14 @@ add_test(
121121
## Unit Test
122122

123123
set(TEST_SNIPPET_EMBEDDED_TESTS
124-
${CMAKE_CURRENT_LIST_DIR}/test/unit/disabled-code-test.cpp
125-
${CMAKE_CURRENT_LIST_DIR}/test/unit/expr-tests.cpp
126124
${CMAKE_CURRENT_LIST_DIR}/test/unit/attribute-specifier-sequence.cpp
125+
${CMAKE_CURRENT_LIST_DIR}/test/unit/disabled-code-test.cpp
127126
${CMAKE_CURRENT_LIST_DIR}/test/unit/error-handler-test.cpp
127+
${CMAKE_CURRENT_LIST_DIR}/test/unit/expr-test.cpp
128128
${CMAKE_CURRENT_LIST_DIR}/test/unit/namespace-test.cpp
129+
${CMAKE_CURRENT_LIST_DIR}/test/unit/template-test.cpp
129130
${CMAKE_CURRENT_LIST_DIR}/test/unit/uniform-init-test.cpp
131+
${CMAKE_CURRENT_LIST_DIR}/test/unit/vardecl-test.cpp
130132
)
131133

132134
add_executable(cppparserunittest

pub/cppast.h

+6-4
Original file line numberDiff line numberDiff line change
@@ -373,7 +373,7 @@ struct CppVarDecl
373373
{
374374
}
375375

376-
CppVarDecl(std::string name, CppExpr* assign);
376+
CppVarDecl(std::string name, CppExpr* assign, AssignType assignType = AssignType::kNone);
377377

378378
const std::string& name() const
379379
{
@@ -607,7 +607,8 @@ struct CppTypedefName : public CppObj
607607

608608
using CppTypedefNameEPtr = CppEasyPtr<CppTypedefName>;
609609

610-
using CppVarListPtr = std::unique_ptr<CppVarList>;
610+
using CppVarListPtr = std::unique_ptr<CppVarList>;
611+
using CppVarListEPtr = CppEasyPtr<CppVarList>;
611612

612613
struct CppTypedefList : public CppObj
613614
{
@@ -1765,10 +1766,11 @@ struct CppLabel : public CppObj
17651766

17661767
using CppLabelEPtr = CppEasyPtr<CppLabel>;
17671768

1768-
inline CppVarDecl::CppVarDecl(std::string name, CppExpr* assign)
1769+
inline CppVarDecl::CppVarDecl(std::string name, CppExpr* assign, AssignType assignType)
17691770
: name_(std::move(name))
1771+
, assignValue_(assign)
1772+
, assignType_(assignType)
17701773
{
1771-
assignValue_.reset(assign);
17721774
}
17731775

17741776
inline CppVarType::CppVarType(std::string baseType, CppTypeModifier modifier)

src/parser.l

+20
Original file line numberDiff line numberDiff line change
@@ -1421,6 +1421,13 @@ This context starts after #if, #elif, and #pragma to capture everyting till a ne
14211421
RETURN(tknOperator);
14221422
}
14231423

1424+
<ctxGeneral>operator{WSNL}*/">>" {
1425+
LOG();
1426+
setupToken();
1427+
g.mExpectedRShiftOperator = yytext + yyleng;
1428+
RETURN(tknOperator);
1429+
}
1430+
14241431
<ctxGeneral>void/{TS} {
14251432
LOG();
14261433
setupToken();
@@ -1493,6 +1500,19 @@ This context starts after #if, #elif, and #pragma to capture everyting till a ne
14931500
RETURN(tknLShiftEq);
14941501
}
14951502

1503+
<ctxGeneral>">>" {
1504+
LOG();
1505+
if (g.mExpectedRShiftOperator == yytext) {
1506+
g.mExpectedRShiftOperator = nullptr;
1507+
setupToken();
1508+
RETURN(tknRShift);
1509+
} else {
1510+
yyless(1);
1511+
setupToken();
1512+
RETURN(tknGT);
1513+
}
1514+
}
1515+
14961516
<ctxGeneral>">>=" {
14971517
LOG();
14981518
setupToken();

src/parser.l.h

+2
Original file line numberDiff line numberDiff line change
@@ -104,6 +104,8 @@ struct LexerData
104104
const char* mPossibleFuncImplStartBracePosition = nullptr;
105105
//@}
106106

107+
const char* mExpectedRShiftOperator = nullptr;
108+
107109
/**
108110
* Comments can appear anywhere in a C/C++ program and unfortunately not all coments can be preserved.
109111
*

src/parser.tab.h

+56-56
Original file line numberDiff line numberDiff line change
@@ -58,62 +58,62 @@
5858
#define tknAndEq 311
5959
#define tknOrEq 312
6060
#define tknLShift 313
61-
#define tknLShiftEq 314
62-
#define tknRShiftEq 315
63-
#define tknCmpEq 316
64-
#define tknNotEq 317
65-
#define tknLessEq 318
66-
#define tknGreaterEq 319
67-
#define tkn3WayCmp 320
68-
#define tknAnd 321
69-
#define tknOr 322
70-
#define tknInc 323
71-
#define tknDec 324
72-
#define tknArrow 325
73-
#define tknArrowStar 326
74-
#define tknLT 327
75-
#define tknGT 328
76-
#define tknNew 329
77-
#define tknDelete 330
78-
#define tknConst 331
79-
#define tknConstExpr 332
80-
#define tknVoid 333
81-
#define tknOverride 334
82-
#define tknFinal 335
83-
#define tknAsm 336
84-
#define tknBlob 337
85-
#define tknGoto 338
86-
#define tknStatic 339
87-
#define tknExtern 340
88-
#define tknVirtual 341
89-
#define tknInline 342
90-
#define tknExplicit 343
91-
#define tknFriend 344
92-
#define tknVolatile 345
93-
#define tknMutable 346
94-
#define tknNoExcept 347
95-
#define tknPreProHash 348
96-
#define tknDefine 349
97-
#define tknUndef 350
98-
#define tknInclude 351
99-
#define tknImport 352
100-
#define tknIf 353
101-
#define tknIfDef 354
102-
#define tknIfNDef 355
103-
#define tknElse 356
104-
#define tknElIf 357
105-
#define tknEndIf 358
106-
#define tknFor 359
107-
#define tknWhile 360
108-
#define tknDo 361
109-
#define tknSwitch 362
110-
#define tknCase 363
111-
#define tknDefault 364
112-
#define tknReturn 365
113-
#define tknBlankLine 366
114-
#define COMMA 367
115-
#define TERNARYCOND 368
116-
#define GTPREC 369
61+
#define tknRShift 314
62+
#define tknLShiftEq 315
63+
#define tknRShiftEq 316
64+
#define tknCmpEq 317
65+
#define tknNotEq 318
66+
#define tknLessEq 319
67+
#define tknGreaterEq 320
68+
#define tkn3WayCmp 321
69+
#define tknAnd 322
70+
#define tknOr 323
71+
#define tknInc 324
72+
#define tknDec 325
73+
#define tknArrow 326
74+
#define tknArrowStar 327
75+
#define tknLT 328
76+
#define tknGT 329
77+
#define tknNew 330
78+
#define tknDelete 331
79+
#define tknConst 332
80+
#define tknConstExpr 333
81+
#define tknVoid 334
82+
#define tknOverride 335
83+
#define tknFinal 336
84+
#define tknAsm 337
85+
#define tknBlob 338
86+
#define tknGoto 339
87+
#define tknStatic 340
88+
#define tknExtern 341
89+
#define tknVirtual 342
90+
#define tknInline 343
91+
#define tknExplicit 344
92+
#define tknFriend 345
93+
#define tknVolatile 346
94+
#define tknMutable 347
95+
#define tknNoExcept 348
96+
#define tknPreProHash 349
97+
#define tknDefine 350
98+
#define tknUndef 351
99+
#define tknInclude 352
100+
#define tknImport 353
101+
#define tknIf 354
102+
#define tknIfDef 355
103+
#define tknIfNDef 356
104+
#define tknElse 357
105+
#define tknElIf 358
106+
#define tknEndIf 359
107+
#define tknFor 360
108+
#define tknWhile 361
109+
#define tknDo 362
110+
#define tknSwitch 363
111+
#define tknCase 364
112+
#define tknDefault 365
113+
#define tknReturn 366
114+
#define tknBlankLine 367
115+
#define COMMA 368
116+
#define TERNARYCOND 369
117117
#define RSHIFT 370
118118
#define PREINCR 371
119119
#define PREDECR 372

src/parser.y

+24-19
Original file line numberDiff line numberDiff line change
@@ -257,7 +257,7 @@ extern int yylex();
257257
%token <str> tknConstCast tknStaticCast tknDynamicCast tknReinterpretCast
258258
%token <str> tknTry tknCatch tknThrow tknSizeOf
259259
%token <str> tknOperator tknPlusEq tknMinusEq tknMulEq tknDivEq tknPerEq tknXorEq tknAndEq tknOrEq
260-
%token <str> tknLShift /*tknRShift*/ tknLShiftEq tknRShiftEq tknCmpEq tknNotEq tknLessEq tknGreaterEq
260+
%token <str> tknLShift tknRShift tknLShiftEq tknRShiftEq tknCmpEq tknNotEq tknLessEq tknGreaterEq
261261
%token <str> tkn3WayCmp tknAnd tknOr tknInc tknDec tknArrow tknArrowStar
262262
%token <str> tknLT tknGT // We will need the position of these operators in stream when used for declaring template instance.
263263
%token <str> '+' '-' '*' '/' '%' '^' '&' '|' '~' '!' '=' ',' '(' ')' '[' ']' ';'
@@ -365,9 +365,9 @@ extern int yylex();
365365
%left '&'
366366
%left tknCmpEq tknNotEq // ==, !=
367367
// tknLT and tknGT are used instead of '<', and '>' because otherwise parsing template and template args is very difficult.
368-
%left tknLT /*tknGT*/ tknLessEq tknGreaterEq GTPREC
368+
%left tknLT tknGT tknLessEq tknGreaterEq
369369
%left tkn3WayCmp // <=>
370-
%left tknLShift RSHIFT
370+
%left tknLShift tknRShift RSHIFT
371371

372372
%left '+' '-'
373373
%left '*' '/' '%'
@@ -713,10 +713,18 @@ typeidentifier : identifier [ZZLOG;] { $$ = $1; }
713713
| tknDecltype '(' expr ')' [ZZLOG;] { $$ = mergeCppToken($1, $4); delete $3; }
714714
;
715715

716-
templidentifier : identifier tknLT templatearglist tknGT [ZZLOG; $$ = mergeCppToken($1, $4); ] {}
716+
templidentifier : identifier tknLT templatearglist tknGT [ZZLOG; $$ = mergeCppToken($1, $4); ] {}
717+
// The following rule is needed to parse an ambiguous input as template identifier,
718+
// see the test "vardecl-or-expr-ambiguity".
719+
| identifier tknLT expr tknNotEq expr tknGT [ZZLOG; $$ = mergeCppToken($1, $6); ] {}
720+
// The following rule is needed to parse a template identifier which otherwise fails to parse
721+
// because of higher precedence of tknLT and tknGT,
722+
// see the test "C<Class, v != 0> x;".
723+
| identifier tknLT templatearglist ',' expr tknNotEq expr tknGT
724+
[ZZLOG; $$ = mergeCppToken($1, $8); ] {}
717725
;
718726

719-
templqualifiedid : tknTemplate templidentifier [ZZLOG; $$ = mergeCppToken($1, $2); ] {}
727+
templqualifiedid : tknTemplate templidentifier [ZZLOG; $$ = mergeCppToken($1, $2); ] {}
720728
;
721729

722730
name : tknName [ZZLOG; $$ = $1;] {}
@@ -856,13 +864,11 @@ vardeclstmt : vardecl ';' [ZZVALID;] { $$ = $1; }
856864

857865
vardecllist : optfunctype varinit ',' opttypemodifier name optvarassign [ZZLOG;] {
858866
$2->addAttr($1);
859-
$$ = new CppVarList($2, CppVarDeclInList($4, CppVarDecl{$5}));
860-
/* TODO: Use optvarassign as well */
867+
$$ = new CppVarList($2, CppVarDeclInList($4, CppVarDecl{$5, $6.assignValue_, $6.assignType_}));
861868
}
862869
| optfunctype vardecl ',' opttypemodifier name optvarassign [ZZLOG;] {
863870
$2->addAttr($1);
864-
$$ = new CppVarList($2, CppVarDeclInList($4, CppVarDecl{$5}));
865-
/* TODO: Use optvarassign as well */
871+
$$ = new CppVarList($2, CppVarDeclInList($4, CppVarDecl{$5, $6.assignValue_, $6.assignType_}));
866872
}
867873
| optfunctype vardecl ',' opttypemodifier name '[' expr ']' [ZZLOG;] {
868874
$2->addAttr($1);
@@ -878,8 +884,7 @@ vardecllist : optfunctype varinit ',' opttypemodifier name optvarassign [Z
878884
}
879885
| vardecllist ',' opttypemodifier name optvarassign [ZZLOG;] {
880886
$$ = $1;
881-
$$->addVarDecl(CppVarDeclInList($3, CppVarDecl{$4}));
882-
/* TODO: Use optvarassign as well */
887+
$$->addVarDecl(CppVarDeclInList($3, CppVarDecl{$4, $5.assignValue_, $5.assignType_}));
883888
}
884889
| vardecllist ',' opttypemodifier name optvarassign ':' expr [ZZLOG;] {
885890
$$ = $1;
@@ -1266,7 +1271,7 @@ operfuncname : tknOperator '+' [ZZLOG;] { $$ = mergeCppToken(
12661271
| tknOperator tknAndEq [ZZLOG;] { $$ = mergeCppToken($1, $2); }
12671272
| tknOperator tknOrEq [ZZLOG;] { $$ = mergeCppToken($1, $2); }
12681273
| tknOperator tknLShift [ZZLOG;] { $$ = mergeCppToken($1, $2); }
1269-
| tknOperator rshift [ZZLOG;] { $$ = mergeCppToken($1, $2); }
1274+
| tknOperator tknRShift [ZZLOG;] { $$ = mergeCppToken($1, $2); }
12701275
| tknOperator tknLShiftEq [ZZLOG;] { $$ = mergeCppToken($1, $2); }
12711276
| tknOperator tknRShiftEq [ZZLOG;] { $$ = mergeCppToken($1, $2); }
12721277
| tknOperator tknCmpEq [ZZLOG;] { $$ = mergeCppToken($1, $2); }
@@ -1343,10 +1348,10 @@ param : varinit [ZZLOG;] { $$ = $1; $1->addAt
13431348
templatearg : [ZZLOG; $$ = nullptr;] { /*$$ = makeCppToken(nullptr, nullptr);*/ }
13441349
| vartype [ZZLOG; $$ = nullptr;] { /*$$ = mergeCppToken($1, $2);*/ }
13451350
| funcobjstr [ZZLOG; $$ = nullptr;] { /*$$ = $1;*/ }
1346-
| expr [ZZLOG; $$ = nullptr; ] {}
1351+
| expr [ZZLOG; $$ = nullptr;] {}
13471352
;
13481353

1349-
templatearglist : templatearg [ZZLOG; $$ = $1; ] {}
1354+
templatearglist : templatearg [ZZLOG; $$ = $1; ] {}
13501355
| templatearglist ',' templatearg [ZZLOG; $$ = $1;] { /*$$ = mergeCppToken($1, $3);*/ }
13511356
| templatearglist ',' doccomment templatearg [ZZLOG; $$ = $1;] { /*$$ = mergeCppToken($1, $3);*/ }
13521357
;
@@ -1756,14 +1761,14 @@ templateparam : tknTypename optname [ZZLOG;] {
17561761
| vartype name [ZZLOG;] {
17571762
$$ = new CppTemplateParam($1, $2);
17581763
}
1759-
| vartype name '=' expr [ZZLOG;] {
1764+
| vartype name '=' expr %prec TEMPLATE [ZZLOG;] {
17601765
$$ = new CppTemplateParam($1, $2);
17611766
$$->defaultArg($4);
17621767
}
17631768
| functionpointer [ZZLOG;] {
17641769
$$ = new CppTemplateParam($1, std::string());
17651770
}
1766-
| functionpointer '=' expr [ZZLOG;] {
1771+
| functionpointer '=' expr %prec TEMPLATE [ZZLOG;] {
17671772
$$ = new CppTemplateParam($1, std::string());
17681773
$$->defaultArg($3);
17691774
}
@@ -1884,7 +1889,7 @@ expr : strlit [ZZLOG
18841889
| expr '^' expr [ZZLOG;] { $$ = new CppExpr($1, kXor, $3); }
18851890
| expr '=' expr [ZZLOG;] { $$ = new CppExpr($1, kEqual, $3); }
18861891
| expr tknLT expr [ZZLOG;] { $$ = new CppExpr($1, kLess, $3); }
1887-
| expr tknGT expr %prec GTPREC [ZZLOG;] { $$ = new CppExpr($1, kGreater, $3); }
1892+
| expr tknGT expr [ZZLOG;] { $$ = new CppExpr($1, kGreater, $3); }
18881893
| expr '?' expr ':' expr %prec TERNARYCOND [ZZLOG;] { $$ = new CppExpr($1, $3, $5); }
18891894
| expr tknPlusEq expr [ZZLOG;] { $$ = new CppExpr($1, kPlusEqual, $3); }
18901895
| expr tknMinusEq expr [ZZLOG;] { $$ = new CppExpr($1, kMinusEqual, $3); }
@@ -2079,8 +2084,8 @@ void yyerror_detailed ( char* text,
20792084

20802085
enum {
20812086
kNoLog = 0x000,
2082-
kParseLog = 0x001,
2083-
kLexLog = 0x002,
2087+
kLexLog = 0x001,
2088+
kParseLog = 0x002,
20842089
kYaccLog = 0x004
20852090
};
20862091

0 commit comments

Comments
 (0)