The unit-string grammar (esm-spec §4.8.2)
A unit string is resolved in four steps, each a function here:
normalize— the mandatory Unicode rewrite, applied BEFORE parsing.lex— tokens. A symbol is a maximal run of identifier characters ([A-Za-z0-9_]); a run of digits alone (optionallydigits.digits) is a number;%is a one-character symbol; whitespace separates tokens and is otherwise dropped.parse— the grammar, to a syntax treeUExpr:unit := term (('*' | '/')? term)* term := atom (('^' | '**') exponent)? exponent := integer | decimal | '(' integer '/' integer ')' atom := '1' | symbol | '(' unit ')'*,/and juxtaposition are one precedence level, folded left to right. A numeric atom whose value is not 1 is a scaling factor and an error.UExpr.eval— look each symbol up in the flat table and compose.
Readings chosen where §4.8.2 admits more than one are listed in the phase-1
report (the lexing of a run such as s1, a lone % inside a run, numeric atoms
spelled 1.0, whitespace-only strings, whitespace inside a term).
Errors
def scalingFactorText : String
The two phrases §4.8.2 requires in the scaling-factor diagnostic.
Unicode normalisation
def supRun (cs : List Char) : List Char × List Char
The leading run of superscript digits, transliterated, and the rest.
def normalizeAux : Nat → List Char → List Char
The §4.8.2 rewrite table, applied left to right.
Tokens
Syntax trees and the parser
def pExp : List Tok → Except Err (ℚ × List Tok)
exponent := integer | decimal | '(' integer '/' integer ')' (signs allowed).
def pTail : Nat → UExpr → List Tok → Except Err (UExpr × List Tok)
The left fold acc (op term)*.
Evaluation and resolution
def resolveChars (cs : List Char) : Except Err U
Resolve a unit string given as characters. The empty string is the
dimensionless key "".
def resolve (s : String) : Except Err U
Resolve a unit string (§4.8.1 table + §4.8.2 grammar).