Fixed mysterious 'unknown conflict' error
This commit is contained in:
parent
a728a23adf
commit
5bf4d9707d
5
CHANGES
5
CHANGES
@ -1,5 +1,10 @@
|
||||
Version 0.4
|
||||
-----------
|
||||
04/09/2019 Minor refinement to the reporting of reduce/reduce conflicts.
|
||||
If a top grammar rule wasn't specified, SLY could fail with
|
||||
a mysterious "unknown conflict" exception. This should be
|
||||
fixed.
|
||||
|
||||
11/18/2018 Various usability fixes observed from last compilers course.
|
||||
|
||||
- Errors encountered during grammar construction are now
|
||||
|
@ -11,52 +11,65 @@ import enum
|
||||
from collections import defaultdict
|
||||
import json
|
||||
|
||||
# ------------------------------------------------------------
|
||||
# Low level encoding of values
|
||||
|
||||
def encode_unsigned(value):
|
||||
'''
|
||||
Produce an LEB128 encoded unsigned integer.
|
||||
'''
|
||||
bits = bin(value)[2:]
|
||||
if len(bits) % 7:
|
||||
bits = '0'*(7 - len(bits) % 7) + bits
|
||||
|
||||
parts = [ bits[i:i+7] for i in range(0,len(bits), 7) ]
|
||||
parts = [ parts[0], *['1'+p for p in parts[1:]] ]
|
||||
parts = [ int(p, 2) for p in parts ]
|
||||
return bytes(parts[::-1])
|
||||
|
||||
assert encode_unsigned(624485) == bytes([0xe5, 0x8e, 0x26])
|
||||
parts = []
|
||||
while value:
|
||||
parts.append((value & 0x7f) | 0x80)
|
||||
value >>= 7
|
||||
if not parts:
|
||||
parts.append(0)
|
||||
parts[-1] &= 0x7f
|
||||
return bytes(parts)
|
||||
|
||||
def encode_signed(value):
|
||||
'''
|
||||
Produce a LEB128 encoded signed integer.
|
||||
'''
|
||||
if value > 0:
|
||||
return encode_unsigned(value)
|
||||
|
||||
bits = bin(~(~0 << value.bit_length()) & value)[2:]
|
||||
bits = '1'+ '0'*(value.bit_length() - len(bits)) + bits
|
||||
if len(bits) % 7:
|
||||
bits = '1'*(7 - len(bits) % 7) + bits
|
||||
return encode_unsigned(int(bits,2))
|
||||
parts = [ ]
|
||||
if value < 0:
|
||||
# Sign extend the value up to a multiple of 7 bits
|
||||
value = (1 << (value.bit_length() + (7 - value.bit_length() % 7))) + value
|
||||
negative = True
|
||||
else:
|
||||
negative = False
|
||||
while value:
|
||||
parts.append((value & 0x7f) | 0x80)
|
||||
value >>= 7
|
||||
if not parts or (not negative and parts[-1] & 0x40):
|
||||
parts.append(0)
|
||||
parts[-1] &= 0x7f
|
||||
return bytes(parts)
|
||||
|
||||
assert encode_unsigned(624485) == bytes([0xe5, 0x8e, 0x26])
|
||||
assert encode_unsigned(127) == bytes([0x7f])
|
||||
assert encode_signed(-624485) == bytes([0x9b, 0xf1, 0x59])
|
||||
assert encode_signed(127) == bytes([0xff, 0x00])
|
||||
|
||||
def encode_float64(value):
|
||||
def encode_f64(value):
|
||||
'''
|
||||
Encode a 64-bit floating point as little endian
|
||||
'''
|
||||
return struct.pack('<d', value)
|
||||
|
||||
def encode_float32(value):
|
||||
def encode_f32(value):
|
||||
'''
|
||||
Encode a 32-bit floating point as little endian.
|
||||
'''
|
||||
return struct.pack('<f', value)
|
||||
|
||||
def encode_name(value):
|
||||
'''
|
||||
Encode a name as UTF-8
|
||||
'''
|
||||
data = value.encode('utf-8')
|
||||
return encode_vector(list(data[i:i+1] for i in range(len(data))))
|
||||
return encode_vector(data)
|
||||
|
||||
def encode_vector(items):
|
||||
'''
|
||||
Items is a list of encoded values
|
||||
Items is a list of encoded value or bytess
|
||||
'''
|
||||
if isinstance(items, bytes):
|
||||
return encode_unsigned(len(items)) + items
|
||||
@ -409,13 +422,13 @@ class F32OpBuilder(OpBuilder):
|
||||
_optable = f32
|
||||
|
||||
def const(self, value):
|
||||
self._append([self._optable.const, *encode_float32(value)])
|
||||
self._append([self._optable.const, *encode_f32(value)])
|
||||
|
||||
class F64OpBuilder(OpBuilder):
|
||||
_optable = f64
|
||||
|
||||
def const(self, value):
|
||||
self._append([self._optable.const, *encode_float64(value)])
|
||||
self._append([self._optable.const, *encode_f64(value)])
|
||||
|
||||
def _flatten(instr):
|
||||
for x in instr:
|
||||
|
@ -1414,7 +1414,7 @@ class LRTable(object):
|
||||
if not rlevel:
|
||||
descrip.append(f' ! shift/reduce conflict for {a} resolved as shift')
|
||||
self.sr_conflicts.append((st, a, 'shift'))
|
||||
elif r < 0:
|
||||
elif r <= 0:
|
||||
# Reduce/reduce conflict. In this case, we favor the rule
|
||||
# that was defined first in the grammar file
|
||||
oldp = Productions[-r]
|
||||
@ -1451,7 +1451,7 @@ class LRTable(object):
|
||||
if r > 0:
|
||||
if r != j:
|
||||
raise LALRError(f'Shift/shift conflict in state {st}')
|
||||
elif r < 0:
|
||||
elif r <= 0:
|
||||
# Do a precedence check.
|
||||
# - if precedence of reduce rule is higher, we reduce.
|
||||
# - if precedence of reduce is same and left assoc, we reduce.
|
||||
|
Loading…
Reference in New Issue
Block a user