First stuff for fco2 -- copied from fco
This commit is contained in:
parent
6dbb86f610
commit
c8c7935905
199
fco2/AST.hs
Normal file
199
fco2/AST.hs
Normal file
|
@ -0,0 +1,199 @@
|
||||||
|
-- Data types for occam abstract syntax
|
||||||
|
-- This is intended to be imported qualified:
|
||||||
|
-- import qualified AST as O
|
||||||
|
|
||||||
|
module AST where
|
||||||
|
|
||||||
|
import Data.Generics
|
||||||
|
import Metadata
|
||||||
|
|
||||||
|
data Name = Name Meta String
|
||||||
|
deriving (Show, Eq, Typeable, Data)
|
||||||
|
|
||||||
|
data Tag = Tag Meta String
|
||||||
|
deriving (Show, Eq, Typeable, Data)
|
||||||
|
|
||||||
|
data Type =
|
||||||
|
Bool
|
||||||
|
| Byte
|
||||||
|
| Int | Int16 | Int32 | Int64
|
||||||
|
| Real32 | Real64
|
||||||
|
| Array Expression Type
|
||||||
|
| ArrayUnsized Type
|
||||||
|
| UserType Name
|
||||||
|
| Chan Type
|
||||||
|
| Counted Type Type
|
||||||
|
| Any
|
||||||
|
| Timer
|
||||||
|
| Port Type
|
||||||
|
| Val Type
|
||||||
|
| Infer -- for where the type is not given but can be worked out (e.g. "x IS y:")
|
||||||
|
deriving (Show, Eq, Typeable, Data)
|
||||||
|
|
||||||
|
data ConversionMode =
|
||||||
|
DefaultConversion
|
||||||
|
| Round
|
||||||
|
| Trunc
|
||||||
|
deriving (Show, Eq, Typeable, Data)
|
||||||
|
|
||||||
|
data Subscript =
|
||||||
|
Subscript Meta Expression
|
||||||
|
| SubscriptTag Meta Tag
|
||||||
|
| SubFromFor Meta Expression Expression
|
||||||
|
| SubFrom Meta Expression
|
||||||
|
| SubFor Meta Expression
|
||||||
|
deriving (Show, Eq, Typeable, Data)
|
||||||
|
|
||||||
|
data LiteralRepr =
|
||||||
|
RealLiteral Meta String
|
||||||
|
| IntLiteral Meta String
|
||||||
|
| HexLiteral Meta String
|
||||||
|
| ByteLiteral Meta String
|
||||||
|
| StringLiteral Meta String
|
||||||
|
| ArrayLiteral Meta [Expression]
|
||||||
|
deriving (Show, Eq, Typeable, Data)
|
||||||
|
|
||||||
|
data Literal =
|
||||||
|
Literal Meta Type LiteralRepr
|
||||||
|
| SubscriptedLiteral Meta Subscript Literal
|
||||||
|
deriving (Show, Eq, Typeable, Data)
|
||||||
|
|
||||||
|
data Variable =
|
||||||
|
Variable Meta Name
|
||||||
|
| SubscriptedVariable Meta Subscript Variable
|
||||||
|
deriving (Show, Eq, Typeable, Data)
|
||||||
|
|
||||||
|
data Expression =
|
||||||
|
Monadic Meta MonadicOp Expression
|
||||||
|
| Dyadic Meta DyadicOp Expression Expression
|
||||||
|
| MostPos Meta Type
|
||||||
|
| MostNeg Meta Type
|
||||||
|
| Size Meta Type
|
||||||
|
| Conversion Meta ConversionMode Type Expression
|
||||||
|
| ExprVariable Meta Variable
|
||||||
|
| ExprLiteral Meta Literal
|
||||||
|
| True Meta
|
||||||
|
| False Meta
|
||||||
|
| FunctionCall Meta Name [Expression]
|
||||||
|
| BytesInType Meta Type
|
||||||
|
| OffsetOf Meta Type Tag
|
||||||
|
deriving (Show, Eq, Typeable, Data)
|
||||||
|
|
||||||
|
data ExpressionList =
|
||||||
|
FunctionCallList Meta Name [Expression]
|
||||||
|
| ExpressionList Meta [Expression]
|
||||||
|
deriving (Show, Eq, Typeable, Data)
|
||||||
|
|
||||||
|
data MonadicOp =
|
||||||
|
MonadicBytesIn
|
||||||
|
| MonadicSubtr
|
||||||
|
| MonadicBitNot
|
||||||
|
| MonadicNot
|
||||||
|
| MonadicSize
|
||||||
|
deriving (Show, Eq, Typeable, Data)
|
||||||
|
|
||||||
|
data DyadicOp =
|
||||||
|
Add | Subtr | Mul | Div | Rem
|
||||||
|
| Plus | Minus | Times
|
||||||
|
| BitAnd | BitOr | BitXor
|
||||||
|
| And | Or
|
||||||
|
| Eq | NotEq | Less | More | LessEq | MoreEq
|
||||||
|
| After
|
||||||
|
deriving (Show, Eq, Typeable, Data)
|
||||||
|
|
||||||
|
data InputItem =
|
||||||
|
InCounted Meta Variable Variable
|
||||||
|
| InVariable Meta Variable
|
||||||
|
deriving (Show, Eq, Typeable, Data)
|
||||||
|
|
||||||
|
data OutputItem =
|
||||||
|
OutCounted Meta Expression Expression
|
||||||
|
| OutExpression Meta Expression
|
||||||
|
deriving (Show, Eq, Typeable, Data)
|
||||||
|
|
||||||
|
data Replicator = For Meta Name Expression Expression
|
||||||
|
deriving (Show, Eq, Typeable, Data)
|
||||||
|
|
||||||
|
data Choice = Choice Meta Expression Process
|
||||||
|
deriving (Show, Eq, Typeable, Data)
|
||||||
|
|
||||||
|
data Alternative =
|
||||||
|
Alternative Meta Variable InputMode Process
|
||||||
|
| AlternativeCond Meta Expression Variable InputMode Process
|
||||||
|
| AlternativeSkip Meta Expression Process
|
||||||
|
deriving (Show, Eq, Typeable, Data)
|
||||||
|
|
||||||
|
data Option =
|
||||||
|
Option Meta [Expression] Process
|
||||||
|
| Else Meta Process
|
||||||
|
deriving (Show, Eq, Typeable, Data)
|
||||||
|
|
||||||
|
data Variant = Variant Meta Tag [InputItem] Process
|
||||||
|
deriving (Show, Eq, Typeable, Data)
|
||||||
|
|
||||||
|
-- This represents something that can contain local replicators and specifications.
|
||||||
|
-- (This ought to be a parametric type, "Structured Variant" etc., but doing so
|
||||||
|
-- makes using generic functions across it hard.)
|
||||||
|
data Structured =
|
||||||
|
Rep Meta Replicator Structured
|
||||||
|
| Spec Meta Specification Structured
|
||||||
|
| OnlyV Meta Variant
|
||||||
|
| OnlyC Meta Choice
|
||||||
|
| OnlyO Meta Option
|
||||||
|
| OnlyP Meta Process
|
||||||
|
| OnlyA Meta Alternative
|
||||||
|
| Several Meta [Structured]
|
||||||
|
deriving (Show, Eq, Typeable, Data)
|
||||||
|
|
||||||
|
data InputMode =
|
||||||
|
InputSimple Meta [InputItem]
|
||||||
|
| InputCase Meta Structured
|
||||||
|
| InputAfter Meta Expression
|
||||||
|
deriving (Show, Eq, Typeable, Data)
|
||||||
|
|
||||||
|
type Formals = [(Type, Name)]
|
||||||
|
type Specification = (Name, SpecType)
|
||||||
|
data SpecType =
|
||||||
|
Place Meta Expression
|
||||||
|
| Declaration Meta Type
|
||||||
|
| Is Meta Type Variable
|
||||||
|
| ValIs Meta Type Expression
|
||||||
|
| DataTypeIs Meta Type
|
||||||
|
| DataTypeRecord Meta Bool [(Type, Tag)]
|
||||||
|
| ProtocolIs Meta [Type]
|
||||||
|
| ProtocolCase Meta [(Tag, [Type])]
|
||||||
|
| Proc Meta Formals Process
|
||||||
|
| Function Meta [Type] Formals ValueProcess
|
||||||
|
| Retypes Meta Type Variable
|
||||||
|
| Reshapes Meta Type Variable
|
||||||
|
| ValRetypes Meta Type Variable
|
||||||
|
| ValReshapes Meta Type Variable
|
||||||
|
deriving (Show, Eq, Typeable, Data)
|
||||||
|
|
||||||
|
data ValueProcess =
|
||||||
|
ValOfSpec Meta Specification ValueProcess
|
||||||
|
| ValOf Meta Process ExpressionList
|
||||||
|
deriving (Show, Eq, Typeable, Data)
|
||||||
|
|
||||||
|
data Process =
|
||||||
|
ProcSpec Meta Specification Process
|
||||||
|
| Assign Meta [Variable] ExpressionList
|
||||||
|
| Input Meta Variable InputMode
|
||||||
|
| Output Meta Variable [OutputItem]
|
||||||
|
| OutputCase Meta Variable Tag [OutputItem]
|
||||||
|
| Skip Meta
|
||||||
|
| Stop Meta
|
||||||
|
| Main Meta
|
||||||
|
| Seq Meta [Process]
|
||||||
|
| SeqRep Meta Replicator Process
|
||||||
|
| If Meta Structured
|
||||||
|
| Case Meta Expression Structured
|
||||||
|
| While Meta Expression Process
|
||||||
|
| Par Meta Bool [Process]
|
||||||
|
| ParRep Meta Bool Replicator Process
|
||||||
|
| PlacedPar Meta Structured
|
||||||
|
| Processor Meta Expression Process
|
||||||
|
| Alt Meta Bool Structured
|
||||||
|
| ProcCall Meta Name [Expression]
|
||||||
|
deriving (Show, Eq, Typeable, Data)
|
||||||
|
|
87
fco2/Main.hs
Normal file
87
fco2/Main.hs
Normal file
|
@ -0,0 +1,87 @@
|
||||||
|
-- Driver for FCO
|
||||||
|
|
||||||
|
module Main where
|
||||||
|
|
||||||
|
import List
|
||||||
|
import System
|
||||||
|
import System.Console.GetOpt
|
||||||
|
import System.IO
|
||||||
|
|
||||||
|
import PrettyShow
|
||||||
|
import Parse
|
||||||
|
import SExpression
|
||||||
|
import Pass
|
||||||
|
import PTPasses
|
||||||
|
import PTToAST
|
||||||
|
import ASTPasses
|
||||||
|
import COutput
|
||||||
|
|
||||||
|
data Flag = ParseOnly | SOccamOnly | Verbose
|
||||||
|
deriving (Eq, Show)
|
||||||
|
|
||||||
|
options :: [OptDescr Flag]
|
||||||
|
options =
|
||||||
|
[ Option [] ["parse-tree"] (NoArg ParseOnly) "parse input files and output S-expression parse tree"
|
||||||
|
, Option [] ["soccam"] (NoArg SOccamOnly) "parse input files and output soccam"
|
||||||
|
, Option ['v'] ["verbose"] (NoArg Verbose) "show more detail about what's going on"
|
||||||
|
]
|
||||||
|
|
||||||
|
getOpts :: [String] -> IO ([Flag], [String])
|
||||||
|
getOpts argv =
|
||||||
|
case getOpt RequireOrder options argv of
|
||||||
|
(o,n,[] ) -> return (o,n)
|
||||||
|
(_,_,errs) -> error (concat errs ++ usageInfo header options)
|
||||||
|
where header = "Usage: fco [OPTION...] SOURCEFILE"
|
||||||
|
|
||||||
|
numberedListing :: String -> String
|
||||||
|
numberedListing s = concat $ intersperse "\n" $ [(show n) ++ ": " ++ s | (n, s) <- zip [1..] (lines s)]
|
||||||
|
|
||||||
|
main :: IO ()
|
||||||
|
main = do
|
||||||
|
argv <- getArgs
|
||||||
|
(opts, args) <- getOpts argv
|
||||||
|
|
||||||
|
let fn = case args of
|
||||||
|
[fn] -> fn
|
||||||
|
_ -> error "Must specify a single input file"
|
||||||
|
|
||||||
|
let progress = if Verbose `elem` opts then hPutStrLn stderr else (\s -> return ())
|
||||||
|
|
||||||
|
progress $ "Options: " ++ (show opts)
|
||||||
|
progress $ "Compiling " ++ fn
|
||||||
|
progress ""
|
||||||
|
|
||||||
|
progress "{{{ Preprocessor"
|
||||||
|
preprocessed <- readSource fn
|
||||||
|
progress $ numberedListing preprocessed
|
||||||
|
progress "}}}"
|
||||||
|
|
||||||
|
progress "{{{ Parser"
|
||||||
|
let pt = parseSource preprocessed fn
|
||||||
|
progress $ pshow pt
|
||||||
|
progress "}}}"
|
||||||
|
|
||||||
|
if ParseOnly `elem` opts then do
|
||||||
|
putStrLn $ show (nodeToSExp pt)
|
||||||
|
else if SOccamOnly `elem` opts then do
|
||||||
|
putStrLn $ show (nodeToSOccam pt)
|
||||||
|
else do
|
||||||
|
progress "{{{ PT passes"
|
||||||
|
pt' <- runPasses ptPasses progress pt
|
||||||
|
progress "}}}"
|
||||||
|
|
||||||
|
progress "{{{ PT to AST"
|
||||||
|
let ast = ptToAST pt'
|
||||||
|
progress $ pshow ast
|
||||||
|
progress "}}}"
|
||||||
|
|
||||||
|
progress "{{{ AST passes"
|
||||||
|
ast' <- runPasses astPasses progress ast
|
||||||
|
progress "}}}"
|
||||||
|
|
||||||
|
progress "{{{ C output"
|
||||||
|
putStr $ writeC ast'
|
||||||
|
progress "}}}"
|
||||||
|
|
||||||
|
progress "Done"
|
||||||
|
|
38
fco2/Makefile
Normal file
38
fco2/Makefile
Normal file
|
@ -0,0 +1,38 @@
|
||||||
|
targets = fco
|
||||||
|
|
||||||
|
all: $(targets)
|
||||||
|
|
||||||
|
sources = \
|
||||||
|
AST.hs \
|
||||||
|
ASTPasses.hs \
|
||||||
|
COutput.hs \
|
||||||
|
Main.hs \
|
||||||
|
Metadata.hs \
|
||||||
|
Parse.hs \
|
||||||
|
Pass.hs \
|
||||||
|
PrettyShow.hs \
|
||||||
|
PT.hs \
|
||||||
|
PTPasses.hs \
|
||||||
|
SExpression.hs \
|
||||||
|
PTToAST.hs
|
||||||
|
|
||||||
|
$(targets): $(sources)
|
||||||
|
ghc -fglasgow-exts -o fco --make Main
|
||||||
|
|
||||||
|
tests = $(wildcard testcases/*.occ)
|
||||||
|
|
||||||
|
test: $(targets) $(tests)
|
||||||
|
@set -e; for x in $(tests); do \
|
||||||
|
echo -n "$$x: " ; \
|
||||||
|
if ! ./fco --parse-tree $$x >$$x.log 2>&1 ; then \
|
||||||
|
echo "parse failed" ; \
|
||||||
|
elif ! ./fco -v $$x >$$x.log 2>&1 ; then \
|
||||||
|
echo "full failed" ; \
|
||||||
|
else \
|
||||||
|
echo "ok" ; \
|
||||||
|
fi ; \
|
||||||
|
done
|
||||||
|
|
||||||
|
clean:
|
||||||
|
rm -f $(targets) *.o *.hi
|
||||||
|
|
30
fco2/Metadata.hs
Normal file
30
fco2/Metadata.hs
Normal file
|
@ -0,0 +1,30 @@
|
||||||
|
-- Metadata types
|
||||||
|
|
||||||
|
module Metadata where
|
||||||
|
|
||||||
|
import Data.Generics
|
||||||
|
import Data.List
|
||||||
|
|
||||||
|
type Meta = [Metadatum]
|
||||||
|
|
||||||
|
data Metadatum =
|
||||||
|
SourcePos String Int Int
|
||||||
|
deriving (Show, Eq, Typeable, Data)
|
||||||
|
|
||||||
|
findSourcePos :: Meta -> Maybe Metadatum
|
||||||
|
findSourcePos ms = find (\x -> case x of SourcePos _ _ _ -> True
|
||||||
|
otherwise -> False) ms
|
||||||
|
|
||||||
|
formatSourcePos :: Meta -> String
|
||||||
|
formatSourcePos m = case findSourcePos m of
|
||||||
|
Just (SourcePos f l c) -> "<@" ++ show l ++ ":" ++ show c ++ ">"
|
||||||
|
Nothing -> "<?>"
|
||||||
|
|
||||||
|
die :: Monad m => String -> m a
|
||||||
|
die s = error $ "error: " ++ s
|
||||||
|
|
||||||
|
dieP :: Monad m => Meta -> String -> m a
|
||||||
|
dieP m s = case findSourcePos m of
|
||||||
|
Just (SourcePos f l c) -> die $ f ++ ":" ++ (show l) ++ ":" ++ (show c) ++ ": " ++ s
|
||||||
|
Nothing -> die $ "unknown position: " ++ s
|
||||||
|
|
803
fco2/Parse.hs
Normal file
803
fco2/Parse.hs
Normal file
|
@ -0,0 +1,803 @@
|
||||||
|
-- Parse occam code
|
||||||
|
|
||||||
|
module Parse (readSource, parseSource) where
|
||||||
|
|
||||||
|
import Data.List
|
||||||
|
import Text.ParserCombinators.Parsec
|
||||||
|
import qualified Text.ParserCombinators.Parsec.Token as P
|
||||||
|
import Text.ParserCombinators.Parsec.Language (emptyDef)
|
||||||
|
import qualified IO
|
||||||
|
|
||||||
|
import qualified PT as N
|
||||||
|
import Metadata
|
||||||
|
|
||||||
|
-- -------------------------------------------------------------
|
||||||
|
|
||||||
|
md :: Parser Meta
|
||||||
|
md = do
|
||||||
|
pos <- getPosition
|
||||||
|
return $ [SourcePos (sourceName pos) (sourceLine pos) (sourceColumn pos)]
|
||||||
|
|
||||||
|
nd :: Meta -> N.NodeType -> N.Node
|
||||||
|
nd = N.Node
|
||||||
|
|
||||||
|
-- -------------------------------------------------------------
|
||||||
|
|
||||||
|
mainMarker = "##MAGIC-FCO-MAIN-PROCESS##"
|
||||||
|
|
||||||
|
occamStyle
|
||||||
|
= emptyDef
|
||||||
|
{ P.commentLine = "--"
|
||||||
|
, P.nestedComments = False
|
||||||
|
, P.identStart = letter
|
||||||
|
, P.identLetter = alphaNum <|> char '.'
|
||||||
|
, P.opStart = oneOf "+-*/\\>=<~"
|
||||||
|
, P.opLetter = oneOf "/\\>=<"
|
||||||
|
, P.reservedOpNames= [
|
||||||
|
"+",
|
||||||
|
"-",
|
||||||
|
"*",
|
||||||
|
"/",
|
||||||
|
"\\",
|
||||||
|
"/\\",
|
||||||
|
"\\/",
|
||||||
|
"><",
|
||||||
|
"=",
|
||||||
|
"<>",
|
||||||
|
"<",
|
||||||
|
">",
|
||||||
|
">=",
|
||||||
|
"<=",
|
||||||
|
"-",
|
||||||
|
"~"
|
||||||
|
]
|
||||||
|
, P.reservedNames = [
|
||||||
|
"AFTER",
|
||||||
|
"ALT",
|
||||||
|
"AND",
|
||||||
|
"ANY",
|
||||||
|
"AT",
|
||||||
|
"BITAND",
|
||||||
|
"BITNOT",
|
||||||
|
"BITOR",
|
||||||
|
"BOOL",
|
||||||
|
"BYTE",
|
||||||
|
"BYTESIN",
|
||||||
|
"CASE",
|
||||||
|
"CHAN",
|
||||||
|
"DATA",
|
||||||
|
"ELSE",
|
||||||
|
"FALSE",
|
||||||
|
"FOR",
|
||||||
|
"FROM",
|
||||||
|
"FUNCTION",
|
||||||
|
"IF",
|
||||||
|
"INT",
|
||||||
|
"INT16",
|
||||||
|
"INT32",
|
||||||
|
"INT64",
|
||||||
|
"IS",
|
||||||
|
"MINUS",
|
||||||
|
"MOSTNEG",
|
||||||
|
"MOSTPOS",
|
||||||
|
"NOT",
|
||||||
|
"OF",
|
||||||
|
"OFFSETOF",
|
||||||
|
"OR",
|
||||||
|
"PACKED",
|
||||||
|
"PAR",
|
||||||
|
"PLACE",
|
||||||
|
"PLACED",
|
||||||
|
"PLUS",
|
||||||
|
"PORT",
|
||||||
|
"PRI",
|
||||||
|
"PROC",
|
||||||
|
"PROCESSOR",
|
||||||
|
"PROTOCOL",
|
||||||
|
"REAL32",
|
||||||
|
"REAL64",
|
||||||
|
"RECORD",
|
||||||
|
"REM",
|
||||||
|
"RESHAPES",
|
||||||
|
"RESULT",
|
||||||
|
"RETYPES",
|
||||||
|
"ROUND",
|
||||||
|
"SEQ",
|
||||||
|
"SIZE",
|
||||||
|
"SKIP",
|
||||||
|
"STOP",
|
||||||
|
"TIMER",
|
||||||
|
"TIMES",
|
||||||
|
"TRUE",
|
||||||
|
"TRUNC",
|
||||||
|
"TYPE",
|
||||||
|
"VAL",
|
||||||
|
"VALOF",
|
||||||
|
"WHILE",
|
||||||
|
mainMarker
|
||||||
|
]
|
||||||
|
, P.caseSensitive = True
|
||||||
|
}
|
||||||
|
|
||||||
|
lexer :: P.TokenParser ()
|
||||||
|
lexer = P.makeTokenParser occamStyle
|
||||||
|
-- XXX replace whitespace with something that doesn't eat \ns
|
||||||
|
|
||||||
|
whiteSpace = P.whiteSpace lexer
|
||||||
|
lexeme = P.lexeme lexer
|
||||||
|
symbol = P.symbol lexer
|
||||||
|
natural = P.natural lexer
|
||||||
|
parens = P.parens lexer
|
||||||
|
semi = P.semi lexer
|
||||||
|
identifier= P.identifier lexer
|
||||||
|
reserved = P.reserved lexer
|
||||||
|
reservedOp= P.reservedOp lexer
|
||||||
|
|
||||||
|
sLeft = try $ symbol "["
|
||||||
|
sRight = try $ symbol "]"
|
||||||
|
sLeftR = try $ symbol "("
|
||||||
|
sRightR = try $ symbol ")"
|
||||||
|
sAssign = try $ symbol ":="
|
||||||
|
sColon = try $ symbol ":"
|
||||||
|
sColons = try $ symbol "::"
|
||||||
|
sComma = try $ symbol ","
|
||||||
|
sSemi = try $ symbol ";"
|
||||||
|
sAmp = try $ symbol "&"
|
||||||
|
sQuest = try $ symbol "?"
|
||||||
|
sBang = try $ symbol "!"
|
||||||
|
sEq = try $ symbol "="
|
||||||
|
|
||||||
|
sAFTER = reserved "AFTER"
|
||||||
|
sALT = reserved "ALT"
|
||||||
|
sAND = reserved "AND"
|
||||||
|
sANY = reserved "ANY"
|
||||||
|
sAT = reserved "AT"
|
||||||
|
sBITAND = reserved "BITAND"
|
||||||
|
sBITNOT = reserved "BITNOT"
|
||||||
|
sBITOR = reserved "BITOR"
|
||||||
|
sBOOL = reserved "BOOL"
|
||||||
|
sBYTE = reserved "BYTE"
|
||||||
|
sBYTESIN = reserved "BYTESIN"
|
||||||
|
sCASE = reserved "CASE"
|
||||||
|
sCHAN = reserved "CHAN"
|
||||||
|
sDATA = reserved "DATA"
|
||||||
|
sELSE = reserved "ELSE"
|
||||||
|
sFALSE = reserved "FALSE"
|
||||||
|
sFOR = reserved "FOR"
|
||||||
|
sFROM = reserved "FROM"
|
||||||
|
sFUNCTION = reserved "FUNCTION"
|
||||||
|
sIF = reserved "IF"
|
||||||
|
sINT = reserved "INT"
|
||||||
|
sINT16 = reserved "INT16"
|
||||||
|
sINT32 = reserved "INT32"
|
||||||
|
sINT64 = reserved "INT64"
|
||||||
|
sIS = reserved "IS"
|
||||||
|
sMINUS = reserved "MINUS"
|
||||||
|
sMOSTNEG = reserved "MOSTNEG"
|
||||||
|
sMOSTPOS = reserved "MOSTPOS"
|
||||||
|
sNOT = reserved "NOT"
|
||||||
|
sOF = reserved "OF"
|
||||||
|
sOFFSETOF = reserved "OFFSETOF"
|
||||||
|
sOR = reserved "OR"
|
||||||
|
sPACKED = reserved "PACKED"
|
||||||
|
sPAR = reserved "PAR"
|
||||||
|
sPLACE = reserved "PLACE"
|
||||||
|
sPLACED = reserved "PLACED"
|
||||||
|
sPLUS = reserved "PLUS"
|
||||||
|
sPORT = reserved "PORT"
|
||||||
|
sPRI = reserved "PRI"
|
||||||
|
sPROC = reserved "PROC"
|
||||||
|
sPROCESSOR = reserved "PROCESSOR"
|
||||||
|
sPROTOCOL = reserved "PROTOCOL"
|
||||||
|
sREAL32 = reserved "REAL32"
|
||||||
|
sREAL64 = reserved "REAL64"
|
||||||
|
sRECORD = reserved "RECORD"
|
||||||
|
sREM = reserved "REM"
|
||||||
|
sRESHAPES = reserved "RESHAPES"
|
||||||
|
sRESULT = reserved "RESULT"
|
||||||
|
sRETYPES = reserved "RETYPES"
|
||||||
|
sROUND = reserved "ROUND"
|
||||||
|
sSEQ = reserved "SEQ"
|
||||||
|
sSIZE = reserved "SIZE"
|
||||||
|
sSKIP = reserved "SKIP"
|
||||||
|
sSTOP = reserved "STOP"
|
||||||
|
sTIMER = reserved "TIMER"
|
||||||
|
sTIMES = reserved "TIMES"
|
||||||
|
sTRUE = reserved "TRUE"
|
||||||
|
sTRUNC = reserved "TRUNC"
|
||||||
|
sTYPE = reserved "TYPE"
|
||||||
|
sVAL = reserved "VAL"
|
||||||
|
sVALOF = reserved "VALOF"
|
||||||
|
sWHILE = reserved "WHILE"
|
||||||
|
sMainMarker = reserved mainMarker
|
||||||
|
|
||||||
|
-- XXX could handle VALOF by translating each step to one { and matching multiple ones?
|
||||||
|
indent = symbol "{"
|
||||||
|
outdent = symbol "}"
|
||||||
|
eol = symbol "@"
|
||||||
|
|
||||||
|
-- -------------------------------------------------------------
|
||||||
|
|
||||||
|
-- These productions are based on the syntax in the occam2.1 manual.
|
||||||
|
|
||||||
|
-- The way productions should work is that each production should only consume input if it's sure that it's unambiguous.
|
||||||
|
|
||||||
|
abbreviation
|
||||||
|
= try (do { m <- md ; n <- name ; sIS ; v <- variable ; sColon ; eol ; return $ nd m $ N.Is n v })
|
||||||
|
<|> try (do { m <- md ; s <- specifier ; n <- name ; sIS ; v <- variable ; sColon ; eol ; return $ nd m $ N.IsType s n v })
|
||||||
|
<|> do { m <- md ; sVAL ;
|
||||||
|
try (do { n <- name ; sIS ; e <- expression ; sColon ; eol ; return $ nd m $ N.ValIs n e })
|
||||||
|
<|> do { s <- specifier ; n <- name ; sIS ; e <- expression ; sColon ; eol ; return $ nd m $ N.ValIsType s n e } }
|
||||||
|
<?> "abbreviation"
|
||||||
|
|
||||||
|
actual
|
||||||
|
= expression
|
||||||
|
<|> variable
|
||||||
|
<|> channel
|
||||||
|
<?> "actual"
|
||||||
|
|
||||||
|
allocation
|
||||||
|
= do { m <- md ; sPLACE ; n <- name ; sAT ; e <- expression ; sColon ; eol ; return $ nd m $ N.Place n e }
|
||||||
|
<?> "allocation"
|
||||||
|
|
||||||
|
alternation
|
||||||
|
= do { m <- md ; sALT ;
|
||||||
|
do { eol ; indent ; as <- many1 alternative ; outdent ; return $ nd m $ N.Alt as }
|
||||||
|
<|> do { r <- replicator ; eol ; indent ; a <- alternative ; outdent ; return $ nd m $ N.AltRep r a } }
|
||||||
|
<|> do { m <- md ; sPRI ; sALT ;
|
||||||
|
do { eol ; indent ; as <- many1 alternative ; outdent ; return $ nd m $ N.PriAlt as }
|
||||||
|
<|> do { r <- replicator ; eol ; indent ; a <- alternative ; outdent ; return $ nd m $ N.PriAltRep r a } }
|
||||||
|
<?> "alternation"
|
||||||
|
|
||||||
|
-- The reason the CASE guards end up here is because they have to be handled
|
||||||
|
-- specially: you can't tell until parsing the guts of the CASE what the processes
|
||||||
|
-- are.
|
||||||
|
alternative
|
||||||
|
= guardedAlternative
|
||||||
|
<|> alternation
|
||||||
|
<|> try (do { m <- md ; b <- boolean ; sAmp ; c <- channel ; sQuest ; sCASE ; eol ; indent ; vs <- many1 variant ; outdent ; return $ nd m $ N.CondGuard b (nd m $ N.In c (nd m $ N.InCase vs)) })
|
||||||
|
<|> try (do { m <- md ; c <- channel ; sQuest ; sCASE ; eol ; indent ; vs <- many1 variant ; outdent ; return $ nd m $ N.In c (nd m $ N.InCase vs) })
|
||||||
|
<|> do { m <- md ; s <- specification ; a <- alternative ; return $ nd m $ N.Decl s a }
|
||||||
|
<?> "alternative"
|
||||||
|
|
||||||
|
assignment
|
||||||
|
= do { m <- md ; vs <- variableList ; sAssign ; es <- expressionList ; eol ; return $ nd m $ N.Assign vs es }
|
||||||
|
<?> "assignment"
|
||||||
|
|
||||||
|
base
|
||||||
|
= expression
|
||||||
|
<?> "base"
|
||||||
|
|
||||||
|
boolean
|
||||||
|
= expression
|
||||||
|
<?> "boolean"
|
||||||
|
|
||||||
|
byte
|
||||||
|
= lexeme (do { m <- md ; char '\'' ; s <- character ; char '\'' ; return $ nd m $ N.LitByte s })
|
||||||
|
<?> "byte"
|
||||||
|
|
||||||
|
caseExpression
|
||||||
|
= expression
|
||||||
|
<?> "caseExpression"
|
||||||
|
|
||||||
|
caseInput
|
||||||
|
= do { m <- md ; c <- channel ; sQuest ; sCASE ; eol ; indent ; vs <- many1 variant ; outdent ; return $ nd m $ N.In c (nd m $ N.InCase vs) }
|
||||||
|
<?> "caseInput"
|
||||||
|
|
||||||
|
-- This is also used for timers and ports, since the syntax is identical (and
|
||||||
|
-- the parser really can't tell at this stage which is which).
|
||||||
|
channel
|
||||||
|
= do { m <- md ; v <- channel' ; es <- many (do { sLeft ; e <- expression ; sRight ; return e }) ; return $ foldl (\e s -> nd m $ N.Sub (nd m $ N.SubPlain s) e) v es }
|
||||||
|
<?> "channel"
|
||||||
|
|
||||||
|
channel'
|
||||||
|
= try name
|
||||||
|
<|> try (do { m <- md ; sLeft ; n <- channel ; sFROM ; e <- expression ; sFOR ; f <- expression ; sRight ; return $ nd m $ N.Sub (nd m $ N.SubFromFor e f) n })
|
||||||
|
<|> try (do { m <- md ; sLeft ; n <- channel ; sFROM ; e <- expression ; sRight ; return $ nd m $ N.Sub (nd m $ N.SubFrom e) n })
|
||||||
|
<|> do { m <- md ; sLeft ; n <- channel ; sFOR ; e <- expression ; sRight ; return $ nd m $ N.Sub (nd m $ N.SubFor e) n }
|
||||||
|
<?> "channel'"
|
||||||
|
|
||||||
|
-- FIXME should probably make CHAN INT work, since that'd be trivial...
|
||||||
|
channelType
|
||||||
|
= do { m <- md ; sCHAN ; sOF ; p <- protocol ; return $ nd m $ N.ChanOf p }
|
||||||
|
<|> try (do { m <- md ; sLeft ; s <- expression ; sRight ; t <- channelType ; return $ nd m $ N.Array s t })
|
||||||
|
<?> "channelType"
|
||||||
|
|
||||||
|
-- FIXME this isn't at all the right way to return the character!
|
||||||
|
character
|
||||||
|
= try (do { char '*' ;
|
||||||
|
do { char '#' ; a <- hexDigit ; b <- hexDigit ; return $ ['*', '#', a, b] }
|
||||||
|
<|> do { c <- anyChar ; return $ ['*', c] } })
|
||||||
|
<|> do { c <- anyChar ; return $ [c] }
|
||||||
|
<?> "character"
|
||||||
|
|
||||||
|
occamChoice
|
||||||
|
= guardedChoice
|
||||||
|
<|> conditional
|
||||||
|
<|> do { m <- md ; s <- try specification ; c <- occamChoice ; return $ nd m $ N.Decl s c }
|
||||||
|
<?> "choice"
|
||||||
|
|
||||||
|
conditional
|
||||||
|
= do { m <- md ; sIF ;
|
||||||
|
do { eol ; indent ; cs <- many1 occamChoice ; outdent ; return $ nd m $ N.If cs }
|
||||||
|
<|> do { r <- replicator ; eol ; indent ; c <- occamChoice ; outdent ; return $ nd m $ N.IfRep r c } }
|
||||||
|
<?> "conditional"
|
||||||
|
|
||||||
|
-- This uses operandNotTable to resolve the "x[y]" ambiguity.
|
||||||
|
conversion
|
||||||
|
= try (do { m <- md ; t <- dataType; do { sROUND ; o <- operand ; return $ nd m $ N.Round t o } <|> do { sTRUNC ; o <- operand ; return $ nd m $ N.Trunc t o } <|> do { o <- operandNotTable ; return $ nd m $ N.Conv t o } })
|
||||||
|
<?> "conversion"
|
||||||
|
|
||||||
|
occamCount
|
||||||
|
= expression
|
||||||
|
<?> "count"
|
||||||
|
|
||||||
|
dataType
|
||||||
|
= do { m <- md ; sBOOL ; return $ nd m $ N.Bool }
|
||||||
|
<|> do { m <- md ; sBYTE ; return $ nd m $ N.Byte }
|
||||||
|
<|> do { m <- md ; sINT ; return $ nd m $ N.Int }
|
||||||
|
<|> do { m <- md ; sINT16 ; return $ nd m $ N.Int16 }
|
||||||
|
<|> do { m <- md ; sINT32 ; return $ nd m $ N.Int32 }
|
||||||
|
<|> do { m <- md ; sINT64 ; return $ nd m $ N.Int64 }
|
||||||
|
<|> do { m <- md ; sREAL32 ; return $ nd m $ N.Real32 }
|
||||||
|
<|> do { m <- md ; sREAL64 ; return $ nd m $ N.Real64 }
|
||||||
|
<|> try (do { m <- md ; sLeft ; s <- expression ; sRight ; t <- dataType ; return $ nd m $ N.Array s t })
|
||||||
|
<|> name
|
||||||
|
<?> "data type"
|
||||||
|
|
||||||
|
declType
|
||||||
|
= dataType
|
||||||
|
<|> channelType
|
||||||
|
<|> timerType
|
||||||
|
<|> portType
|
||||||
|
|
||||||
|
-- FIXME this originally had four lines like this, one for each of the above;
|
||||||
|
-- it might be nicer to generate a different nd m $ N.Node for each type of declaration
|
||||||
|
declaration
|
||||||
|
= do { m <- md ; d <- declType ; ns <- sepBy1 name sComma ; sColon ; eol ; return $ nd m $ N.Vars d ns }
|
||||||
|
<?> "declaration"
|
||||||
|
|
||||||
|
definition
|
||||||
|
= do { m <- md ; sDATA ; sTYPE ; n <- name ;
|
||||||
|
do {sIS ; t <- dataType ; sColon ; eol ; return $ nd m $ N.DataType n t }
|
||||||
|
<|> do { eol ; indent ; t <- structuredType ; outdent ; sColon ; eol ; return $ nd m $ N.DataType n t } }
|
||||||
|
<|> do { m <- md ; sPROTOCOL ; n <- name ;
|
||||||
|
do { sIS ; p <- sequentialProtocol ; sColon ; eol ; return $ nd m $ N.Protocol n p }
|
||||||
|
<|> do { eol ; indent ; sCASE ; eol ; indent ; ps <- many1 taggedProtocol ; outdent ; outdent ; sColon ; eol ; return $ nd m $ N.TaggedProtocol n ps } }
|
||||||
|
<|> do { m <- md ; sPROC ; n <- name ; fs <- formalList ; eol ; indent ; p <- process ; outdent ; sColon ; eol ; return $ nd m $ N.Proc n fs p }
|
||||||
|
<|> try (do { m <- md ; rs <- sepBy1 dataType sComma ; (n, fs) <- functionHeader ;
|
||||||
|
do { sIS ; el <- expressionList ; sColon ; eol ; return $ nd m $ N.FuncIs n rs fs el }
|
||||||
|
<|> do { eol ; indent ; vp <- valueProcess ; outdent ; sColon ; eol ; return $ nd m $ N.Func n rs fs vp } })
|
||||||
|
<|> try (do { m <- md ; s <- specifier ; n <- name ;
|
||||||
|
do { sRETYPES ; v <- variable ; sColon ; eol ; return $ nd m $ N.Retypes s n v }
|
||||||
|
<|> do { try sRESHAPES ; v <- variable ; sColon ; eol ; return $ nd m $ N.Reshapes s n v } })
|
||||||
|
<|> do { m <- md ; sVAL ; s <- specifier ; n <- name ;
|
||||||
|
do { sRETYPES ; v <- variable ; sColon ; eol ; return $ nd m $ N.ValRetypes s n v }
|
||||||
|
<|> do { sRESHAPES ; v <- variable ; sColon ; eol ; return $ nd m $ N.ValReshapes s n v } }
|
||||||
|
<?> "definition"
|
||||||
|
|
||||||
|
digits
|
||||||
|
= many1 digit
|
||||||
|
<?> "digits"
|
||||||
|
|
||||||
|
dyadicOperator
|
||||||
|
= do { m <- md ; reservedOp "+" ; return $ nd m $ N.Add }
|
||||||
|
<|> do { m <- md ; reservedOp "-" ; return $ nd m $ N.Subtr }
|
||||||
|
<|> do { m <- md ; reservedOp "*" ; return $ nd m $ N.Mul }
|
||||||
|
<|> do { m <- md ; reservedOp "/" ; return $ nd m $ N.Div }
|
||||||
|
<|> do { m <- md ; reservedOp "\\" ; return $ nd m $ N.Rem }
|
||||||
|
<|> do { m <- md ; sREM ; return $ nd m $ N.Rem }
|
||||||
|
<|> do { m <- md ; sPLUS ; return $ nd m $ N.Plus }
|
||||||
|
<|> do { m <- md ; sMINUS ; return $ nd m $ N.Minus }
|
||||||
|
<|> do { m <- md ; sTIMES ; return $ nd m $ N.Times }
|
||||||
|
<|> do { m <- md ; reservedOp "/\\" ; return $ nd m $ N.BitAnd }
|
||||||
|
<|> do { m <- md ; reservedOp "\\/" ; return $ nd m $ N.BitOr }
|
||||||
|
<|> do { m <- md ; reservedOp "><" ; return $ nd m $ N.BitXor }
|
||||||
|
<|> do { m <- md ; sBITAND ; return $ nd m $ N.BitAnd }
|
||||||
|
<|> do { m <- md ; sBITOR ; return $ nd m $ N.BitOr }
|
||||||
|
<|> do { m <- md ; sAND ; return $ nd m $ N.And }
|
||||||
|
<|> do { m <- md ; sOR ; return $ nd m $ N.Or }
|
||||||
|
<|> do { m <- md ; reservedOp "=" ; return $ nd m $ N.Eq }
|
||||||
|
<|> do { m <- md ; reservedOp "<>" ; return $ nd m $ N.NEq }
|
||||||
|
<|> do { m <- md ; reservedOp "<" ; return $ nd m $ N.Less }
|
||||||
|
<|> do { m <- md ; reservedOp ">" ; return $ nd m $ N.More }
|
||||||
|
<|> do { m <- md ; reservedOp "<=" ; return $ nd m $ N.LessEq }
|
||||||
|
<|> do { m <- md ; reservedOp ">=" ; return $ nd m $ N.MoreEq }
|
||||||
|
<|> do { m <- md ; sAFTER ; return $ nd m $ N.After }
|
||||||
|
<?> "dyadicOperator"
|
||||||
|
|
||||||
|
occamExponent
|
||||||
|
= try (do { c <- oneOf "+-" ; d <- digits ; return $ c : d })
|
||||||
|
<?> "exponent"
|
||||||
|
|
||||||
|
expression
|
||||||
|
= try (do { m <- md ; o <- monadicOperator ; v <- operand ; return $ nd m $ N.MonadicOp o v })
|
||||||
|
<|> do { m <- md ; a <- sMOSTPOS ; t <- dataType ; return $ nd m $ N.MostPos t }
|
||||||
|
<|> do { m <- md ; a <- sMOSTNEG ; t <- dataType ; return $ nd m $ N.MostNeg t }
|
||||||
|
<|> do { m <- md ; a <- sSIZE ; t <- dataType ; return $ nd m $ N.Size t }
|
||||||
|
<|> try (do { m <- md ; a <- operand ; o <- dyadicOperator ; b <- operand ; return $ nd m $ N.DyadicOp o a b })
|
||||||
|
<|> try conversion
|
||||||
|
<|> operand
|
||||||
|
<?> "expression"
|
||||||
|
|
||||||
|
expressionList
|
||||||
|
= try (do { m <- md ; n <- name ; sLeftR ; as <- sepBy expression sComma ; sRightR ; return $ nd m $ N.Call n as })
|
||||||
|
<|> do { m <- md ; es <- sepBy1 expression sComma ; return $ nd m $ N.ExpList es }
|
||||||
|
-- XXX value process
|
||||||
|
<?> "expressionList"
|
||||||
|
|
||||||
|
fieldName
|
||||||
|
= name
|
||||||
|
<?> "fieldName"
|
||||||
|
|
||||||
|
-- This is rather different from the grammar, since I had some difficulty
|
||||||
|
-- getting Parsec to parse it as a list of lists of arguments.
|
||||||
|
formalList
|
||||||
|
= do { m <- md ; sLeftR ; fs <- sepBy formalArg sComma ; sRightR ; return $ markTypes m fs }
|
||||||
|
<?> "formalList"
|
||||||
|
where
|
||||||
|
formalArg :: Parser (Maybe N.Node, N.Node)
|
||||||
|
formalArg = try (do { m <- md ; sVAL ; s <- specifier ; n <- name ; return $ (Just (nd m $ N.Val s), n) })
|
||||||
|
<|> try (do { s <- specifier ; n <- name ; return $ (Just s, n) })
|
||||||
|
<|> try (do { n <- name ; return $ (Nothing, n) })
|
||||||
|
|
||||||
|
markTypes :: Meta -> [(Maybe N.Node, N.Node)] -> [N.Node]
|
||||||
|
markTypes _ [] = []
|
||||||
|
markTypes _ ((Nothing, _):_) = error "Formal list must start with a type"
|
||||||
|
markTypes m ((Just ft, fn):is) = markRest m ft [fn] is
|
||||||
|
|
||||||
|
markRest :: Meta -> N.Node -> [N.Node] -> [(Maybe N.Node, N.Node)] -> [N.Node]
|
||||||
|
markRest m lt ns [] = [nd m $ N.Formals lt ns]
|
||||||
|
markRest m lt ns ((Nothing, n):is) = markRest m lt (ns ++ [n]) is
|
||||||
|
markRest m lt ns ((Just t, n):is) = (markRest m lt ns []) ++ (markRest m t [n] is)
|
||||||
|
|
||||||
|
functionHeader
|
||||||
|
= do { sFUNCTION ; n <- name ; fs <- formalList ; return $ (n, fs) }
|
||||||
|
<?> "functionHeader"
|
||||||
|
|
||||||
|
guard
|
||||||
|
= try input
|
||||||
|
<|> try (do { m <- md ; b <- boolean ; sAmp ; i <- input ; return $ nd m $ N.CondGuard b i })
|
||||||
|
<|> try (do { m <- md ; b <- boolean ; sAmp ; sSKIP ; eol ; return $ nd m $ N.CondGuard b (nd m $ N.Skip) })
|
||||||
|
<?> "guard"
|
||||||
|
|
||||||
|
guardedAlternative
|
||||||
|
= do { m <- md ; g <- guard ; indent ; p <- process ; outdent ; return $ nd m $ N.Guard g p }
|
||||||
|
<?> "guardedAlternative"
|
||||||
|
|
||||||
|
guardedChoice
|
||||||
|
= do { m <- md ; b <- boolean ; eol ; indent ; p <- process ; outdent ; return $ nd m $ N.Choice b p }
|
||||||
|
<?> "guardedChoice"
|
||||||
|
|
||||||
|
hexDigits
|
||||||
|
= do { m <- md ; d <- many1 hexDigit ; return $ nd m $ N.LitHex d }
|
||||||
|
<?> "hexDigits"
|
||||||
|
|
||||||
|
input
|
||||||
|
= do m <- md
|
||||||
|
c <- channel
|
||||||
|
sQuest
|
||||||
|
(do { sCASE ; tl <- taggedList ; eol ; return $ nd m $ N.In c (nd m $ N.InTag tl) }
|
||||||
|
<|> do { sAFTER ; e <- expression ; eol ; return $ nd m $ N.In c (nd m $ N.InAfter e) }
|
||||||
|
<|> do { is <- sepBy1 inputItem sSemi ; eol ; return $ nd m $ N.In c (nd m $ N.InSimple is) })
|
||||||
|
<?> "input"
|
||||||
|
|
||||||
|
inputItem
|
||||||
|
= try (do { m <- md ; v <- variable ; sColons ; w <- variable ; return $ nd m $ N.Counted v w })
|
||||||
|
<|> variable
|
||||||
|
<?> "inputItem"
|
||||||
|
|
||||||
|
integer
|
||||||
|
= try (do { m <- md ; d <- lexeme digits ; return $ nd m $ N.LitInt d })
|
||||||
|
<|> do { char '#' ; d <- lexeme hexDigits ; return $ d }
|
||||||
|
<?> "integer"
|
||||||
|
|
||||||
|
literal
|
||||||
|
= try real
|
||||||
|
<|> try integer
|
||||||
|
<|> try byte
|
||||||
|
<|> try (do { m <- md ; v <- real ; sLeftR ; t <- dataType ; sRightR ; return $ nd m $ N.TypedLit t v })
|
||||||
|
<|> try (do { m <- md ; v <- integer ; sLeftR ; t <- dataType ; sRightR ; return $ nd m $ N.TypedLit t v })
|
||||||
|
<|> try (do { m <- md ; v <- byte ; sLeftR ; t <- dataType ; sRightR ; return $ nd m $ N.TypedLit t v })
|
||||||
|
<|> try (do { m <- md ; sTRUE ; return $ nd m $ N.True })
|
||||||
|
<|> do { m <- md ; sFALSE ; return $ nd m $ N.False }
|
||||||
|
<?> "literal"
|
||||||
|
|
||||||
|
loop
|
||||||
|
= do { m <- md ; sWHILE ; b <- boolean ; eol ; indent ; p <- process ; outdent ; return $ nd m $ N.While b p }
|
||||||
|
|
||||||
|
monadicOperator
|
||||||
|
= do { m <- md ; reservedOp "-" ; return $ nd m $ N.MonSub }
|
||||||
|
<|> do { m <- md ; sMINUS ; return $ nd m $ N.MonSub }
|
||||||
|
<|> do { m <- md ; reservedOp "~" ; return $ nd m $ N.MonBitNot }
|
||||||
|
<|> do { m <- md ; sBITNOT ; return $ nd m $ N.MonBitNot }
|
||||||
|
<|> do { m <- md ; sNOT ; return $ nd m $ N.MonNot }
|
||||||
|
<|> do { m <- md ; sSIZE ; return $ nd m $ N.MonSize }
|
||||||
|
<?> "monadicOperator"
|
||||||
|
|
||||||
|
name
|
||||||
|
= do { m <- md ; s <- identifier ; return $ nd m $ N.Name s }
|
||||||
|
<?> "name"
|
||||||
|
|
||||||
|
occamString
|
||||||
|
= lexeme (do { m <- md ; char '"' ; s <- many (noneOf "\"") ; char '"' ; return $ nd m $ N.LitString s })
|
||||||
|
<?> "string"
|
||||||
|
|
||||||
|
operandNotTable
|
||||||
|
= do { m <- md ; v <- operandNotTable' ; es <- many (do { sLeft ; e <- expression ; sRight ; return e }) ; return $ foldl (\e s -> nd m $ N.Sub (nd m $ N.SubPlain s) e) v es }
|
||||||
|
<?> "operandNotTable"
|
||||||
|
|
||||||
|
operandNotTable'
|
||||||
|
= try variable
|
||||||
|
<|> try literal
|
||||||
|
<|> try (do { sLeftR ; e <- expression ; sRightR ; return e })
|
||||||
|
-- XXX value process
|
||||||
|
<|> try (do { m <- md ; n <- name ; sLeftR ; as <- sepBy expression sComma ; sRightR ; return $ nd m $ N.Call n as })
|
||||||
|
<|> try (do { m <- md ; sBYTESIN ; sLeftR ; o <- operand ; sRightR ; return $ nd m $ N.BytesIn o })
|
||||||
|
<|> try (do { m <- md ; sBYTESIN ; sLeftR ; o <- dataType ; sRightR ; return $ nd m $ N.BytesIn o })
|
||||||
|
<|> try (do { m <- md ; sOFFSETOF ; sLeftR ; n <- name ; sComma ; f <- fieldName ; sRightR ; return $ nd m $ N.OffsetOf n f })
|
||||||
|
<?> "operandNotTable'"
|
||||||
|
|
||||||
|
operand
|
||||||
|
= do { m <- md ; v <- operand' ; es <- many (do { sLeft ; e <- expression ; sRight ; return e }) ; return $ foldl (\e s -> nd m $ N.Sub (nd m $ N.SubPlain s) e) v es }
|
||||||
|
<?> "operand"
|
||||||
|
|
||||||
|
operand'
|
||||||
|
= try table
|
||||||
|
<|> operandNotTable'
|
||||||
|
<?> "operand'"
|
||||||
|
|
||||||
|
occamOption
|
||||||
|
= try (do { m <- md ; ces <- sepBy caseExpression sComma ; eol ; indent ; p <- process ; outdent ; return $ nd m $ N.CaseExps ces p })
|
||||||
|
<|> try (do { m <- md ; sELSE ; eol ; indent ; p <- process ; outdent ; return $ nd m $ N.Else p })
|
||||||
|
<|> do { m <- md ; s <- specification ; o <- occamOption ; return $ nd m $ N.Decl s o }
|
||||||
|
<?> "option"
|
||||||
|
|
||||||
|
-- XXX This can't tell at parse time in "c ! x; y" whether x is a variable or a tag...
|
||||||
|
-- ... so this now wants "c ! CASE x" if it's a tag, to match input.
|
||||||
|
-- We can fix this with a pass later...
|
||||||
|
output
|
||||||
|
= do m <- md
|
||||||
|
c <- channel
|
||||||
|
sBang
|
||||||
|
(do { sCASE ; t <- tag ; sSemi ; os <- sepBy1 outputItem sSemi ; eol ; return $ nd m $ N.OutCase c t os }
|
||||||
|
<|> do { sCASE ; t <- tag ; eol ; return $ nd m $ N.OutCase c t [] }
|
||||||
|
<|> do { os <- sepBy1 outputItem sSemi ; eol ; return $ nd m $ N.Out c os })
|
||||||
|
<?> "output"
|
||||||
|
|
||||||
|
outputItem
|
||||||
|
= try (do { m <- md ; a <- expression ; sColons ; b <- expression ; return $ nd m $ N.Counted a b })
|
||||||
|
<|> expression
|
||||||
|
<?> "outputItem"
|
||||||
|
|
||||||
|
parallel
|
||||||
|
= do { m <- md ; sPAR ; do { eol ; indent ; ps <- many1 process ; outdent ; return $ nd m $ N.Par ps } <|> do { r <- replicator ; eol ; indent ; p <- process ; outdent ; return $ nd m $ N.ParRep r p } }
|
||||||
|
<|> do { m <- md ; sPRI ; sPAR ; do { eol ; indent ; ps <- many1 process ; outdent ; return $ nd m $ N.PriPar ps } <|> do { r <- replicator ; eol ; indent ; p <- process ; outdent ; return $ nd m $ N.PriParRep r p } }
|
||||||
|
<|> placedpar
|
||||||
|
<?> "parallel"
|
||||||
|
|
||||||
|
-- XXX PROCESSOR as a process isn't really legal, surely?
|
||||||
|
placedpar
|
||||||
|
= do { m <- md ; sPLACED ; sPAR ; do { eol ; indent ; ps <- many1 placedpar ; outdent ; return $ nd m $ N.PlacedPar ps } <|> do { r <- replicator ; eol ; indent ; p <- placedpar ; outdent ; return $ nd m $ N.PlacedParRep r p } }
|
||||||
|
<|> do { m <- md ; sPROCESSOR ; e <- expression ; eol ; indent ; p <- process ; outdent ; return $ nd m $ N.Processor e p }
|
||||||
|
<?> "placedpar"
|
||||||
|
|
||||||
|
portType
|
||||||
|
= do { m <- md ; sPORT ; sOF ; p <- protocol ; return $ nd m $ N.PortOf p }
|
||||||
|
<|> do { m <- md ; try sLeft ; s <- try expression ; try sRight ; t <- portType ; return $ nd m $ N.Array s t }
|
||||||
|
<?> "portType"
|
||||||
|
|
||||||
|
procInstance
|
||||||
|
= do { m <- md ; n <- name ; sLeftR ; as <- sepBy actual sComma ; sRightR ; eol ; return $ nd m $ N.ProcCall n as }
|
||||||
|
<?> "procInstance"
|
||||||
|
|
||||||
|
process
|
||||||
|
= try assignment
|
||||||
|
<|> try input
|
||||||
|
<|> try output
|
||||||
|
<|> do { m <- md ; sSKIP ; eol ; return $ nd m $ N.Skip }
|
||||||
|
<|> do { m <- md ; sSTOP ; eol ; return $ nd m $ N.Stop }
|
||||||
|
<|> occamSequence
|
||||||
|
<|> conditional
|
||||||
|
<|> selection
|
||||||
|
<|> loop
|
||||||
|
<|> try parallel
|
||||||
|
<|> alternation
|
||||||
|
<|> try caseInput
|
||||||
|
<|> try procInstance
|
||||||
|
<|> do { m <- md ; sMainMarker ; eol ; return $ nd m $ N.MainProcess }
|
||||||
|
<|> do { m <- md ; a <- allocation ; p <- process ; return $ nd m $ N.Decl a p }
|
||||||
|
<|> do { m <- md ; s <- specification ; p <- process ; return $ nd m $ N.Decl s p }
|
||||||
|
<?> "process"
|
||||||
|
|
||||||
|
protocol
|
||||||
|
= try name
|
||||||
|
<|> simpleProtocol
|
||||||
|
<?> "protocol"
|
||||||
|
|
||||||
|
real
|
||||||
|
= try (do { m <- md ; l <- digits ; char '.' ; r <- digits ; char 'e' ; e <- lexeme occamExponent ; return $ nd m $ N.LitReal (l ++ "." ++ r ++ "e" ++ e) })
|
||||||
|
<|> do { m <- md ; l <- digits ; char '.' ; r <- lexeme digits ; return $ nd m $ N.LitReal (l ++ "." ++ r) }
|
||||||
|
<?> "real"
|
||||||
|
|
||||||
|
replicator
|
||||||
|
= do { m <- md ; n <- name ; sEq ; b <- base ; sFOR ; c <- occamCount ; return $ nd m $ N.For n b c }
|
||||||
|
<?> "replicator"
|
||||||
|
|
||||||
|
selection
|
||||||
|
= do { m <- md ; sCASE ; s <- selector ; eol ; indent ; os <- many1 occamOption ; outdent ; return $ nd m $ N.Case s os }
|
||||||
|
<?> "selection"
|
||||||
|
|
||||||
|
selector
|
||||||
|
= expression
|
||||||
|
<?> "selector"
|
||||||
|
|
||||||
|
occamSequence
|
||||||
|
= do m <- md
|
||||||
|
sSEQ
|
||||||
|
(do { eol ; indent ; ps <- many1 process ; outdent ; return $ nd m $ N.Seq ps }
|
||||||
|
<|> do { r <- replicator ; eol ; indent ; p <- process ; outdent ; return $ nd m $ N.SeqRep r p })
|
||||||
|
<?> "sequence"
|
||||||
|
|
||||||
|
sequentialProtocol
|
||||||
|
= do { l <- try $ sepBy1 simpleProtocol sSemi ; return $ l }
|
||||||
|
<?> "sequentialProtocol"
|
||||||
|
|
||||||
|
simpleProtocol
|
||||||
|
= try (do { m <- md ; l <- dataType ; sColons ; sLeft ; sRight ; r <- dataType ; return $ nd m $ N.Counted l r })
|
||||||
|
<|> dataType
|
||||||
|
<|> do { m <- md ; sANY ; return $ nd m $ N.Any }
|
||||||
|
<?> "simpleProtocol"
|
||||||
|
|
||||||
|
specification
|
||||||
|
= try declaration
|
||||||
|
<|> try abbreviation
|
||||||
|
<|> definition
|
||||||
|
<?> "specification"
|
||||||
|
|
||||||
|
specifier
|
||||||
|
= try dataType
|
||||||
|
<|> try channelType
|
||||||
|
<|> try timerType
|
||||||
|
<|> try portType
|
||||||
|
<|> try (do { m <- md ; sLeft ; sRight ; s <- specifier ; return $ nd m $ N.ArrayUnsized s })
|
||||||
|
<|> do { m <- md ; sLeft ; e <- expression ; sRight ; s <- specifier ; return $ nd m $ N.Array e s }
|
||||||
|
<?> "specifier"
|
||||||
|
|
||||||
|
structuredType
|
||||||
|
= try (do { m <- md ; sRECORD ; eol ; indent ; fs <- many1 structuredTypeField ; outdent ; return $ nd m $ N.Record fs })
|
||||||
|
<|> do { m <- md ; sPACKED ; sRECORD ; eol ; indent ; fs <- many1 structuredTypeField ; outdent ; return $ nd m $ N.PackedRecord fs }
|
||||||
|
<?> "structuredType"
|
||||||
|
|
||||||
|
-- FIXME this should use the same type-folding code as proc/func definitions
|
||||||
|
structuredTypeField
|
||||||
|
= do { m <- md ; t <- dataType ; fs <- many1 fieldName ; sColon ; eol ; return $ nd m $ N.Fields t fs }
|
||||||
|
<?> "structuredTypeField"
|
||||||
|
|
||||||
|
-- i.e. array literal
|
||||||
|
table
|
||||||
|
= do { m <- md ; v <- table' ; es <- many (do { sLeft ; e <- expression ; sRight ; return e }) ; return $ foldl (\e s -> nd m $ N.Sub (nd m $ N.SubPlain s) e) v es }
|
||||||
|
<?> "table"
|
||||||
|
|
||||||
|
table'
|
||||||
|
= try occamString
|
||||||
|
<|> try (do { m <- md ; s <- occamString ; sLeftR ; n <- name ; sRightR ; return $ nd m $ N.TypedLit n s })
|
||||||
|
<|> do { sLeft ;
|
||||||
|
try (do { m <- md ; es <- sepBy1 expression sComma ; sRight ; return $ nd m $ N.LitArray es })
|
||||||
|
<|> try (do { m <- md ; n <- table ; sFROM ; e <- expression ; sFOR ; f <- expression ; sRight ; return $ nd m $ N.Sub (nd m $ N.SubFromFor e f) n })
|
||||||
|
<|> try (do { m <- md ; n <- table ; sFROM ; e <- expression ; sRight ; return $ nd m $ N.Sub (nd m $ N.SubFrom e) n })
|
||||||
|
<|> do { m <- md ; n <- table ; sFOR ; e <- expression ; sRight ; return $ nd m $ N.Sub (nd m $ N.SubFor e) n } }
|
||||||
|
<?> "table'"
|
||||||
|
|
||||||
|
tag
|
||||||
|
= name
|
||||||
|
<?> "tag"
|
||||||
|
|
||||||
|
taggedList
|
||||||
|
= try (do { m <- md ; t <- tag ; sSemi ; is <- sepBy1 inputItem sSemi ; return $ nd m $ N.Tag t is })
|
||||||
|
<|> do { m <- md ; t <- tag ; return $ nd m $ N.Tag t [] }
|
||||||
|
<?> "taggedList"
|
||||||
|
|
||||||
|
taggedProtocol
|
||||||
|
= try (do { m <- md ; t <- tag ; eol ; return $ nd m $ N.Tag t [] })
|
||||||
|
<|> try (do { m <- md ; t <- tag ; sSemi ; sp <- sequentialProtocol ; eol ; return $ nd m $ N.Tag t sp })
|
||||||
|
|
||||||
|
timerType
|
||||||
|
= do { m <- md ; sTIMER ; return $ nd m $ N.Timer }
|
||||||
|
<|> do { m <- md ; try sLeft ; s <- try expression ; try sRight ; t <- timerType ; return $ nd m $ N.Array s t }
|
||||||
|
<?> "timerType"
|
||||||
|
|
||||||
|
valueProcess
|
||||||
|
= try (do { m <- md ; sVALOF ; eol ; indent ; p <- process ; sRESULT ; el <- expressionList ; eol ; outdent ; return $ nd m $ N.ValOf p el })
|
||||||
|
<|> do { m <- md ; s <- specification ; v <- valueProcess ; return $ nd m $ N.Decl s v }
|
||||||
|
|
||||||
|
variable
|
||||||
|
= do { m <- md ; v <- variable' ; es <- many (do { sLeft ; e <- expression ; sRight ; return e }) ; return $ foldl (\e s -> nd m $ N.Sub (nd m $ N.SubPlain s) e) v es }
|
||||||
|
<?> "variable"
|
||||||
|
|
||||||
|
variable'
|
||||||
|
= try name
|
||||||
|
<|> try (do { m <- md ; sLeft ; n <- variable ; sFROM ; e <- expression ; sFOR ; f <- expression ; sRight ; return $ nd m $ N.Sub (nd m $ N.SubFromFor e f) n })
|
||||||
|
<|> try (do { m <- md ; sLeft ; n <- variable ; sFROM ; e <- expression ; sRight ; return $ nd m $ N.Sub (nd m $ N.SubFrom e) n })
|
||||||
|
<|> do { m <- md ; sLeft ; n <- variable ; sFOR ; e <- expression ; sRight ; return $ nd m $ N.Sub (nd m $ N.SubFor e) n }
|
||||||
|
<?> "variable'"
|
||||||
|
|
||||||
|
variableList
|
||||||
|
= do { vs <- sepBy1 variable sComma ; return $ vs }
|
||||||
|
<?> "variableList"
|
||||||
|
|
||||||
|
variant
|
||||||
|
= try (do { m <- md ; t <- taggedList ; eol ; indent ; p <- process ; outdent ; return $ nd m $ N.Variant t p })
|
||||||
|
<|> do { m <- md ; s <- specification ; v <- variant ; return $ nd m $ N.Decl s v }
|
||||||
|
<?> "variant"
|
||||||
|
|
||||||
|
-- -------------------------------------------------------------
|
||||||
|
|
||||||
|
-- This is only really true once we've tacked a process onto the bottom; a
|
||||||
|
-- source file is really a series of specifications, but the later ones need to
|
||||||
|
-- have the earlier ones in scope, so we can't parse them separately.
|
||||||
|
|
||||||
|
sourceFile = do { whiteSpace ; process }
|
||||||
|
|
||||||
|
-- -------------------------------------------------------------
|
||||||
|
|
||||||
|
-- XXX this doesn't handle multi-line strings
|
||||||
|
-- XXX or VALOF processes
|
||||||
|
|
||||||
|
countIndent :: String -> Int
|
||||||
|
countIndent (' ':' ':cs) = 1 + (countIndent cs)
|
||||||
|
countIndent (' ':cs) = error "Bad indentation"
|
||||||
|
countIndent _ = 0
|
||||||
|
|
||||||
|
stripIndent :: String -> String
|
||||||
|
stripIndent (' ':cs) = stripIndent cs
|
||||||
|
stripIndent cs = cs
|
||||||
|
|
||||||
|
stripComment :: String -> String
|
||||||
|
stripComment [] = []
|
||||||
|
stripComment ('-':'-':s) = []
|
||||||
|
stripComment ('"':s) = '"' : stripCommentInString s
|
||||||
|
stripComment (c:s) = c : stripComment s
|
||||||
|
|
||||||
|
stripCommentInString :: String -> String
|
||||||
|
stripCommentInString [] = error "In string at end of line"
|
||||||
|
stripCommentInString ('"':s) = '"' : stripComment s
|
||||||
|
stripCommentInString (c:s) = c : stripCommentInString s
|
||||||
|
|
||||||
|
flatten :: [String] -> String
|
||||||
|
flatten ls = concat $ intersperse "\n" $ flatten' ls 0
|
||||||
|
where
|
||||||
|
rep n i = take n (repeat i)
|
||||||
|
flatten' [] level = [rep level '}']
|
||||||
|
flatten' (s:ss) level
|
||||||
|
| stripped == "" = "" : flatten' ss level
|
||||||
|
| newLevel > level = (rep (newLevel - level) '{' ++ stripped) : rest
|
||||||
|
| newLevel < level = (rep (level - newLevel) '}' ++ stripped) : rest
|
||||||
|
| otherwise = stripped : rest
|
||||||
|
where newLevel = countIndent s
|
||||||
|
stripped' = stripComment s
|
||||||
|
stripped = if stripIndent stripped' == "" then "" else (stripped' ++ "@")
|
||||||
|
rest = flatten' ss newLevel
|
||||||
|
|
||||||
|
-- -------------------------------------------------------------
|
||||||
|
|
||||||
|
-- XXX Doesn't handle preprocessor instructions.
|
||||||
|
|
||||||
|
preprocess :: String -> String
|
||||||
|
preprocess d = flatten $ lines (d ++ "\n" ++ mainMarker)
|
||||||
|
|
||||||
|
readSource :: String -> IO String
|
||||||
|
readSource fn = do
|
||||||
|
f <- IO.openFile fn IO.ReadMode
|
||||||
|
d <- IO.hGetContents f
|
||||||
|
let prep = preprocess d
|
||||||
|
return prep
|
||||||
|
|
||||||
|
-- -------------------------------------------------------------
|
||||||
|
|
||||||
|
parseSource :: String -> String -> N.Node
|
||||||
|
parseSource prep sourceFileName
|
||||||
|
= case (parse sourceFile sourceFileName prep) of
|
||||||
|
Left err -> error ("Parsing error: " ++ (show err))
|
||||||
|
Right defs -> defs
|
||||||
|
|
49
fco2/PrettyShow.hs
Normal file
49
fco2/PrettyShow.hs
Normal file
|
@ -0,0 +1,49 @@
|
||||||
|
-- A generic show implementation that pretty-prints expressions
|
||||||
|
-- This ought to use a class (like show does), so that it can be extended
|
||||||
|
-- properly without me needing to have FCO-specific cases in here -- see the
|
||||||
|
-- appropriate SYB paper.
|
||||||
|
|
||||||
|
module PrettyShow (pshow) where
|
||||||
|
|
||||||
|
import Data.Generics
|
||||||
|
import Text.PrettyPrint.HughesPJ
|
||||||
|
import Metadata
|
||||||
|
|
||||||
|
-- This is ugly -- but it looks like you can't easily define a generic function
|
||||||
|
-- even for a single tuple type, since it has to parameterise over multiple Data
|
||||||
|
-- types...
|
||||||
|
isTupleCtr :: String -> Bool
|
||||||
|
isTupleCtr ('(':cs) = checkRest cs
|
||||||
|
where
|
||||||
|
checkRest ",)" = True
|
||||||
|
checkRest (',':cs) = checkRest cs
|
||||||
|
checkRest _ = False
|
||||||
|
isTupleCtr _ = False
|
||||||
|
|
||||||
|
doGeneral :: Data a => a -> Doc
|
||||||
|
doGeneral t =
|
||||||
|
if isTupleCtr cn then
|
||||||
|
parens $ sep $ punctuate (text ",") l
|
||||||
|
else case l of
|
||||||
|
[] -> con
|
||||||
|
otherwise -> parens $ sep (con : l)
|
||||||
|
where
|
||||||
|
cn = showConstr (toConstr t)
|
||||||
|
con = text $ cn
|
||||||
|
l = gmapQ doAny t
|
||||||
|
|
||||||
|
doList :: Data a => [a] -> Doc
|
||||||
|
doList t = brackets $ sep $ punctuate (text ",") (map doAny t)
|
||||||
|
|
||||||
|
doString :: String -> Doc
|
||||||
|
doString s = text $ show s
|
||||||
|
|
||||||
|
doMeta :: Meta -> Doc
|
||||||
|
doMeta m = text $ formatSourcePos m
|
||||||
|
|
||||||
|
doAny :: Data a => a -> Doc
|
||||||
|
doAny = doGeneral `ext1Q` doList `extQ` doString `extQ` doMeta
|
||||||
|
|
||||||
|
pshow :: Data a => a -> String
|
||||||
|
pshow x = render $ doAny x
|
||||||
|
|
Loading…
Reference in New Issue
Block a user