SPEC change: ^ is right-assoc and of highest priority

This commit is contained in:
Araq 2011-01-10 21:28:48 +01:00
commit 19fbc8a55e
4 changed files with 38 additions and 26 deletions

View file

@ -368,19 +368,20 @@ indentation tokens is already described in the `Lexical Analysis`_ section.
Nimrod allows user-definable operators. Nimrod allows user-definable operators.
Binary operators have 8 different levels of precedence. For user-defined Binary operators have 8 different levels of precedence. For user-defined
operators, the precedence depends on the first character the operator consists operators, the precedence depends on the first character the operator consists
of. All binary operators are left-associative. of. All binary operators are left-associative, except binary operator starting
with (or only consisting of) ``^``.
================ ============================================== ================== =============== ================ ============================================== ================== ===============
Precedence level Operators First characters Terminal symbol Precedence level Operators First characters Terminal symbol
================ ============================================== ================== =============== ================ ============================================== ================== ===============
7 (highest) ``$`` OP7 7 (highest) ``$ ^`` OP7
6 ``* / div mod shl shr %`` ``* % \ /`` OP6 6 ``* / div mod shl shr %`` ``* % \ /`` OP6
5 ``+ -`` ``+ ~ |`` OP5 5 ``+ -`` ``+ ~ |`` OP5
4 ``&`` ``&`` OP4 4 ``&`` ``&`` OP4
3 ``== <= < >= > != in not_in is isnot`` ``= < > !`` OP3 3 ``== <= < >= > != in not_in is isnot`` ``= < > !`` OP3
2 ``and`` OP2 2 ``and`` OP2
1 ``or xor`` OP1 1 ``or xor`` OP1
0 (lowest) ``? @ ^ ` : .`` OP0 0 (lowest) ``? @ ` : .`` OP0
================ ============================================== ================== =============== ================ ============================================== ================== ===============
@ -1530,6 +1531,7 @@ Example:
close(f) close(f)
The statements after the `try`:idx: are executed in sequential order unless The statements after the `try`:idx: are executed in sequential order unless
an exception ``e`` is raised. If the exception type of ``e`` matches any an exception ``e`` is raised. If the exception type of ``e`` matches any
of the list ``exceptlist`` the corresponding statements are executed. of the list ``exceptlist`` the corresponding statements are executed.

View file

@ -1,7 +1,7 @@
# #
# #
# The Nimrod Compiler # The Nimrod Compiler
# (c) Copyright 2009 Andreas Rumpf # (c) Copyright 2011 Andreas Rumpf
# #
# See the file "copying.txt", included in this # See the file "copying.txt", included in this
# distribution, for details about the copyright. # distribution, for details about the copyright.
@ -145,11 +145,14 @@ proc parseStmt(p: var TParser): PNode
proc parseTypeDesc(p: var TParser): PNode proc parseTypeDesc(p: var TParser): PNode
proc parseParamList(p: var TParser): PNode proc parseParamList(p: var TParser): PNode
proc IsLeftAssociative(tok: PToken): bool {.inline.} =
result = tok.tokType != tkOpr or tok.ident.s[0] != '^'
proc getPrecedence(tok: PToken): int = proc getPrecedence(tok: PToken): int =
case tok.tokType case tok.tokType
of tkOpr: of tkOpr:
case tok.ident.s[0] case tok.ident.s[0]
of '$': result = 7 of '$', '^': result = 7
of '*', '%', '/', '\\': result = 6 of '*', '%', '/', '\\': result = 6
of '+', '-', '~', '|': result = 5 of '+', '-', '~', '|': result = 5
of '&': result = 4 of '&': result = 4
@ -159,7 +162,7 @@ proc getPrecedence(tok: PToken): int =
of tkIn, tkNotIn, tkIs, tkIsNot: result = 3 of tkIn, tkNotIn, tkIs, tkIsNot: result = 3
of tkAnd: result = 2 of tkAnd: result = 2
of tkOr, tkXor: result = 1 of tkOr, tkXor: result = 1
else: result = - 1 else: result = - 10
proc isOperator(tok: PToken): bool = proc isOperator(tok: PToken): bool =
result = getPrecedence(tok) >= 0 result = getPrecedence(tok) >= 0
@ -386,14 +389,10 @@ proc parseAddr(p: var TParser): PNode =
proc setBaseFlags(n: PNode, base: TNumericalBase) = proc setBaseFlags(n: PNode, base: TNumericalBase) =
case base case base
of base10: of base10: nil
nil of base2: incl(n.flags, nfBase2)
of base2: of base8: incl(n.flags, nfBase8)
incl(n.flags, nfBase2) of base16: incl(n.flags, nfBase16)
of base8:
incl(n.flags, nfBase8)
of base16:
incl(n.flags, nfBase16)
proc identOrLiteral(p: var TParser): PNode = proc identOrLiteral(p: var TParser): PNode =
case p.tok.tokType case p.tok.tokType
@ -475,7 +474,7 @@ proc identOrLiteral(p: var TParser): PNode =
result = parseAddr(p) result = parseAddr(p)
else: else:
parMessage(p, errExprExpected, tokToStr(p.tok)) parMessage(p, errExprExpected, tokToStr(p.tok))
getTok(p) # we must consume a token here to prevend endless loops! getTok(p) # we must consume a token here to prevend endless loops!
result = nil result = nil
proc primary(p: var TParser): PNode = proc primary(p: var TParser): PNode =
@ -520,25 +519,23 @@ proc primary(p: var TParser): PNode =
else: break else: break
proc lowestExprAux(p: var TParser, v: var PNode, limit: int): PToken = proc lowestExprAux(p: var TParser, v: var PNode, limit: int): PToken =
var
op, nextop: PToken
opPred: int
v2, node, opNode: PNode
v = primary(p) # expand while operators have priorities higher than 'limit' v = primary(p) # expand while operators have priorities higher than 'limit'
op = p.tok var op = p.tok
opPred = getPrecedence(p.tok) var opPrec = getPrecedence(op)
while (opPred > limit): while opPrec >= limit:
node = newNodeP(nkInfix, p) var leftAssoc = ord(IsLeftAssociative(op))
opNode = newIdentNodeP(op.ident, p) # skip operator: var node = newNodeP(nkInfix, p)
var opNode = newIdentNodeP(op.ident, p) # skip operator:
getTok(p) getTok(p)
optInd(p, opNode) # read sub-expression with higher priority optInd(p, opNode) # read sub-expression with higher priority
nextop = lowestExprAux(p, v2, opPred) var v2: PNode
var nextop = lowestExprAux(p, v2, opPrec + leftAssoc)
addSon(node, opNode) addSon(node, opNode)
addSon(node, v) addSon(node, v)
addSon(node, v2) addSon(node, v2)
v = node v = node
op = nextop op = nextop
opPred = getPrecedence(nextop) opPrec = getPrecedence(nextop)
result = op # return first untreated operator result = op # return first untreated operator
proc lowestExpr(p: var TParser): PNode = proc lowestExpr(p: var TParser): PNode =

View file

@ -49,6 +49,7 @@ tnestprc.nim;10
toop1.nim;34[]o 5 toop1.nim;34[]o 5
topenarrayrepr.nim;5 - [1] topenarrayrepr.nim;5 - [1]
topenlen.nim;7 topenlen.nim;7
toprprec.nim;done
toverflw.nim;the computation overflowed toverflw.nim;the computation overflowed
toverflw2.nim;Error: unhandled exception: over- or underflow [EOverflow] toverflw2.nim;Error: unhandled exception: over- or underflow [EOverflow]
toverl2.nim;true012 toverl2.nim;true012

1 tack.nim 125
49 toop1.nim 34[]o 5
50 topenarrayrepr.nim 5 - [1]
51 topenlen.nim 7
52 toprprec.nim done
53 toverflw.nim the computation overflowed
54 toverflw2.nim Error: unhandled exception: over- or underflow [EOverflow]
55 toverl2.nim true012

View file

@ -0,0 +1,12 @@
# Test operator precedence:
assert 3+5*5-2 == 28- -26-28
proc `^-` (x, y: int): int =
# now right-associative!
result = x - y
assert 34 ^- 6 ^- 2 == 30
assert 34 - 6 - 2 == 26
echo "done"