packages feed

LR-demo-0.0.20251105: src/LR.hs

{-# LANGUAGE LambdaCase #-}
{-# LANGUAGE FlexibleInstances #-}
{-# LANGUAGE PatternSynonyms #-}
{-# LANGUAGE TupleSections #-}
{-# LANGUAGE TypeApplications #-}
{-# LANGUAGE TypeSynonymInstances #-}

-- | LR-parser.

module LR where

import Data.Version                 ( showVersion )

import System.Environment (getArgs)
import System.Exit (exitFailure, exitSuccess)

import qualified LBNF.Abs as A
import LBNF.Par (pGrammar, myLexer)
import LBNF.Print (printTree)

import DebugPrint
import Util

import CFG
import CharacterTokenGrammar
import ParseTable
import ParseTable.Pretty

import License
import qualified Paths_LR_demo as Self ( version )

-- | Main: read file passed by only command line argument and call 'run'.

main :: IO ()
main = do
  getArgs >>= \case
    ["-h"]                -> usage
    ["--help"]            -> usage
    ["-V"]                -> version
    ["--version"]         -> version
    ["--numeric-version"] -> numericVersion
    ["--license"]         -> printLicense
    ["--licence"]         -> printLicense
    ['-':_]               -> usage
    [file]                -> run =<< readFile file
    _                     -> usage
  where
    ver = showVersion Self.version
    versionLine = unwords [ "lr-demo version", ver, "(C) 2019-25 Andreas Abel" ]
    usage = do
      putStr $ unlines
        [ versionLine
        , "Call patterns:"
        , "  -h | --help        Print this help text."
        , "  -V | --version     Print version info."
        , "  --numeric-version  Print just the version number."
        , "  --license          Print the license text."
        , "  FILE               Parses stdin with the LBNF grammar given in FILE."
        ]
      exitFailure
    version = do
      putStr $ unlines
        [ versionLine
        , "Developed for the course Programming Language Technology;"
        , "Chalmers DAT151 / University of Gothenburg DIT231."
        , "License: BSD 3-clause."
        ]
    numericVersion = do
      putStrLn ver
      exitSuccess
    printLicense = do
      putStr license
      exitSuccess

-- | Parse grammar and then use it to parse stdin.

run :: String -> IO ()
run s = do

  -- Parse CFG grammar from file in LBNF syntax
  tree <- runErr (putStrLn "Syntax error in grammar file") $
    pGrammar (myLexer s)

  -- Scope-check grammar and convert into internal format.
  (mstart, grm)  <- runM $ checkGrammar tree

  start <- runM $ case mstart of
    Just start -> Right start
    Nothing    -> Left "grammar is empty!"

  putStrLn $ unlines
    [ "Using the following grammar:"
    , ""
    , printTree $ reifyGrammar grm
    ]

  let newstart = A.Ident "%start"
  let egrm = addNewStart newstart newstart $ makeEGrammar grm start
  let ipt  = ptGen egrm

  putStrLn $ unlines
    [ "Generated parse table:"
    , ""
    , debugPrint $ WithNTNames @A.Ident (getNTNames egrm) ipt
    ]

  let pt   = constructParseTable' ipt

  -- Run the parser.
  putStrLn "Parsing stdin..."
  stdin <- trim <$> getContents
  -- runM $ parseWith pt stdin
  -- putStrLn "Parse successful!"
  putStrLn $ debugPrint $ runLR1Parser pt stdin

type Err = Either String

runM :: Err a -> IO a
runM = runErr $ return ()

runErr :: IO () -> Err a -> IO a
runErr preErr = \case
  Right a -> return a
  Left err -> do
    preErr
    putStrLn $ "Error: " ++ err
    exitFailure