From a93439dfc79547386462d1c08b06d546b033b6ba Mon Sep 17 00:00:00 2001 From: Adam Sampson Date: Thu, 26 Apr 2007 13:20:43 +0000 Subject: [PATCH] Implement continuation lines of both kinds --- fco2/Indentation.hs | 64 ++++++++++++++++++++++++++++++++------------- fco2/Parse.hs | 4 +-- fco2/TODO | 5 ---- 3 files changed, 48 insertions(+), 25 deletions(-) diff --git a/fco2/Indentation.hs b/fco2/Indentation.hs index 0a83c53..21d991f 100644 --- a/fco2/Indentation.hs +++ b/fco2/Indentation.hs @@ -5,6 +5,7 @@ import Control.Monad import Control.Monad.Error import Control.Monad.State import Data.List +import Text.Regex import Errors import ParseState @@ -14,10 +15,6 @@ import Pass -- what it joined into ParseState so that error reporting later on can -- reconstruct the original position. --- FIXME this doesn't handle multi-line strings --- FIXME or VALOF processes --- FIXME or continuation lines... - indentMarker = "__indent" outdentMarker = "__outdent" eolMarker = "__eol" @@ -69,21 +66,52 @@ removeIndentation filename orig case psIndentLinesOut ps of (l:ls) -> ((l ++ s):ls) }) -- | Given a line, read the rest of it, then return the complete thing. - finishLine :: String -> String -> Bool -> PassM String - finishLine left soFar inStr + finishLine :: String -> String -> Bool -> String -> PassM String + finishLine left soFar inStr afterStr = case (left, inStr) of ([], False) -> plainEOL ('-':'-':cs, False) -> plainEOL ([], True) -> die "end of line in string without continuation" (['*'], True) -> stringEOL - ('"':cs, iS) -> finishLine cs ('"':soFar) (not iS) - ('*':'"':cs, True) -> finishLine cs ('"':'*':soFar) True - (c:cs, iS) -> finishLine cs (c:soFar) iS + ('"':cs, iS) -> finishLine cs (afterStr ++ ('"':soFar)) (not iS) "" + ('*':'"':cs, True) -> finishLine cs ('"':'*':soFar) True afterStr + (c:cs, iS) -> finishLine cs (c:soFar) iS afterStr where - -- FIXME check if this should have a continuation - plainEOL = return $ reverse soFar - -- FIXME implement - stringEOL = die "string continues" + -- | Finish a regular line. + plainEOL :: PassM String + plainEOL + = do let s = reverse soFar + if hasContinuation s + then do l <- getLine >>= checkJust "no continuation line" + finishLine l ('\n':soFar) False "" + else return s + + -- | Finish a line where we're in the middle of a string. + stringEOL :: PassM String + stringEOL + = do l <- getLine >>= checkJust "no string continuation line" + l' <- contStringStart l + -- When we hit the end of the string, add a \n after it to + -- make the line numbers match up again. + finishLine l' soFar True ('\n':afterStr) + + -- | Does a line have a continuation line following it? + hasContinuation :: String -> Bool + hasContinuation s + = case matchRegex contRE s of + Just _ -> True + Nothing -> False + where + -- FIXME This should probably be based on the list of operators and + -- reserved words that the parser already has; for now this is the + -- regexp that occamdoc uses. + contRE = mkRegexWithOpts "(-|~|\\+|-|\\*|/|\\\\|/\\\\|\\\\/|><|=|<>|<|>|>=|<=|,|;|:=|<<|>>|([[:space:]](MINUS|BITNOT|NOT|SIZE|REM|PLUS|MINUS|TIMES|BITAND|BITOR|AND|OR|AFTER|FROM|FOR|IS|RETYPES|RESHAPES)))[[:space:]]*$" False True + + -- | Strip the spaces-then-star beginning off a string continuation line. + contStringStart :: String -> PassM String + contStringStart (' ':cs) = contStringStart cs + contStringStart ('*':cs) = return cs + contStringStart _ = die "string continuation line doesn't start with *" -- | Get the next *complete* line from the input, resolving continuations. readLine :: PassM (Maybe String) @@ -91,7 +119,7 @@ removeIndentation filename orig = do line <- getLine case line of Just s -> - do r <- finishLine s "" False + do r <- finishLine s "" False "" return $ Just r Nothing -> return Nothing @@ -117,13 +145,13 @@ removeIndentation filename orig Nothing -> return () Just line -> do (newLevel, stripped) <- countIndent line 0 - addLine level newLevel stripped + addLine level newLevel line stripped -- | Once a line's been retrieved, add it to the output along with the -- appropriate markers, then go and process the next one. - addLine :: Int -> Int -> String -> PassM () - addLine level newLevel line - | line == "" = + addLine :: Int -> Int -> String -> String -> PassM () + addLine level newLevel line stripped + | stripped == "" = do putLine "" nextLine level | newLevel > level = diff --git a/fco2/Parse.hs b/fco2/Parse.hs index 425815f..acb72e0 100644 --- a/fco2/Parse.hs +++ b/fco2/Parse.hs @@ -1722,7 +1722,6 @@ mainProcess :: OccParser A.Process mainProcess = do m <- md sMainMarker - eol -- Stash the current locals so that we can either restore them -- when we get back to the file we included this one from, or -- pull the TLP name from them at the end. @@ -1783,7 +1782,8 @@ loadSource file = load file file Nothing -> do progress $ "Loading source file " ++ realName rawSource <- liftIO $ readSource realName - source <- removeIndentation realName (rawSource ++ "\n" ++ mainMarker) + source' <- removeIndentation realName rawSource + let source = source' ++ "\n" ++ mainMarker ++ "\n" debug $ "Preprocessed source:" debug $ numberLines source modify $ (\ps -> ps { psSourceFiles = (file, source) : psSourceFiles ps }) diff --git a/fco2/TODO b/fco2/TODO index 5be7308..8f98c68 100644 --- a/fco2/TODO +++ b/fco2/TODO @@ -25,8 +25,6 @@ Add an option for whether to compile out overflow/bounds checks. ## Parser -The indentation parser is way too simplistic. - Record literals aren't implemented. ## Passes @@ -54,9 +52,6 @@ Multidimensional array literals won't work. We could have genSpec generate {} around specs if it's not immediately inside another spec (which'd require some extra boolean arguments to find out). -genTopLevel should look at what interface the PROC is actually expecting, like -occ21 does. - If the assembler-analysis approach to working out process sizes works, then we can put the sizes in variables in a separate object file and only generate/compile that after we've done the main one.