Changed the lexing and parsing of PRAGMAs again, to allow unknown pragmas

With my previous change to PRAGMAs, unknown pragmas would fatally fail in the lexer, so that an unknown pragma would always stop compilation, which is not good.  I've changed it more towards Adam's suggestion of re-lexing and re-parsing the pragma from the parser, so we now gracefully ignore unknown pragmas again.  The lexer is a bit messy, though.
This commit is contained in:
Neil Brown 2009-03-31 11:08:53 +00:00
parent edc336de7a
commit dbc3b97343
2 changed files with 61 additions and 12 deletions

View File

@ -20,6 +20,7 @@ with this program. If not, see <http://www.gnu.org/licenses/>.
-- | Lexically analyse occam code.
module LexOccam where
import Control.Monad.Error
import Data.Generics
import Errors
@ -35,8 +36,8 @@ $hexDigit = [0-9 a-f A-F]
$horizSpace = [\ \t]
$vertSpace = [\r\n]
@directive = "COMMENT" | "ELSE" | "ENDIF" | "IF" | "INCLUDE"
| "OPTION" | "RELAX" | "USE" | "DEFINE"
@directive = "COMMENT" | "DEFINE" | "ELSE" | "ENDIF" | "IF" | "INCLUDE"
| "OPTION" | "PRAGMA" | "RELAX" | "USE"
@preprocessor = "#" @directive [^\n]*
@ -100,12 +101,15 @@ occam :-
-- In state two, we're reading the rest of the line.
-- In state three, we're in the middle of a multi-line string.
-- In state four, we're in the middle of a pragma-external string
-- In state five, we're lexing a pragma. State five is only entered specifically,
-- when we re-lex and re-parse pragmas (but it makes it easiest to put it
-- in this file too, since it can lex occam).
<0> $horizSpace* { mkState one }
<one> "#PRAGMA" $horizSpace+ "SHARED" { mkToken TokPreprocessor two }
<one> "#PRAGMA" $horizSpace+ "PERMITALIASES" { mkToken TokPreprocessor two }
<one> "#PRAGMA" $horizSpace+ "EXTERNAL" $horizSpace* \" { mkToken TokPreprocessor four }
<five> "SHARED" { mkToken Pragma two }
<five> "PERMITALIASES" { mkToken Pragma two }
<five> "EXTERNAL" $horizSpace* \" { mkToken Pragma four }
<four> \" $horizSpace* $vertSpace+ { mkState 0 }
<one> @preprocessor { mkToken TokPreprocessor 0 }
@ -134,7 +138,7 @@ occam :-
<four> @hexLiteral { mkToken TokHexLiteral four }
<four> @realLiteral { mkToken TokRealLiteral four }
<two, four> $horizSpace+ ;
<two, four, five> $horizSpace+ ;
{
-- | An occam source token and its position.
@ -215,5 +219,30 @@ runLexer filename str = go (alexStartPos, '\n', str) 0
metaLine = line,
metaColumn = col
}
-- | Run the lexer, returning a list of tokens.
-- (This is based on the `alexScanTokens` function that Alex provides.)
runPragmaLexer :: String -> String -> Either (Maybe Meta, String) [Token]
runPragmaLexer filename str = go (alexStartPos, '\n', str) five
where
go inp@(pos@(AlexPn _ line col), _, str) code =
case alexScan inp code of
AlexEOF -> return []
AlexError _ -> throwError (Just meta, "Unrecognised token")
AlexSkip inp' len -> go inp' code
AlexToken inp' len act ->
do let (t, code) = act pos (take len str)
ts <- go inp' code
return $ case t of
Just (Token _ tt) -> Token meta tt : ts
Nothing -> ts
where
meta = emptyMeta {
metaFile = Just filename,
metaLine = line,
metaColumn = col
}
}

View File

@ -1344,12 +1344,25 @@ structuredTypeField
--}}}
--{{{ pragmas
pragma :: OccParser ()
pragma = do Pragma p <- genToken isPragma
pragma = do Pragma rawP <- genToken isPragma
m <- getPosition >>* sourcePosToMeta
case map (flip matchRegex p . mkRegex)
[ "^SHARED.*"
, "^PERMITALIASES.*"
, "^EXTERNAL.*"] of
pragToks <- case runPragmaLexer "<unknown(pragma)>" rawP of
Left _ -> return []
Right toks -> return toks
cs <- getCompState
maybeParse <- return $
-- Maybe monad:
(\prod -> do otherToks <- safeTail pragToks
eitherToMaybe $ runParser (prod >> getState) ([], cs) "" otherToks
) $ -- Maybe monad again:
case
[ do Token _ (Pragma firstTok) <- listToMaybe pragToks
matchRegex (mkRegex pt) firstTok
| pt <- [ "^SHARED.*"
, "^PERMITALIASES.*"
, "^EXTERNAL.*"
]
] of
[Just _, _, _] -> do
vars <- sepBy1 identifier sComma
mapM_ (\var ->
@ -1386,11 +1399,18 @@ pragma = do Pragma p <- genToken isPragma
, csExternals = (on, fs) : csExternals st
}
_ -> warnP m WarnUnknownPreprocessorDirective $
"Unknown PRAGMA: " ++ p
"Unknown PRAGMA: " ++ show (listToMaybe pragToks)
case maybeParse of
Just st -> setState st
Nothing -> return ()
eol
where
isPragma (Token _ p@(Pragma {})) = Just p
isPragma _ = Nothing
safeTail [] = Nothing
safeTail (_:xs) = Just xs
--}}}
--{{{ processes
process :: OccParser A.Process