Implement continuation lines of both kinds

This commit is contained in:
Adam Sampson 2007-04-26 13:20:43 +00:00
parent f5345f3815
commit a93439dfc7
3 changed files with 48 additions and 25 deletions

View File

@ -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 =

View File

@ -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 })

View File

@ -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.