Skip to content

Commit 7e54381

Browse files
authored
Merge pull request #605 from boriel/feature/implement_and_or_in_zxbpp
feat: add AND and OR operators to zxbpp
2 parents 2a88911 + f727e3d commit 7e54381

10 files changed

Lines changed: 164 additions & 73 deletions

File tree

src/parsetab/tabs.dbm.bak

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
'zxbpp', (0, 76970)
2-
'asmparse', (77312, 270618)
3-
'zxnext_asmparse', (348160, 300642)
4-
'zxbparser', (649216, 708977)
1+
'zxbpp', (0, 67001)
2+
'asmparse', (67072, 220672)
3+
'zxnext_asmparse', (287744, 245099)
4+
'zxbparser', (532992, 641182)

src/parsetab/tabs.dbm.dat

-180 KB
Binary file not shown.

src/parsetab/tabs.dbm.dir

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
'zxbpp', (0, 76970)
2-
'asmparse', (77312, 270618)
3-
'zxnext_asmparse', (348160, 300642)
4-
'zxbparser', (649216, 708977)
1+
'zxbpp', (0, 67001)
2+
'asmparse', (67072, 220672)
3+
'zxnext_asmparse', (287744, 245099)
4+
'zxbparser', (532992, 641182)

src/zxbpp/base_pplex.py

Lines changed: 26 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@
1414
import sys
1515

1616
from dataclasses import dataclass
17+
from enum import Enum, unique
1718

1819
from typing import Iterable
1920
from typing import List
@@ -24,10 +25,10 @@
2425

2526
from src.api import utils
2627

27-
from .prepro import output
28+
from src.zxbpp.prepro import output
2829

29-
from .prepro.definestable import DefinesTable
30-
from .prepro.builtinmacro import BuiltinMacro
30+
from src.zxbpp.prepro.definestable import DefinesTable
31+
from src.zxbpp.prepro.builtinmacro import BuiltinMacro
3132

3233
EOL = "\n"
3334

@@ -37,6 +38,26 @@
3738
STDERR = "<stderr>"
3839

3940

41+
@unique
42+
class ReservedDirectives(str, Enum):
43+
INCLUDE = "INCLUDE"
44+
ONCE = "ONCE"
45+
DEFINE = "DEFINE"
46+
UNDEF = "UNDEF"
47+
IF = "IF"
48+
IFDEF = "IFDEF"
49+
IFNDEF = "IFNDEF"
50+
ELSE = "ELSE"
51+
ELIF = "ELIF"
52+
ENDIF = "ENDIF"
53+
INIT = "INIT"
54+
LINE = "LINE"
55+
REQUIRE = "REQUIRE"
56+
PRAGMA = "PRAGMA"
57+
ERROR = "ERROR"
58+
WARNING = "WARNING"
59+
60+
4061
@dataclass
4162
class LexerState:
4263
filename: str
@@ -51,6 +72,8 @@ class BaseLexer:
5172
It's the base class for the asm and basic preprocessor lexers.
5273
"""
5374

75+
reserved_directives = {x.value.lower(): x.value for x in ReservedDirectives}
76+
5477
builtin_macros = {
5578
"__ABS_FILE__": lambda token: f'"{utils.get_absolute_filename_path(token.fname)}"',
5679
"__BASE_FILE__": lambda token: f'"{os.path.basename(token.fname)}"',

src/zxbpp/zxbasmpplex.py

Lines changed: 66 additions & 37 deletions
Original file line numberDiff line numberDiff line change
@@ -16,9 +16,8 @@
1616

1717
from src.ply import lex
1818

19-
from .prepro.definestable import DefinesTable
20-
from .base_pplex import BaseLexer
21-
19+
from src.zxbpp.prepro.definestable import DefinesTable
20+
from src.zxbpp.base_pplex import BaseLexer, ReservedDirectives
2221

2322
EOL = "\n"
2423

@@ -36,11 +35,14 @@
3635
("defexpr", "exclusive"),
3736
("msg", "exclusive"),
3837
("pragma", "exclusive"),
38+
("if", "exclusive"),
3939
("singlecomment", "exclusive"),
4040
("asmcomment", "exclusive"),
4141
)
4242

4343
_tokens = (
44+
"AND",
45+
"OR",
4446
"STRING",
4547
"TEXT",
4648
"TOKEN",
@@ -60,28 +62,18 @@
6062
"CONTINUE",
6163
"NUMBER",
6264
"SEPARATOR",
65+
"GT",
66+
"GE",
67+
"LT",
68+
"LE",
69+
"NE",
6370
"PASTE",
71+
"STRINGIZING",
6472
)
6573

66-
reserved_directives = {
67-
"include": "INCLUDE",
68-
"once": "ONCE",
69-
"define": "DEFINE",
70-
"undef": "UNDEF",
71-
"ifdef": "IFDEF",
72-
"ifndef": "IFNDEF",
73-
"else": "ELSE",
74-
"endif": "ENDIF",
75-
"init": "INIT",
76-
"line": "LINE",
77-
"require": "REQUIRE",
78-
"pragma": "PRAGMA",
79-
"error": "ERROR",
80-
"warning": "WARNING",
81-
}
8274

8375
# List of token names.
84-
tokens = _tokens + tuple(reserved_directives.values())
76+
tokens = _tokens + tuple(x.value for x in ReservedDirectives)
8577

8678
__COMMENT_LEVEL = 0
8779

@@ -130,7 +122,7 @@ def t_INITIAL_TOKEN(self, t):
130122
r"[][}{%'`,.:$()*/<>~&|+^-]"
131123
return t
132124

133-
def t_line_singlecomment_asmcomment_prepro_define_defargs_defargsopt_defexpr_pragma_NEWLINE(self, t):
125+
def t_line_singlecomment_asmcomment_prepro_define_defargs_defargsopt_defexpr_pragma_if_NEWLINE(self, t):
134126
r"\r?\n"
135127
t.lexer.lineno += 1
136128
t.lexer.pop_state()
@@ -153,26 +145,50 @@ def t_singlecomment_comment_Skip(self, t):
153145
pass
154146

155147
# Allows line breaking
156-
def t_defexpr_CONTINUE(self, t):
157-
r"[\\_]\r?\n"
158-
t.lexer.lineno += 1
159-
return t
160-
161-
def t_line_prepro_pragma_defargs_define_skip(self, t):
148+
def t_line_prepro_pragma_defargs_define_skip_if(self, t):
162149
r"[ \t]+"
163150
pass # Ignore whitespaces and tabs
164151

152+
def t_if_EQ(self, t):
153+
r"=="
154+
return t
155+
156+
def t_if_NE(self, t):
157+
r"!=|<>"
158+
return t
159+
160+
def t_if_GE(self, t):
161+
r">="
162+
return t
163+
164+
def t_if_GT(self, t):
165+
r">"
166+
return t
167+
168+
def t_if_LE(self, t):
169+
r"<="
170+
return t
171+
172+
def t_if_LT(self, t):
173+
r"<"
174+
return t
175+
176+
def t_if_AND(self, t):
177+
r"&&"
178+
return t
179+
180+
def t_if_OR(self, t):
181+
r"\|\|"
182+
return t
183+
165184
def t_prepro_ID(self, t):
166185
r"[._a-zA-Z][._a-zA-Z0-9]*" # preprocessor directives
167-
t.type = reserved_directives.get(t.value.lower(), "ID")
168-
if t.type == "DEFINE":
169-
t.lexer.begin("define")
170-
elif t.type == "PRAGMA":
171-
t.lexer.begin("pragma")
172-
elif t.type == "LINE":
173-
t.lexer.begin("line")
174-
elif t.type in ("ERROR", "WARNING"):
175-
t.lexer.begin("msg")
186+
t.type = self.reserved_directives.get(t.value, "ID")
187+
states_ = {"DEFINE": "define", "ERROR": "msg", "IF": "if", "LINE": "line", "PRAGMA": "pragma", "WARNING": "msg"}
188+
189+
if t.type in states_:
190+
t.lexer.begin(states_[t.type])
191+
176192
return t
177193

178194
def t_msg_TEXT(self, t):
@@ -198,6 +214,19 @@ def t_defexpr_RRP(self, t):
198214
r"\)"
199215
return t
200216

217+
def t_defexpr_CONTINUE(self, t):
218+
r"[\\_]\r?\n"
219+
t.lexer.lineno += 1
220+
return t
221+
222+
def t_defexpr_STRINGIZING(self, t):
223+
r"\#[ \t]*"
224+
return t
225+
226+
def t_defexpr_PASTE(self, t):
227+
r"[ \t]*\#\#[ \t]*"
228+
return t
229+
201230
def t_pragma_ID(self, t):
202231
r"[_a-zA-Z][_a-zA-Z0-9]*" # pragma directives
203232
if t.value.upper() in ("PUSH", "POP"):
@@ -323,7 +352,7 @@ def t_line_defargs_defargsopt_prepro_define_defexpr_pragma_singlecomment_INITIAL
323352
r"."
324353
self.error("illegal preprocessor character '%s'" % t.value[0])
325354

326-
def t_line_msg_defargs_defargsopt_prepro_define_defexpr_pragma_singlecomment_INITIAL_asmcomment_error(self, t):
355+
def t_if_line_msg_defargs_defargsopt_prepro_define_defexpr_pragma_singlecomment_INITIAL_asmcomment_error(self, t):
327356
"""error handling rule. This should never happens!"""
328357
pass # The lexer will raise an exception here. This is intended
329358

src/zxbpp/zxbpp.py

Lines changed: 17 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -102,6 +102,7 @@ class IncludedFileInfo:
102102

103103
precedence = (
104104
("nonassoc", "DUMMY"),
105+
("left", "AND", "OR"),
105106
("left", "EQ", "NE", "LT", "LE", "GT", "GE"),
106107
("right", "LLP"),
107108
("left", "PASTE", "STRINGIZING"),
@@ -652,6 +653,16 @@ def p_expr_str(p):
652653
p[0] = p[1]
653654

654655

656+
def p_exprand(p):
657+
"""expr : expr AND expr"""
658+
p[0] = "1" if p[1] and p[3] else "0"
659+
660+
661+
def p_expror(p):
662+
"""expr : expr OR expr"""
663+
p[0] = "1" if p[1] or p[3] else "0"
664+
665+
655666
def p_exprne(p):
656667
"""expr : expr NE expr"""
657668
p[0] = "1" if p[1] != p[3] else "0"
@@ -694,6 +705,11 @@ def p_exprge(p):
694705
p[0] = "1" if a >= b else "0"
695706

696707

708+
def p_expr_par(p):
709+
"""expr : LLP expr RRP"""
710+
p[0] = p[2]
711+
712+
697713
def p_defs_list_eps(p):
698714
"""defs :"""
699715
p[0] = []
@@ -866,7 +882,7 @@ def main(argv):
866882
return global_.has_errors
867883

868884

869-
parser = yacc.yacc(debug=True)
885+
parser = utils.get_or_create("zxbpp", lambda: yacc.yacc(debug=True))
870886
parser.defaulted_states = {}
871887

872888

src/zxbpp/zxbpplex.py

Lines changed: 15 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -17,9 +17,9 @@
1717

1818
from src.ply import lex
1919
from src.api import global_
20-
from src.zxbpp.base_pplex import BaseLexer
20+
from src.zxbpp.base_pplex import BaseLexer, ReservedDirectives
2121

22-
from .prepro.definestable import DefinesTable
22+
from src.zxbpp.prepro.definestable import DefinesTable
2323

2424

2525
EOL = "\n"
@@ -46,6 +46,8 @@
4646
)
4747

4848
_tokens = (
49+
"AND",
50+
"OR",
4951
"STRING",
5052
"TEXT",
5153
"TOKEN",
@@ -74,26 +76,8 @@
7476
"STRINGIZING",
7577
)
7678

77-
reserved_directives = {
78-
"include": "INCLUDE",
79-
"once": "ONCE",
80-
"define": "DEFINE",
81-
"undef": "UNDEF",
82-
"if": "IF",
83-
"ifdef": "IFDEF",
84-
"ifndef": "IFNDEF",
85-
"else": "ELSE",
86-
"endif": "ENDIF",
87-
"init": "INIT",
88-
"line": "LINE",
89-
"require": "REQUIRE",
90-
"pragma": "PRAGMA",
91-
"error": "ERROR",
92-
"warning": "WARNING",
93-
}
94-
9579
# List of token names.
96-
tokens = sorted(_tokens + tuple(reserved_directives.values()))
80+
tokens = sorted(_tokens + tuple(x.value for x in ReservedDirectives))
9781

9882

9983
class Lexer(BaseLexer):
@@ -242,9 +226,17 @@ def t_if_LT(self, t):
242226
r"<"
243227
return t
244228

229+
def t_if_AND(self, t):
230+
r"&&"
231+
return t
232+
233+
def t_if_OR(self, t):
234+
r"\|\|"
235+
return t
236+
245237
def t_prepro_ID(self, t):
246238
r"[._a-zA-Z][._a-zA-Z0-9]*" # preprocessor directives
247-
t.type = reserved_directives.get(t.value.lower(), "ID")
239+
t.type = self.reserved_directives.get(t.value, "ID")
248240
states_ = {"DEFINE": "define", "ERROR": "msg", "IF": "if", "LINE": "line", "PRAGMA": "pragma", "WARNING": "msg"}
249241

250242
if t.type in states_:
@@ -400,7 +392,7 @@ def t_INITIAL_line_defargs_defargsopt_prepro_define_defexpr_pragma_comment_singl
400392
r"."
401393
self.error("illegal preprocessor character '%s'" % t.value[0])
402394

403-
def t_INITIAL_line_defargs_defargsopt_prepro_define_defexpr_pragma_comment_singlecomment_error(self, t):
395+
def t_INITIAL_if_line_defargs_defargsopt_prepro_define_defexpr_pragma_comment_singlecomment_error(self, t):
404396
"""error handling rule. Should never happen!"""
405397
pass # The lexer will raise an exception here. This is intended
406398

tests/functional/iflogic.bi

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
2+
#define A 1
3+
#define B 2
4+
5+
#if A == 1 || B == 1
6+
PRINT "Or works"
7+
#endif
8+
9+
#if A == 1 && B == 2
10+
PRINT "And works"
11+
#endif
12+
13+
#if (A == 1 && B == 1) || B == 2
14+
PRINT "Parenthesis works"
15+
#endif

tests/functional/iflogic.out

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
#line 1 "iflogic.bi"
2+
3+
#line 3 "iflogic.bi"
4+
#line 4 "iflogic.bi"
5+
6+
7+
PRINT "Or works"
8+
#line 8 "iflogic.bi"
9+
10+
11+
PRINT "And works"
12+
#line 12 "iflogic.bi"
13+
14+
15+
PRINT "Parenthesis works"
16+
#line 16 "iflogic.bi"

0 commit comments

Comments
 (0)