mirror of
https://github.com/irmen/prog8.git
synced 2024-11-29 17:50:35 +00:00
remove excessive warnings in preprocess
This commit is contained in:
parent
a228bcd8fc
commit
cfb21d7f4f
@ -6,6 +6,7 @@ Written by Irmen de Jong (irmen@razorvine.net)
|
|||||||
License: GNU GPL 3.0, see LICENSE
|
License: GNU GPL 3.0, see LICENSE
|
||||||
"""
|
"""
|
||||||
|
|
||||||
|
import math
|
||||||
import re
|
import re
|
||||||
import os
|
import os
|
||||||
import shutil
|
import shutil
|
||||||
@ -14,8 +15,8 @@ from typing import Set, List, Tuple, Optional, Any, Dict, Union
|
|||||||
from .astparse import ParseError, parse_expr_as_int, parse_expr_as_number, parse_expr_as_primitive,\
|
from .astparse import ParseError, parse_expr_as_int, parse_expr_as_number, parse_expr_as_primitive,\
|
||||||
parse_expr_as_string
|
parse_expr_as_string
|
||||||
from .symbols import SourceRef, SymbolTable, DataType, SymbolDefinition, SubroutineDef, LabelDef, \
|
from .symbols import SourceRef, SymbolTable, DataType, SymbolDefinition, SubroutineDef, LabelDef, \
|
||||||
zeropage, check_value_in_range, coerce_value, char_to_bytevalue, \
|
zeropage, check_value_in_range, char_to_bytevalue, \
|
||||||
VariableDef, ConstantDef, SymbolError, STRING_DATATYPES, \
|
PrimitiveType, VariableDef, ConstantDef, SymbolError, STRING_DATATYPES, \
|
||||||
REGISTER_SYMBOLS, REGISTER_WORDS, REGISTER_BYTES, RESERVED_NAMES
|
REGISTER_SYMBOLS, REGISTER_WORDS, REGISTER_BYTES, RESERVED_NAMES
|
||||||
|
|
||||||
|
|
||||||
@ -343,7 +344,8 @@ class ParseResult:
|
|||||||
else:
|
else:
|
||||||
cur_block = parser.cur_block
|
cur_block = parser.cur_block
|
||||||
stringvar_name = "il65_str_{:d}".format(id(self))
|
stringvar_name = "il65_str_{:d}".format(id(self))
|
||||||
cur_block.symbols.define_variable(stringvar_name, cur_block.sourceref, DataType.STRING, value=self.right.value)
|
value = self.right.value
|
||||||
|
cur_block.symbols.define_variable(stringvar_name, cur_block.sourceref, DataType.STRING, value=value)
|
||||||
self.right.name = stringvar_name
|
self.right.name = stringvar_name
|
||||||
self._immediate_string_vars[self.right.value] = (cur_block.name, stringvar_name)
|
self._immediate_string_vars[self.right.value] = (cur_block.name, stringvar_name)
|
||||||
|
|
||||||
@ -467,6 +469,7 @@ class Parser:
|
|||||||
self.cur_block = None # type: ParseResult.Block
|
self.cur_block = None # type: ParseResult.Block
|
||||||
self.root_scope = SymbolTable("<root>", None, None)
|
self.root_scope = SymbolTable("<root>", None, None)
|
||||||
self.ppsymbols = ppsymbols # symboltable from preprocess phase # @todo use this
|
self.ppsymbols = ppsymbols # symboltable from preprocess phase # @todo use this
|
||||||
|
self.print_block_parsing = True
|
||||||
|
|
||||||
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:
|
||||||
@ -506,6 +509,9 @@ class Parser:
|
|||||||
self._parse_2()
|
self._parse_2()
|
||||||
return self.result
|
return self.result
|
||||||
|
|
||||||
|
def print_warning(self, text: str) -> None:
|
||||||
|
print(text)
|
||||||
|
|
||||||
def _parse_1(self) -> None:
|
def _parse_1(self) -> None:
|
||||||
self.parse_header()
|
self.parse_header()
|
||||||
zeropage.configure(self.result.clobberzp)
|
zeropage.configure(self.result.clobberzp)
|
||||||
@ -531,7 +537,7 @@ class Parser:
|
|||||||
self.sourceref.column = 0
|
self.sourceref.column = 0
|
||||||
raise self.PError("The 'main' block should contain the program entry point 'start'")
|
raise self.PError("The 'main' block should contain the program entry point 'start'")
|
||||||
if not any(s for s in block.statements if isinstance(s, ParseResult.ReturnStmt)):
|
if not any(s for s in block.statements if isinstance(s, ParseResult.ReturnStmt)):
|
||||||
print("warning: {}: The 'main' block is lacking a return statement.".format(block.sourceref))
|
self.print_warning("warning: {}: The 'main' block is lacking a return statement.".format(block.sourceref))
|
||||||
break
|
break
|
||||||
else:
|
else:
|
||||||
raise self.PError("A block named 'main' should be defined for the program's entry point 'start'")
|
raise self.PError("A block named 'main' should be defined for the program's entry point 'start'")
|
||||||
@ -748,10 +754,11 @@ class Parser:
|
|||||||
raise self.PError("expected '{' after block")
|
raise self.PError("expected '{' after block")
|
||||||
else:
|
else:
|
||||||
self.next_line()
|
self.next_line()
|
||||||
if self.cur_block.address:
|
if self.print_block_parsing:
|
||||||
print(" parsing block '{:s}' at ${:04x}".format(self.cur_block.name, self.cur_block.address))
|
if self.cur_block.address:
|
||||||
else:
|
print(" parsing block '{:s}' at ${:04x}".format(self.cur_block.name, self.cur_block.address))
|
||||||
print(" parsing block '{:s}'".format(self.cur_block.name))
|
else:
|
||||||
|
print(" parsing block '{:s}'".format(self.cur_block.name))
|
||||||
while True:
|
while True:
|
||||||
line = self.next_line()
|
line = self.next_line()
|
||||||
unstripped_line = line
|
unstripped_line = line
|
||||||
@ -760,7 +767,7 @@ class Parser:
|
|||||||
if is_zp_block and any(b.name == "ZP" for b in self.result.blocks):
|
if is_zp_block and any(b.name == "ZP" for b in self.result.blocks):
|
||||||
return None # we already have the ZP block
|
return None # we already have the ZP block
|
||||||
if not self.cur_block.name and not self.cur_block.address:
|
if not self.cur_block.name and not self.cur_block.address:
|
||||||
print("warning: {}: Ignoring block without name and address.".format(self.cur_block.sourceref))
|
self.print_warning("warning: {}: Ignoring block without name and address.".format(self.cur_block.sourceref))
|
||||||
return None
|
return None
|
||||||
return self.cur_block
|
return self.cur_block
|
||||||
if line.startswith("var"):
|
if line.startswith("var"):
|
||||||
@ -827,7 +834,7 @@ class Parser:
|
|||||||
if dimensions:
|
if dimensions:
|
||||||
raise self.PError("cannot declare a constant matrix")
|
raise self.PError("cannot declare a constant matrix")
|
||||||
value = parse_expr_as_primitive(valuetext, self.cur_block.symbols, self.sourceref)
|
value = parse_expr_as_primitive(valuetext, self.cur_block.symbols, self.sourceref)
|
||||||
_, value = coerce_value(self.sourceref, datatype, value)
|
_, value = self.coerce_value(self.sourceref, datatype, value)
|
||||||
try:
|
try:
|
||||||
self.cur_block.symbols.define_constant(varname, self.sourceref, datatype, length=length, value=value)
|
self.cur_block.symbols.define_constant(varname, self.sourceref, datatype, length=length, value=value)
|
||||||
except (ValueError, SymbolError) as x:
|
except (ValueError, SymbolError) as x:
|
||||||
@ -889,7 +896,7 @@ class Parser:
|
|||||||
def parse_var_def(self, line: str) -> None:
|
def parse_var_def(self, line: str) -> None:
|
||||||
varname, datatype, length, dimensions, valuetext = self.parse_def_common(line, "var", False)
|
varname, datatype, length, dimensions, valuetext = self.parse_def_common(line, "var", False)
|
||||||
value = parse_expr_as_primitive(valuetext, self.cur_block.symbols, self.sourceref)
|
value = parse_expr_as_primitive(valuetext, self.cur_block.symbols, self.sourceref)
|
||||||
_, value = coerce_value(self.sourceref, datatype, value)
|
_, value = self.coerce_value(self.sourceref, datatype, value)
|
||||||
try:
|
try:
|
||||||
self.cur_block.symbols.define_variable(varname, self.sourceref, datatype,
|
self.cur_block.symbols.define_variable(varname, self.sourceref, datatype,
|
||||||
length=length, value=value, matrixsize=dimensions)
|
length=length, value=value, matrixsize=dimensions)
|
||||||
@ -1040,7 +1047,7 @@ class Parser:
|
|||||||
raise self.PError("cannot assign {0} to {1}; {2}".format(r_value, lv, reason))
|
raise self.PError("cannot assign {0} to {1}; {2}".format(r_value, lv, reason))
|
||||||
if lv.datatype in (DataType.BYTE, DataType.WORD, DataType.MATRIX):
|
if lv.datatype in (DataType.BYTE, DataType.WORD, DataType.MATRIX):
|
||||||
if isinstance(r_value, ParseResult.FloatValue):
|
if isinstance(r_value, ParseResult.FloatValue):
|
||||||
truncated, value = coerce_value(self.sourceref, lv.datatype, r_value.value)
|
truncated, value = self.coerce_value(self.sourceref, lv.datatype, r_value.value)
|
||||||
if truncated:
|
if truncated:
|
||||||
r_value = ParseResult.IntegerValue(int(value), datatype=lv.datatype, name=r_value.name)
|
r_value = ParseResult.IntegerValue(int(value), datatype=lv.datatype, name=r_value.name)
|
||||||
return ParseResult.AssignmentStmt(l_values, r_value, self.sourceref.line)
|
return ParseResult.AssignmentStmt(l_values, r_value, self.sourceref.line)
|
||||||
@ -1249,6 +1256,19 @@ class Parser:
|
|||||||
return (parse_expr_as_int(xs, self.cur_block.symbols, self.sourceref),
|
return (parse_expr_as_int(xs, self.cur_block.symbols, self.sourceref),
|
||||||
parse_expr_as_int(ys, self.cur_block.symbols, self.sourceref))
|
parse_expr_as_int(ys, self.cur_block.symbols, self.sourceref))
|
||||||
|
|
||||||
|
def coerce_value(self, sourceref: SourceRef, datatype: DataType, value: PrimitiveType) -> Tuple[bool, PrimitiveType]:
|
||||||
|
# if we're a BYTE type, and the value is a single character, convert it to the numeric value
|
||||||
|
if datatype in (DataType.BYTE, DataType.BYTEARRAY, DataType.MATRIX) and isinstance(value, str):
|
||||||
|
if len(value) == 1:
|
||||||
|
return True, char_to_bytevalue(value)
|
||||||
|
# if we're an integer value and the passed value is float, truncate it (and give a warning)
|
||||||
|
if datatype in (DataType.BYTE, DataType.WORD, DataType.MATRIX) and type(value) is float:
|
||||||
|
frac = math.modf(value) # type:ignore
|
||||||
|
if frac != 0:
|
||||||
|
self.print_warning("warning: {}: Float value truncated.".format(sourceref))
|
||||||
|
return True, int(value)
|
||||||
|
return False, value
|
||||||
|
|
||||||
def psplit(self, sentence: str, separators: str=" \t", lparen: str="(", rparen: str=")") -> List[str]:
|
def psplit(self, sentence: str, separators: str=" \t", lparen: str="(", rparen: str=")") -> List[str]:
|
||||||
"""split a sentence but not on separators within parenthesis"""
|
"""split a sentence but not on separators within parenthesis"""
|
||||||
nb_brackets = 0
|
nb_brackets = 0
|
||||||
|
@ -13,6 +13,7 @@ from .parse import Parser, ParseResult, SymbolTable, SymbolDefinition
|
|||||||
class PreprocessingParser(Parser):
|
class PreprocessingParser(Parser):
|
||||||
def __init__(self, filename: str) -> None:
|
def __init__(self, filename: str) -> None:
|
||||||
super().__init__(filename, "", parsing_import=True)
|
super().__init__(filename, "", parsing_import=True)
|
||||||
|
self.print_block_parsing = False
|
||||||
|
|
||||||
def preprocess(self) -> Tuple[List[Tuple[int, str]], SymbolTable]:
|
def preprocess(self) -> Tuple[List[Tuple[int, str]], SymbolTable]:
|
||||||
def cleanup_table(symbols: SymbolTable):
|
def cleanup_table(symbols: SymbolTable):
|
||||||
@ -26,6 +27,9 @@ class PreprocessingParser(Parser):
|
|||||||
cleanup_table(self.root_scope)
|
cleanup_table(self.root_scope)
|
||||||
return self.lines, self.root_scope
|
return self.lines, self.root_scope
|
||||||
|
|
||||||
|
def print_warning(self, text: str) -> None:
|
||||||
|
pass
|
||||||
|
|
||||||
def load_source(self, filename: str) -> List[Tuple[int, str]]:
|
def load_source(self, filename: str) -> List[Tuple[int, str]]:
|
||||||
lines = super().load_source(filename)
|
lines = super().load_source(filename)
|
||||||
# can do some additional source-level preprocessing here
|
# can do some additional source-level preprocessing here
|
||||||
|
@ -329,8 +329,6 @@ class SymbolTable:
|
|||||||
range_error = check_value_in_range(datatype, register, length, value)
|
range_error = check_value_in_range(datatype, register, length, value)
|
||||||
if range_error:
|
if range_error:
|
||||||
raise ValueError(range_error)
|
raise ValueError(range_error)
|
||||||
if type(value) in (int, float):
|
|
||||||
_, value = coerce_value(sourceref, datatype, value) # type: ignore
|
|
||||||
allocate = address is None
|
allocate = address is None
|
||||||
if datatype == DataType.BYTE:
|
if datatype == DataType.BYTE:
|
||||||
if allocate and self.name == "ZP":
|
if allocate and self.name == "ZP":
|
||||||
@ -389,8 +387,6 @@ class SymbolTable:
|
|||||||
# this defines a new constant and also checks if the value is allowed for the data type.
|
# this defines a new constant and also checks if the value is allowed for the data type.
|
||||||
assert value is not None
|
assert value is not None
|
||||||
self.check_identifier_valid(name, sourceref)
|
self.check_identifier_valid(name, sourceref)
|
||||||
if type(value) in (int, float):
|
|
||||||
_, value = coerce_value(sourceref, datatype, value) # type: ignore
|
|
||||||
range_error = check_value_in_range(datatype, "", length, value)
|
range_error = check_value_in_range(datatype, "", length, value)
|
||||||
if range_error:
|
if range_error:
|
||||||
raise ValueError(range_error)
|
raise ValueError(range_error)
|
||||||
@ -477,20 +473,6 @@ class Eval_symbol_dict(dict):
|
|||||||
raise SymbolError("no support for non-constant expression evaluation yet")
|
raise SymbolError("no support for non-constant expression evaluation yet")
|
||||||
|
|
||||||
|
|
||||||
def coerce_value(sourceref: SourceRef, datatype: DataType, value: PrimitiveType) -> Tuple[bool, PrimitiveType]:
|
|
||||||
# if we're a BYTE type, and the value is a single character, convert it to the numeric value
|
|
||||||
if datatype in (DataType.BYTE, DataType.BYTEARRAY, DataType.MATRIX) and isinstance(value, str):
|
|
||||||
if len(value) == 1:
|
|
||||||
return True, char_to_bytevalue(value)
|
|
||||||
# if we're an integer value and the passed value is float, truncate it (and give a warning)
|
|
||||||
if datatype in (DataType.BYTE, DataType.WORD, DataType.MATRIX) and type(value) is float:
|
|
||||||
frac = math.modf(value) # type:ignore
|
|
||||||
if frac != 0:
|
|
||||||
print("warning: {}: Float value truncated.".format(sourceref))
|
|
||||||
return True, int(value)
|
|
||||||
return False, value
|
|
||||||
|
|
||||||
|
|
||||||
def check_value_in_range(datatype: DataType, register: str, length: int, value: PrimitiveType) -> Optional[str]:
|
def check_value_in_range(datatype: DataType, register: str, length: int, value: PrimitiveType) -> Optional[str]:
|
||||||
if register:
|
if register:
|
||||||
if register in REGISTER_BYTES:
|
if register in REGISTER_BYTES:
|
||||||
|
Loading…
Reference in New Issue
Block a user