Core C++

1.1. Lexer🔗

Definition1.1.1
Group: Syntax, tokens and the parser. (13)
Group member previews
Preview
Definition 1.1.2
Loading preview
Group member preview content is loaded from the rendered-fragment cache.
uses 0
Used by 2
Reverse dependency previews
Preview
Definition 1.1.2
Loading preview
Reverse dependency preview content is loaded from the rendered-fragment cache.
✓L∃∀N

Tokens fall in six classes, and the end token eof closes the array.

  • Reserved words, the 24 words int, bool, void, if, else, while, for, return, true, false, auto, delete, new, nullptr, this, class, public, private, virtual, override, namespace, template, typename and operator.

  • Type identifiers, TypeId, with an uppercase initial.

  • Variable identifiers, VarId, with a lowercase initial or _, naming variables, fields, functions and methods.

  • Namespace identifiers, NsId, the identifiers of either case that :: follows.

  • Decimal integer literals, IntLit.

  • Operators and punctuation, with [=] as a single token by the longest match rule.

There is no token >>, so Stack<Stack<int>> closes with two tokens >.

\begin{array}{lcl} \textit{Token} & ::= & \textit{Keyword}\ \mid\ \textit{TypeId}\ \mid\ \textit{VarId}\ \mid\ \textit{NsId}\ \mid\ \textit{IntLit}\ \mid\ \textit{Symbol} \\ \textit{Keyword} & ::= & \texttt{int}\ \mid\ \texttt{bool}\ \mid\ \texttt{void}\ \mid\ \texttt{class} \\ & \mid & \texttt{public}\ \mid\ \texttt{private}\ \mid\ \texttt{new}\ \mid\ \texttt{delete} \\ & \mid & \texttt{nullptr}\ \mid\ \texttt{this}\ \mid\ \texttt{virtual} \\ & \mid & \texttt{override}\ \mid\ \texttt{namespace}\ \mid\ \texttt{template} \\ & \mid & \texttt{typename}\ \mid\ \texttt{auto}\ \mid\ \texttt{if}\ \mid\ \texttt{else}\ \mid\ \texttt{while}\ \mid\ \texttt{for}\ \mid\ \texttt{return} \\ & \mid & \texttt{true}\ \mid\ \texttt{false}\ \mid\ \texttt{operator} \\ \textit{TypeId} & ::= & \textit{Upper}\ \textit{IdentChar}^{*} \\ \textit{VarId} & ::= & \big(\ \textit{Lower}\ \mid\ \texttt{\_}\ \big)\ \textit{IdentChar}^{*} \\ \textit{NsId} & ::= & \textit{TypeId}\ \mid\ \textit{VarId} \\ \textit{IntLit} & ::= & \textit{Digit}\ \textit{Digit}^{*} \\ \textit{Symbol} & ::= & \texttt{[=]} \\ & \mid & \texttt{==}\ \mid\ \texttt{!=}\ \mid\ \texttt{<=}\ \mid\ \texttt{>=}\ \mid\ \texttt{\&\&}\ \mid\ \texttt{||}\ \mid\ \texttt{->}\ \mid\ \texttt{::}\ \mid\ \texttt{--}\ \mid\ \texttt{++} \\ & \mid & \texttt{+}\ \mid\ \texttt{-}\ \mid\ \texttt{*}\ \mid\ \texttt{/}\ \mid\ \texttt{\%}\ \mid\ \texttt{<}\ \mid\ \texttt{>}\ \mid\ \texttt{!}\ \mid\ \texttt{?}\ \mid\ \texttt{:}\ \mid\ \texttt{=} \\ & \mid & \texttt{(}\ \mid\ \texttt{)}\ \mid\ \texttt{\{}\ \mid\ \texttt{\}}\ \mid\ \texttt{[}\ \mid\ \texttt{]}\ \mid\ \texttt{,}\ \mid\ \texttt{;}\ \mid\ \texttt{.}\ \mid\ \texttt{\&}\ \mid\ \texttt{\textasciitilde} \\ \textit{IdentChar} & ::= & \textit{Upper}\ \mid\ \textit{Lower}\ \mid\ \textit{Digit}\ \mid\ \texttt{\_} \\ \textit{Upper} & ::= & \texttt{A}\ \mid\ \ldots\ \mid\ \texttt{Z} \\ \textit{Lower} & ::= & \texttt{a}\ \mid\ \ldots\ \mid\ \texttt{z} \\ \textit{Digit} & ::= & \texttt{0}\ \mid\ \ldots\ \mid\ \texttt{9} \\ \textit{Skip} & ::= & \textit{WhiteSpace}\ \mid\ \texttt{//}\ \textit{NotNewline}^{*}\ \textit{Newline}^{?} \end{array}

The lexer covers the input by a sequence of Token and Skip, discards Skip, and takes the longest match at each position. A line comment ends at a newline or at the end of the input. The symbols of three characters are tried before those of two and of one.

Lean code for Definition1.1.1●8 definitions
  • inductive(7 constructors)defined in CoreCpp/Token.lean
    complete
    inductive CoreCpp.Token : Type
    inductive CoreCpp.Token : Type
    CoreCpp.Token.kw (s : String) : CoreCpp.Token
    CoreCpp.Token.typeId (s : String) : CoreCpp.Token
    CoreCpp.Token.varId (s : String) : CoreCpp.Token
    CoreCpp.Token.nsId (s : String) : CoreCpp.Token
    CoreCpp.Token.intLit (n : Nat) : CoreCpp.Token
    CoreCpp.Token.sym (s : String) : CoreCpp.Token
    CoreCpp.Token.eof : CoreCpp.Token
  • defdefined in CoreCpp/Token.lean
    complete
    def CoreCpp.keywords : List String
    def CoreCpp.keywords : List String
    Reserved words of the subset handled by this parser. 
  • defdefined in CoreCpp/Token.lean
    complete
    def CoreCpp.cppReserved : List String
    def CoreCpp.cppReserved : List String
    The keywords of C++17 (N4659 §5.11 [lex.key], Table 5) and the alternative
    representations (Table 6). A Core C++ program uses none of them outside
    `keywords`, so every Core C++ program stays a C++ program. 
  • defdefined in CoreCpp/Token.lean
    complete
    def CoreCpp.symbols3 : List String
    def CoreCpp.symbols3 : List String
    Symbols of three, two and one characters, longest first. The tokens `--`
    and `++` belong to no production. The lexer reads them so that `5--2` fails as
    it does in C++, where the longest match gives `--`. 
  • defdefined in CoreCpp/Token.lean
    complete
    def CoreCpp.symbols2 : List String
    def CoreCpp.symbols2 : List String
  • defdefined in CoreCpp/Token.lean
    complete
    def CoreCpp.symbols1 : List String
    def CoreCpp.symbols1 : List String
  • defdefined in CoreCpp/Lexer.lean
    complete
    def CoreCpp.Lexer.isIdentStart (c : Char) : Bool
    def CoreCpp.Lexer.isIdentStart (c : Char) :
      Bool
  • defdefined in CoreCpp/Lexer.lean
    complete
    def CoreCpp.Lexer.isIdentChar (c : Char) : Bool
    def CoreCpp.Lexer.isIdentChar (c : Char) :
      Bool
Definition1.1.2
Group: Syntax, tokens and the parser. (13)
Group member previews
Preview
Definition 1.1.1
Loading preview
Group member preview content is loaded from the rendered-fragment cache.
uses 1used by 1✓L∃∀N

An identifier is classified by its initial after the reserved words are excluded. A further pass over the token array marks as an NsId every identifier whose next token is ::, of either case.

The pass qualifiers runs after the automaton, so it sees neither white space nor comments and marks std :: vector as it marks std::vector. The parser runs the automaton on each line of the Preproc output alone and the pass once on the tokens of all the lines, so a :: that starts a line marks the identifier that ends the line before.

That class is what lets a qualified name open a type where the case convention alone would read a variable, so std::vector<int> needs no reserved word.

Lean code for Definition1.1.2●2 definitions
  • defdefined in CoreCpp/Lexer.lean
    complete
    def CoreCpp.Lexer.identifier (s : String) : CoreCpp.Token
    def CoreCpp.Lexer.identifier (s : String) :
      CoreCpp.Token
    Classifies an identifier as a reserved word, or else by its initial. An
    uppercase initial gives a type identifier, and a lowercase initial or `_` a
    variable identifier. 
  • defdefined in CoreCpp/Lexer.lean
    complete
    def CoreCpp.Lexer.qualifiers (ts : Array CoreCpp.Token) :
      Array CoreCpp.Token
    def CoreCpp.Lexer.qualifiers
      (ts : Array CoreCpp.Token) :
      Array CoreCpp.Token
    Marks as a namespace identifier every identifier whose next token is `::`.
    The pass runs over the token array, so it sees neither the white space nor the
    comments the automaton has already dropped, and it marks `std :: vector` as it
    marks `std::vector`. `parseUnit` runs it once on the tokens of all the lines,
    so a `::` at the start of a line marks the identifier that ends the line
    before. 
Definition1.1.3
Group: Syntax, tokens and the parser. (13)
Group member previews
Preview
Definition 1.1.1
Loading preview
Group member preview content is loaded from the rendered-fragment cache.
Statement uses 2
Statement dependency previews
Preview
Definition 1.1.1
Loading preview
Statement dependency preview content is loaded from the rendered-fragment cache.
used by 1✓L∃∀N

The function lex maps a string to an array of tokens ended by eof. It runs the automaton Lexer.run and then the pass of Definition 1.1.2. It discards white space and line comments, reads the longest run of digits as an integer literal, the longest run of identifier characters as an identifier, and tries the symbols of three, two and one characters in that order. Any other character is a lexical error.

The lexer also rejects what C++ would read otherwise, so that every Core C++ program is a C++ program with the same meaning.

  • It rejects a keyword of C++ or an alternative representation such as and outside the reserved words of the subset (N4659 §5.11, Tables 5 and 6).

  • It rejects an integer literal with a leading 0, which C++ reads in octal, and one above 2147483647, to which C++ gives a type wider than int.

  • It reads -- and ++ as tokens that no production uses, so 5--2 fails as in C++, where the longest match gives --.

The automaton Lexer.run is partial, so Lean records an opaque constant that carries the type and not the body, and no property of it is proved here.

Lean code for Definition1.1.3●5 definitions
  • defdefined in CoreCpp/Lexer.lean
    complete
    def CoreCpp.lex (input : String) : Except String (Array CoreCpp.Token)
    def CoreCpp.lex (input : String) :
      Except String (Array CoreCpp.Token)
    The lexer, the automaton `Lexer.run` followed by the pass
    `Lexer.qualifiers`. 
  • opaquedefined in CoreCpp/Lexer.lean
    complete
    opaque CoreCpp.Lexer.run (cs : List Char) (acc : Array CoreCpp.Token) :
      Except String (Array CoreCpp.Token)
    opaque CoreCpp.Lexer.run (cs : List Char)
      (acc : Array CoreCpp.Token) :
      Except String (Array CoreCpp.Token)
    The automaton. It discards white space and line comments, reads the longest
    run of digits as an integer literal and the longest run of identifier
    characters as an identifier, tries the symbols of three, two and one
    characters in that order, and ends the array with `eof`. 
  • defdefined in CoreCpp/Lexer.lean
    complete
    def CoreCpp.Lexer.takeWhile (p : Char → Bool) :
      List Char → String × List Char
    def CoreCpp.Lexer.takeWhile
      (p : Char → Bool) :
      List Char → String × List Char
    Takes the longest prefix of characters satisfying `p`. 
  • defdefined in CoreCpp/Lexer.lean
    complete
    def CoreCpp.Lexer.matchSymbol (syms : List String) (cs : List Char) :
      Option (String × List Char)
    def CoreCpp.Lexer.matchSymbol
      (syms : List String) (cs : List Char) :
      Option (String × List Char)
    Tries to match one of the symbols at the start of the input. 
  • defdefined in CoreCpp/Lexer.lean
    complete
    def CoreCpp.Lexer.skipLine : List Char → List Char
    def CoreCpp.Lexer.skipLine :
      List Char → List Char
    Discards a line comment, up to the next newline or the end of the input.