multiple parse errors

This commit is contained in:
Irmen de Jong 2018-01-01 05:49:12 +01:00
parent 6922ea2a0b
commit 50db122525

View File

@ -93,6 +93,7 @@ class Parser:
self.ppsymbols = ppsymbols # symboltable from preprocess phase self.ppsymbols = ppsymbols # symboltable from preprocess phase
self.print_block_parsing = True self.print_block_parsing = True
self.existing_imports = existing_imports self.existing_imports = existing_imports
self.parse_errors = 0
def load_source(self, filename: str) -> List[Tuple[int, str]]: def load_source(self, filename: str) -> List[Tuple[int, str]]:
with open(filename, "rU") as source: with open(filename, "rU") as source:
@ -115,22 +116,9 @@ class Parser:
def parse(self) -> Optional[ParseResult]: def parse(self) -> Optional[ParseResult]:
# start the parsing # start the parsing
try: try:
return self.parse_file() result = self.parse_file()
except ParseError as x: except ParseError as x:
if sys.stderr.isatty(): self.handle_parse_error(x)
print("\x1b[1m", file=sys.stderr)
print("", file=sys.stderr)
if x.sourcetext:
print("\tsource text: '{:s}'".format(x.sourcetext), file=sys.stderr)
if x.sourceref.column:
print("\t" + ' '*x.sourceref.column + ' ^', file=sys.stderr)
if self.parsing_import:
print("Error (in imported file):", str(x), file=sys.stderr)
else:
print("Error:", str(x), file=sys.stderr)
if sys.stderr.isatty():
print("\x1b[0m", file=sys.stderr)
raise # XXX temporary solution to get stack trace info in the event of parse errors
except Exception as x: except Exception as x:
if sys.stderr.isatty(): if sys.stderr.isatty():
print("\x1b[1m", file=sys.stderr) print("\x1b[1m", file=sys.stderr)
@ -140,8 +128,27 @@ class Parser:
else: else:
print(" file:", self.sourceref.file, file=sys.stderr) print(" file:", self.sourceref.file, file=sys.stderr)
if sys.stderr.isatty(): if sys.stderr.isatty():
print("\x1b[0m", file=sys.stderr) print("\x1b[0m", file=sys.stderr, end="", flush=True)
raise # XXX temporary solution to get stack trace info in the event of parse errors raise
if self.parse_errors:
self.print_bold("\nNo output; there were {:d} errors in file {:s}\n".format(self.parse_errors, self.sourceref.file))
raise SystemExit(1)
return result
def handle_parse_error(self, exc: ParseError) -> None:
self.parse_errors += 1
if sys.stderr.isatty():
print("\x1b[1m", file=sys.stderr)
if exc.sourcetext:
print("\t" + exc.sourcetext, file=sys.stderr)
if exc.sourceref.column:
print("\t" + ' ' * exc.sourceref.column + ' ^', file=sys.stderr)
if self.parsing_import:
print("Error (in imported file):", str(exc), file=sys.stderr)
else:
print("Error:", str(exc), file=sys.stderr)
if sys.stderr.isatty():
print("\x1b[0m", file=sys.stderr, end="", flush=True)
def parse_file(self) -> ParseResult: def parse_file(self) -> ParseResult:
print("\nparsing", self.sourceref.file) print("\nparsing", self.sourceref.file)
@ -155,7 +162,7 @@ class Parser:
def print_bold(self, text: str) -> None: def print_bold(self, text: str) -> None:
if sys.stdout.isatty(): if sys.stdout.isatty():
print("\x1b[1m" + text + "\x1b[0m") print("\x1b[1m" + text + "\x1b[0m", flush=True)
else: else:
print(text) print(text)
@ -584,49 +591,59 @@ class Parser:
else: else:
raise self.PError("invalid statement in block") raise self.PError("invalid statement in block")
while True: while True:
self._parse_comments() try:
line = self.next_line() go_on, resultblock = self._parse_block_statement(is_zp_block)
unstripped_line = line if not go_on:
line = line.strip() return resultblock
if line == "}": except ParseError as x:
if is_zp_block and any(b.name == "ZP" for b in self.result.blocks): self.handle_parse_error(x)
return None # we already have the ZP block
if self.cur_block.ignore: def _parse_block_statement(self, is_zp_block: bool) -> Tuple[bool, Optional[Block]]:
self.print_warning("ignoring block without name and address", self.cur_block.sourceref) # parse the statements inside a block
return None self._parse_comments()
return self.cur_block line = self.next_line()
if line.startswith(("var ", "var\t")): unstripped_line = line
self.parse_var_def(line) line = line.strip()
elif line.startswith(("const ", "const\t")): if line == "}":
self.parse_const_def(line) if is_zp_block and any(b.name == "ZP" for b in self.result.blocks):
elif line.startswith(("memory ", "memory\t")): return False, None # we already have the ZP block
self.parse_memory_def(line, is_zp_block) if self.cur_block.ignore:
elif line.startswith(("sub ", "sub\t")): self.print_warning("ignoring block without name and address", self.cur_block.sourceref)
if is_zp_block: return False, None
raise self.PError("ZP block cannot contain subroutines") return False, self.cur_block
self.parse_subroutine_def(line) if line.startswith(("var ", "var\t")):
elif line.startswith(("asminclude ", "asminclude\t", "asmbinary ", "asmbinary\t")): self.parse_var_def(line)
if is_zp_block: elif line.startswith(("const ", "const\t")):
raise self.PError("ZP block cannot contain assembler directives") self.parse_const_def(line)
self.cur_block.statements.append(self.parse_asminclude(line)) elif line.startswith(("memory ", "memory\t")):
elif line.startswith(("asm ", "asm\t")): self.parse_memory_def(line, is_zp_block)
if is_zp_block: elif line.startswith(("sub ", "sub\t")):
raise self.PError("ZP block cannot contain code statements") if is_zp_block:
self.prev_line() raise self.PError("ZP block cannot contain subroutines")
self.cur_block.statements.append(self.parse_asm()) self.parse_subroutine_def(line)
elif line == "breakpoint": elif line.startswith(("asminclude ", "asminclude\t", "asmbinary ", "asmbinary\t")):
self.cur_block.statements.append(BreakpointStmt(self.sourceref)) if is_zp_block:
self.print_warning("breakpoint defined") raise self.PError("ZP block cannot contain assembler directives")
elif unstripped_line.startswith((" ", "\t")): self.cur_block.statements.append(self.parse_asminclude(line))
if is_zp_block: elif line.startswith(("asm ", "asm\t")):
raise self.PError("ZP block cannot contain code statements") if is_zp_block:
self.cur_block.statements.append(self.parse_statement(line)) raise self.PError("ZP block cannot contain code statements")
elif line: self.prev_line()
if is_zp_block: self.cur_block.statements.append(self.parse_asm())
raise self.PError("ZP block cannot contain code labels") elif line == "breakpoint":
self.parse_label(line) self.cur_block.statements.append(BreakpointStmt(self.sourceref))
else: self.print_warning("breakpoint defined")
raise self.PError("invalid statement in block") elif unstripped_line.startswith((" ", "\t")):
if is_zp_block:
raise self.PError("ZP block cannot contain code statements")
self.cur_block.statements.append(self.parse_statement(line))
elif line:
if is_zp_block:
raise self.PError("ZP block cannot contain code labels")
self.parse_label(line)
else:
raise self.PError("invalid statement in block")
return True, None # continue with more statements
def parse_label(self, line: str) -> None: def parse_label(self, line: str) -> None:
label_line = line.split(maxsplit=1) label_line = line.split(maxsplit=1)