LMU ☀️ CMSI 3802
LANGUAGES AND AUTOMATA II
HOMEWORK #2 PARTIAL ANSWERS
  1. Ohm Exercises:

    ohm_exercises.js
    import * as ohm from "ohm-js"
    
    const grammars = {
      canadianPostalCode: String.raw`
        code  = alpha digit alpha " " digit alpha digit
        alpha = "A".."C" | "E" | "G".."H" | "J".."N" | "P" | "R".."T" | "V".."Z"
      `,
    
      visa: String.raw`
        card = "4" d d d d d d d d d d d d (d d d)?
        d    = digit
      `,
    
      masterCard: String.raw`
        card = "5" "1".."5" d d d12     --fives
             | "222" "1".."9" d12       --range2221_2229
             | "22" "3".."9" d d12      --range2230_2299
             | "2" "3".."6" d d d12     --range2300_2699
             | "27" "0".."1" d d d12    --range2700_2719
             | "2720" d12               --range2720
        d12  = d d d d d d d d d d d d
        d    = digit
      `,
    
      notThreeEndingInOO: String.raw`
        ok = long | threeWithNoFinalO | threeWithNoPenultimateO | two | char?
        long = char char char char+
        threeWithNoFinalO = char char nonOChar
        threeWithNoPenultimateO = char nonOChar char
        two = char char
        char = "A".."Z" | "a".."z"
        nonOChar = ~"o" ~"O" char
      `,
    
      divisibleBy16: String.raw`
        ok = (~("0000" end) ("0"|"1"))* "0000"   -- nonzero
           | "0" "0"? "0"? "0"?                  -- zero
      `,
    
      eightThroughThirtyTwo: String.raw`
        ok = "1".."2" digit   -- tenToTwentyNine
           | "3" "0".."2"     -- thirtyToThirtyTwo
           | "8".."9"         -- eightToNine
      `,
    
      notPythonPycharmPyc: String.raw`
        word = ~("python" end) ~("pycharm" end) ~("pyc" end) letter*
      `,
    
      restrictedFloats: String.raw`
        float = digit+ frac? exp
        frac = "." digit+
        exp = ("E" | "e") ("+" | "-")? digit digit? digit?
      `,
    
      palindromes2358: String.raw`
        pal2358 = pal8 | pal5 | pal3 | pal2
        pal8    = "a" pal6 "a"
                | "b" pal6 "b"
                | "c" pal6 "c"
        pal6    = "a" pal4 "a"
                | "b" pal4 "b"
                | "c" pal4 "c"
        pal5    = "a" pal3 "a"
                | "b" pal3 "b"
                | "c" pal3 "c"
        pal4    = "a" pal2 "a"
                | "b" pal2 "b"
                | "c" pal2 "c"
        pal3    = "a" pal1 "a"
                | "b" pal1 "b"
                | "c" pal1 "c"
        pal2    = "aa" | "bb" | "cc"
        pal1    = "a" | "b" | "c"
      `,
    
      pythonStringLiterals: String.raw`
        stringliteral     =  stringprefix? (longstring | shortstring)
        stringprefix      =  "r" | "u" | "R" | "U" | "f" | "F"
                          |  "fr" | "Fr" | "fR" | "FR" | "rf" | "rF" | "Rf" | "RF"
        shortstring       =  "'" shortstringitem_s* "'" | "\"" shortstringitem_d* "\""
        longstring        =  "'''" longstringitem_s* "'''" | "\"\"\"" longstringitem_d* "\"\"\""
        shortstringitem_s =  shortstringchar_s | stringescapeseq
        shortstringitem_d =  shortstringchar_d | stringescapeseq
        longstringitem_s  =  longstringchar_s | stringescapeseq
        longstringitem_d  =  longstringchar_d | stringescapeseq
        shortstringchar_s =  ~"\n" ~"\\" ~"'" any
        shortstringchar_d =  ~"\n" ~"\\" ~"\"" any
        longstringchar_s  =  ~"\\" ~"'''" any
        longstringchar_d  =  ~"\\" ~"\"\"\"" any
        stringescapeseq   =  "\\" any
      `,
    }
    
    export function matches(name, string) {
      const grammar = `G {${grammars[name]}}`
      return ohm.grammar(grammar).match(string).succeeded()
    }
    
  2. An Ohm Grammar for a Mystery Language:

    Mystery {
      Program   = FunDecl* Exp
      Exp       = Exp1 if Exp1 else Exp     --conditional
                | Exp1
      Exp1      = Exp1 ("+" | "-") Exp2     --additive
                | Exp2
      Exp2      = Exp2 ("*" | "/") Exp3     --multiplicative
                | Exp3
      Exp3      = "-" Exp4                  --negation
                | Exp4 
      Exp4      = Exp5 "!"                  --factorial
                | Exp5
      Exp5      = num
                | str
                | Call
                | id
                | "(" Exp ")"               --parens
      FunDecl   = func id Params Body
      Params    = "(" ListOf<id, ","> ")"
      Body      = NonemptyListOf<Exp, ";"> endkw
      Call      = id Args
      Args      = "[" ListOf<Exp, ","> "]"
    
      id        = ~keyword (letter | "@") idchar*
      idchar    = alnum | "_" | "@" | "$"
      endkw     = "end" ~idchar
      func      = "func" ~idchar
      if        = "if" ~idchar
      else      = "else" ~idchar
      keyword   = endkw | func | if | else
      num       = digit+ ("." digit+)? (("E" | "e") ("+" | "-")? digit+)?
      str       = "\"" char* "\""
      char      = ~("\"" | "\\") any        --direct
                | "\\" escape               --escaped
      escape    = "'" | "\"" | "\\" | "n" 
                | "u{" hexes "}"            --codepoint
      hexes     = h h? h? h? h? h?
      h         = hexDigit
    
      space    += "--" (~"\n" any)*         --comment
    }
    
  3. Here are the syntax diagrams for the phrase categories of the language above:

    Program
    FunDecl
    Params
    Body
    Exp
    Exp1
    Exp2
    Exp3
    Exp4
    Exp4
    Call