Added gfcc2c to GF repo.

This commit is contained in:
bringert
2006-12-22 13:43:32 +00:00
parent a335b29c0a
commit 7abd4c00a2
15 changed files with 2603 additions and 0 deletions

View File

@@ -49,6 +49,20 @@ Use <tt>pg -printer=vxml</tt>.
generated from a multilingual GF grammar. Use <tt>pm -printer=js</tt>.
<p>
5/12 (BB) A new tool for generating C linearization libraries
from a GFCC file. <tt>make gfcc2c</tt> in <tt>src</tt>
compiles the tool. The generated
code includes header files in <tt>lib/c</tt> and should be linked
against <tt>libgfcc.a</tt> in <tt>lib/c</tt>. For an example of
using the generated code, see <tt>src/tools/c/examples/bronzeage</tt>.
<tt>make</tt> in that directory generates a GFCC file, then generates
C code from that, and then compiles a program <tt>bronzeage-test</tt>.
The <tt>main</tt> function for that program is defined in
<tt>bronzeage-test.c</tt>.
<p>
20/11 (AR) Type error messages in concrete syntax are printed with a

View File

@@ -112,6 +112,9 @@ clean:
-rm -f $(GFEDITOR)/de/uka/ilkd/key/ocl/gf/*.class
-rm -f gf.wixobj
-rm -f ../bin/$(GF_EXE)
$(MAKE) -C tools/c clean
$(MAKE) -C ../lib/c clean
-rm -f ../bin/gfcc2c
distclean: clean
-rm -f JavaGUI/gf-java.jar jgf
@@ -182,6 +185,12 @@ gfcc:
$(GHMAKE) $(GHCOPTFLAGS) -o gfcc GF/Canon/GFCC/RunGFCC.hs
strip gfcc
mv gfcc ../bin/
gfcc2c:
$(MAKE) -C tools/c
$(MAKE) -C ../lib/c
mv tools/c/gfcc2c ../bin
#
# Distribution
#

227
src/tools/c/GFCC/Abs.hs Normal file
View File

@@ -0,0 +1,227 @@
{-# OPTIONS_GHC -fglasgow-exts #-}
module GFCC.Abs (Tree(..), Grammar, Header, Abstract, Concrete, AbsDef, CncDef, Type, Exp, Atom, Term, Tokn, Variant, CId, johnMajorEq, module GFCC.ComposOp) where
import GFCC.ComposOp
import Data.Monoid
-- Haskell module generated by the BNF converter
data Grammar_
type Grammar = Tree Grammar_
data Header_
type Header = Tree Header_
data Abstract_
type Abstract = Tree Abstract_
data Concrete_
type Concrete = Tree Concrete_
data AbsDef_
type AbsDef = Tree AbsDef_
data CncDef_
type CncDef = Tree CncDef_
data Type_
type Type = Tree Type_
data Exp_
type Exp = Tree Exp_
data Atom_
type Atom = Tree Atom_
data Term_
type Term = Tree Term_
data Tokn_
type Tokn = Tree Tokn_
data Variant_
type Variant = Tree Variant_
data CId_
type CId = Tree CId_
data Tree :: * -> * where
Grm :: Header -> Abstract -> [Concrete] -> Tree Grammar_
Hdr :: CId -> [CId] -> Tree Header_
Abs :: [AbsDef] -> Tree Abstract_
Cnc :: CId -> [CncDef] -> Tree Concrete_
Fun :: CId -> Type -> Exp -> Tree AbsDef_
Lin :: CId -> Term -> Tree CncDef_
Typ :: [CId] -> CId -> Tree Type_
Tr :: Atom -> [Exp] -> Tree Exp_
AC :: CId -> Tree Atom_
AS :: String -> Tree Atom_
AI :: Integer -> Tree Atom_
AF :: Double -> Tree Atom_
AM :: Tree Atom_
R :: [Term] -> Tree Term_
P :: Term -> Term -> Tree Term_
S :: [Term] -> Tree Term_
K :: Tokn -> Tree Term_
V :: Integer -> Tree Term_
C :: Integer -> Tree Term_
F :: CId -> Tree Term_
FV :: [Term] -> Tree Term_
W :: String -> Term -> Tree Term_
RP :: Term -> Term -> Tree Term_
TM :: Tree Term_
L :: CId -> Term -> Tree Term_
BV :: CId -> Tree Term_
KS :: String -> Tree Tokn_
KP :: [String] -> [Variant] -> Tree Tokn_
Var :: [String] -> [String] -> Tree Variant_
CId :: String -> Tree CId_
instance Compos Tree where
compos r a f t = case t of
Grm header abstract concretes -> r Grm `a` f header `a` f abstract `a` foldr (a . a (r (:)) . f) (r []) concretes
Hdr cid cids -> r Hdr `a` f cid `a` foldr (a . a (r (:)) . f) (r []) cids
Abs absdefs -> r Abs `a` foldr (a . a (r (:)) . f) (r []) absdefs
Cnc cid cncdefs -> r Cnc `a` f cid `a` foldr (a . a (r (:)) . f) (r []) cncdefs
Fun cid type' exp -> r Fun `a` f cid `a` f type' `a` f exp
Lin cid term -> r Lin `a` f cid `a` f term
Typ cids cid -> r Typ `a` foldr (a . a (r (:)) . f) (r []) cids `a` f cid
Tr atom exps -> r Tr `a` f atom `a` foldr (a . a (r (:)) . f) (r []) exps
AC cid -> r AC `a` f cid
R terms -> r R `a` foldr (a . a (r (:)) . f) (r []) terms
P term0 term1 -> r P `a` f term0 `a` f term1
S terms -> r S `a` foldr (a . a (r (:)) . f) (r []) terms
K tokn -> r K `a` f tokn
F cid -> r F `a` f cid
FV terms -> r FV `a` foldr (a . a (r (:)) . f) (r []) terms
W str term -> r W `a` r str `a` f term
RP term0 term1 -> r RP `a` f term0 `a` f term1
L cid term -> r L `a` f cid `a` f term
BV cid -> r BV `a` f cid
KP strs variants -> r KP `a` r strs `a` foldr (a . a (r (:)) . f) (r []) variants
_ -> r t
instance Show (Tree c) where
showsPrec n t = case t of
Grm header abstract concretes -> opar n . showString "Grm" . showChar ' ' . showsPrec 1 header . showChar ' ' . showsPrec 1 abstract . showChar ' ' . showsPrec 1 concretes . cpar n
Hdr cid cids -> opar n . showString "Hdr" . showChar ' ' . showsPrec 1 cid . showChar ' ' . showsPrec 1 cids . cpar n
Abs absdefs -> opar n . showString "Abs" . showChar ' ' . showsPrec 1 absdefs . cpar n
Cnc cid cncdefs -> opar n . showString "Cnc" . showChar ' ' . showsPrec 1 cid . showChar ' ' . showsPrec 1 cncdefs . cpar n
Fun cid type' exp -> opar n . showString "Fun" . showChar ' ' . showsPrec 1 cid . showChar ' ' . showsPrec 1 type' . showChar ' ' . showsPrec 1 exp . cpar n
Lin cid term -> opar n . showString "Lin" . showChar ' ' . showsPrec 1 cid . showChar ' ' . showsPrec 1 term . cpar n
Typ cids cid -> opar n . showString "Typ" . showChar ' ' . showsPrec 1 cids . showChar ' ' . showsPrec 1 cid . cpar n
Tr atom exps -> opar n . showString "Tr" . showChar ' ' . showsPrec 1 atom . showChar ' ' . showsPrec 1 exps . cpar n
AC cid -> opar n . showString "AC" . showChar ' ' . showsPrec 1 cid . cpar n
AS str -> opar n . showString "AS" . showChar ' ' . showsPrec 1 str . cpar n
AI n -> opar n . showString "AI" . showChar ' ' . showsPrec 1 n . cpar n
AF d -> opar n . showString "AF" . showChar ' ' . showsPrec 1 d . cpar n
AM -> showString "AM"
R terms -> opar n . showString "R" . showChar ' ' . showsPrec 1 terms . cpar n
P term0 term1 -> opar n . showString "P" . showChar ' ' . showsPrec 1 term0 . showChar ' ' . showsPrec 1 term1 . cpar n
S terms -> opar n . showString "S" . showChar ' ' . showsPrec 1 terms . cpar n
K tokn -> opar n . showString "K" . showChar ' ' . showsPrec 1 tokn . cpar n
V n -> opar n . showString "V" . showChar ' ' . showsPrec 1 n . cpar n
C n -> opar n . showString "C" . showChar ' ' . showsPrec 1 n . cpar n
F cid -> opar n . showString "F" . showChar ' ' . showsPrec 1 cid . cpar n
FV terms -> opar n . showString "FV" . showChar ' ' . showsPrec 1 terms . cpar n
W str term -> opar n . showString "W" . showChar ' ' . showsPrec 1 str . showChar ' ' . showsPrec 1 term . cpar n
RP term0 term1 -> opar n . showString "RP" . showChar ' ' . showsPrec 1 term0 . showChar ' ' . showsPrec 1 term1 . cpar n
TM -> showString "TM"
L cid term -> opar n . showString "L" . showChar ' ' . showsPrec 1 cid . showChar ' ' . showsPrec 1 term . cpar n
BV cid -> opar n . showString "BV" . showChar ' ' . showsPrec 1 cid . cpar n
KS str -> opar n . showString "KS" . showChar ' ' . showsPrec 1 str . cpar n
KP strs variants -> opar n . showString "KP" . showChar ' ' . showsPrec 1 strs . showChar ' ' . showsPrec 1 variants . cpar n
Var strs0 strs1 -> opar n . showString "Var" . showChar ' ' . showsPrec 1 strs0 . showChar ' ' . showsPrec 1 strs1 . cpar n
CId str -> opar n . showString "CId" . showChar ' ' . showsPrec 1 str . cpar n
where opar n = if n > 0 then showChar '(' else id
cpar n = if n > 0 then showChar ')' else id
instance Eq (Tree c) where (==) = johnMajorEq
johnMajorEq :: Tree a -> Tree b -> Bool
johnMajorEq (Grm header abstract concretes) (Grm header_ abstract_ concretes_) = header == header_ && abstract == abstract_ && concretes == concretes_
johnMajorEq (Hdr cid cids) (Hdr cid_ cids_) = cid == cid_ && cids == cids_
johnMajorEq (Abs absdefs) (Abs absdefs_) = absdefs == absdefs_
johnMajorEq (Cnc cid cncdefs) (Cnc cid_ cncdefs_) = cid == cid_ && cncdefs == cncdefs_
johnMajorEq (Fun cid type' exp) (Fun cid_ type'_ exp_) = cid == cid_ && type' == type'_ && exp == exp_
johnMajorEq (Lin cid term) (Lin cid_ term_) = cid == cid_ && term == term_
johnMajorEq (Typ cids cid) (Typ cids_ cid_) = cids == cids_ && cid == cid_
johnMajorEq (Tr atom exps) (Tr atom_ exps_) = atom == atom_ && exps == exps_
johnMajorEq (AC cid) (AC cid_) = cid == cid_
johnMajorEq (AS str) (AS str_) = str == str_
johnMajorEq (AI n) (AI n_) = n == n_
johnMajorEq (AF d) (AF d_) = d == d_
johnMajorEq AM AM = True
johnMajorEq (R terms) (R terms_) = terms == terms_
johnMajorEq (P term0 term1) (P term0_ term1_) = term0 == term0_ && term1 == term1_
johnMajorEq (S terms) (S terms_) = terms == terms_
johnMajorEq (K tokn) (K tokn_) = tokn == tokn_
johnMajorEq (V n) (V n_) = n == n_
johnMajorEq (C n) (C n_) = n == n_
johnMajorEq (F cid) (F cid_) = cid == cid_
johnMajorEq (FV terms) (FV terms_) = terms == terms_
johnMajorEq (W str term) (W str_ term_) = str == str_ && term == term_
johnMajorEq (RP term0 term1) (RP term0_ term1_) = term0 == term0_ && term1 == term1_
johnMajorEq TM TM = True
johnMajorEq (L cid term) (L cid_ term_) = cid == cid_ && term == term_
johnMajorEq (BV cid) (BV cid_) = cid == cid_
johnMajorEq (KS str) (KS str_) = str == str_
johnMajorEq (KP strs variants) (KP strs_ variants_) = strs == strs_ && variants == variants_
johnMajorEq (Var strs0 strs1) (Var strs0_ strs1_) = strs0 == strs0_ && strs1 == strs1_
johnMajorEq (CId str) (CId str_) = str == str_
johnMajorEq _ _ = False
instance Ord (Tree c) where
compare x y = compare (index x) (index y) `mappend` compareSame x y
index :: Tree c -> Int
index (Grm _ _ _) = 0
index (Hdr _ _) = 1
index (Abs _) = 2
index (Cnc _ _) = 3
index (Fun _ _ _) = 4
index (Lin _ _) = 5
index (Typ _ _) = 6
index (Tr _ _) = 7
index (AC _) = 8
index (AS _) = 9
index (AI _) = 10
index (AF _) = 11
index (AM ) = 12
index (R _) = 13
index (P _ _) = 14
index (S _) = 15
index (K _) = 16
index (V _) = 17
index (C _) = 18
index (F _) = 19
index (FV _) = 20
index (W _ _) = 21
index (RP _ _) = 22
index (TM ) = 23
index (L _ _) = 24
index (BV _) = 25
index (KS _) = 26
index (KP _ _) = 27
index (Var _ _) = 28
index (CId _) = 29
compareSame :: Tree c -> Tree c -> Ordering
compareSame (Grm header abstract concretes) (Grm header_ abstract_ concretes_) = mappend (compare header header_) (mappend (compare abstract abstract_) (compare concretes concretes_))
compareSame (Hdr cid cids) (Hdr cid_ cids_) = mappend (compare cid cid_) (compare cids cids_)
compareSame (Abs absdefs) (Abs absdefs_) = compare absdefs absdefs_
compareSame (Cnc cid cncdefs) (Cnc cid_ cncdefs_) = mappend (compare cid cid_) (compare cncdefs cncdefs_)
compareSame (Fun cid type' exp) (Fun cid_ type'_ exp_) = mappend (compare cid cid_) (mappend (compare type' type'_) (compare exp exp_))
compareSame (Lin cid term) (Lin cid_ term_) = mappend (compare cid cid_) (compare term term_)
compareSame (Typ cids cid) (Typ cids_ cid_) = mappend (compare cids cids_) (compare cid cid_)
compareSame (Tr atom exps) (Tr atom_ exps_) = mappend (compare atom atom_) (compare exps exps_)
compareSame (AC cid) (AC cid_) = compare cid cid_
compareSame (AS str) (AS str_) = compare str str_
compareSame (AI n) (AI n_) = compare n n_
compareSame (AF d) (AF d_) = compare d d_
compareSame AM AM = EQ
compareSame (R terms) (R terms_) = compare terms terms_
compareSame (P term0 term1) (P term0_ term1_) = mappend (compare term0 term0_) (compare term1 term1_)
compareSame (S terms) (S terms_) = compare terms terms_
compareSame (K tokn) (K tokn_) = compare tokn tokn_
compareSame (V n) (V n_) = compare n n_
compareSame (C n) (C n_) = compare n n_
compareSame (F cid) (F cid_) = compare cid cid_
compareSame (FV terms) (FV terms_) = compare terms terms_
compareSame (W str term) (W str_ term_) = mappend (compare str str_) (compare term term_)
compareSame (RP term0 term1) (RP term0_ term1_) = mappend (compare term0 term0_) (compare term1 term1_)
compareSame TM TM = EQ
compareSame (L cid term) (L cid_ term_) = mappend (compare cid cid_) (compare term term_)
compareSame (BV cid) (BV cid_) = compare cid cid_
compareSame (KS str) (KS str_) = compare str str_
compareSame (KP strs variants) (KP strs_ variants_) = mappend (compare strs strs_) (compare variants variants_)
compareSame (Var strs0 strs1) (Var strs0_ strs1_) = mappend (compare strs0 strs0_) (compare strs1 strs1_)
compareSame (CId str) (CId str_) = compare str str_
compareSame x y = error "BNFC error:" compareSame

View File

@@ -0,0 +1,30 @@
{-# OPTIONS_GHC -fglasgow-exts #-}
module GFCC.ComposOp (Compos(..),composOp,composOpM,composOpM_,composOpMonoid,
composOpMPlus,composOpFold) where
import Control.Monad.Identity
import Data.Monoid
class Compos t where
compos :: (forall a. a -> m a) -> (forall a b. m (a -> b) -> m a -> m b)
-> (forall a. t a -> m (t a)) -> t c -> m (t c)
composOp :: Compos t => (forall a. t a -> t a) -> t c -> t c
composOp f = runIdentity . composOpM (Identity . f)
composOpM :: (Compos t, Monad m) => (forall a. t a -> m (t a)) -> t c -> m (t c)
composOpM = compos return ap
composOpM_ :: (Compos t, Monad m) => (forall a. t a -> m ()) -> t c -> m ()
composOpM_ = composOpFold (return ()) (>>)
composOpMonoid :: (Compos t, Monoid m) => (forall a. t a -> m) -> t c -> m
composOpMonoid = composOpFold mempty mappend
composOpMPlus :: (Compos t, MonadPlus m) => (forall a. t a -> m b) -> t c -> m b
composOpMPlus = composOpFold mzero mplus
composOpFold :: Compos t => b -> (b -> b -> b) -> (forall a. t a -> b) -> t c -> b
composOpFold z c f = unC . compos (\_ -> C z) (\(C x) (C y) -> C (c x y)) (C . f)
newtype C b a = C { unC :: b }

16
src/tools/c/GFCC/ErrM.hs Normal file
View File

@@ -0,0 +1,16 @@
-- BNF Converter: Error Monad
-- Copyright (C) 2004 Author: Aarne Ranta
-- This file comes with NO WARRANTY and may be used FOR ANY PURPOSE.
module GFCC.ErrM where
-- the Error monad: like Maybe type with error msgs
data Err a = Ok a | Bad String
deriving (Read, Show, Eq)
instance Monad Err where
return = Ok
fail = Bad
Ok a >>= f = f a
Bad s >>= f = Bad s

340
src/tools/c/GFCC/Lex.hs Normal file

File diff suppressed because one or more lines are too long

135
src/tools/c/GFCC/Lex.x Normal file
View File

@@ -0,0 +1,135 @@
-- -*- haskell -*-
-- This Alex file was machine-generated by the BNF converter
{
{-# OPTIONS -fno-warn-incomplete-patterns #-}
module GFCC.Lex where
}
$l = [a-zA-Z\192 - \255] # [\215 \247] -- isolatin1 letter FIXME
$c = [A-Z\192-\221] # [\215] -- capital isolatin1 letter FIXME
$s = [a-z\222-\255] # [\247] -- small isolatin1 letter FIXME
$d = [0-9] -- digit
$i = [$l $d _ '] -- identifier character
$u = [\0-\255] -- universal: any character
@rsyms = -- symbols and non-identifier-like reserved words
\; | \( | \) | \{ | \} | \: | \= | \- \> | \? | \[ | \] | \! | \$ | \[ \| | \| \] | \+ | \@ | \# | \/ | \,
:-
$white+ ;
@rsyms { tok (\p s -> PT p (TS $ share s)) }
(\_ | $l)($l | $d | \' | \_)* { tok (\p s -> PT p (eitherResIdent (T_CId . share) s)) }
$l $i* { tok (\p s -> PT p (eitherResIdent (TV . share) s)) }
\" ([$u # [\" \\ \n]] | (\\ (\" | \\ | \' | n | t)))* \"{ tok (\p s -> PT p (TL $ share $ unescapeInitTail s)) }
$d+ { tok (\p s -> PT p (TI $ share s)) }
$d+ \. $d+ (e (\-)? $d+)? { tok (\p s -> PT p (TD $ share s)) }
{
tok f p s = f p s
share :: String -> String
share = id
data Tok =
TS !String -- reserved words and symbols
| TL !String -- string literals
| TI !String -- integer literals
| TV !String -- identifiers
| TD !String -- double precision float literals
| TC !String -- character literals
| T_CId !String
deriving (Eq,Show,Ord)
data Token =
PT Posn Tok
| Err Posn
deriving (Eq,Show,Ord)
tokenPos (PT (Pn _ l _) _ :_) = "line " ++ show l
tokenPos (Err (Pn _ l _) :_) = "line " ++ show l
tokenPos _ = "end of file"
posLineCol (Pn _ l c) = (l,c)
mkPosToken t@(PT p _) = (posLineCol p, prToken t)
prToken t = case t of
PT _ (TS s) -> s
PT _ (TI s) -> s
PT _ (TV s) -> s
PT _ (TD s) -> s
PT _ (TC s) -> s
PT _ (T_CId s) -> s
_ -> show t
data BTree = N | B String Tok BTree BTree deriving (Show)
eitherResIdent :: (String -> Tok) -> String -> Tok
eitherResIdent tv s = treeFind resWords
where
treeFind N = tv s
treeFind (B a t left right) | s < a = treeFind left
| s > a = treeFind right
| s == a = t
resWords = b "grammar" (b "concrete" (b "abstract" N N) N) (b "pre" N N)
where b s = B s (TS s)
unescapeInitTail :: String -> String
unescapeInitTail = unesc . tail where
unesc s = case s of
'\\':c:cs | elem c ['\"', '\\', '\''] -> c : unesc cs
'\\':'n':cs -> '\n' : unesc cs
'\\':'t':cs -> '\t' : unesc cs
'"':[] -> []
c:cs -> c : unesc cs
_ -> []
-------------------------------------------------------------------
-- Alex wrapper code.
-- A modified "posn" wrapper.
-------------------------------------------------------------------
data Posn = Pn !Int !Int !Int
deriving (Eq, Show,Ord)
alexStartPos :: Posn
alexStartPos = Pn 0 1 1
alexMove :: Posn -> Char -> Posn
alexMove (Pn a l c) '\t' = Pn (a+1) l (((c+7) `div` 8)*8+1)
alexMove (Pn a l c) '\n' = Pn (a+1) (l+1) 1
alexMove (Pn a l c) _ = Pn (a+1) l (c+1)
type AlexInput = (Posn, -- current position,
Char, -- previous char
String) -- current input string
tokens :: String -> [Token]
tokens str = go (alexStartPos, '\n', str)
where
go :: (Posn, Char, String) -> [Token]
go inp@(pos, _, str) =
case alexScan inp 0 of
AlexEOF -> []
AlexError (pos, _, _) -> [Err pos]
AlexSkip inp' len -> go inp'
AlexToken inp' len act -> act pos (take len str) : (go inp')
alexGetChar :: AlexInput -> Maybe (Char,AlexInput)
alexGetChar (p, c, []) = Nothing
alexGetChar (p, _, (c:s)) =
let p' = alexMove p c
in p' `seq` Just (c, (p', c, s))
alexInputPrevChar :: AlexInput -> Char
alexInputPrevChar (p, c, s) = c
}

1096
src/tools/c/GFCC/Par.hs Normal file

File diff suppressed because it is too large Load Diff

204
src/tools/c/GFCC/Par.y Normal file
View File

@@ -0,0 +1,204 @@
-- This Happy file was machine-generated by the BNF converter
{
{-# OPTIONS -fno-warn-incomplete-patterns -fno-warn-overlapping-patterns #-}
module GFCC.Par where
import GFCC.Abs
import GFCC.Lex
import GFCC.ErrM
}
%name pGrammar Grammar
%name pHeader Header
%name pAbstract Abstract
%name pConcrete Concrete
%name pAbsDef AbsDef
%name pCncDef CncDef
%name pType Type
%name pExp Exp
%name pAtom Atom
%name pTerm Term
%name pTokn Tokn
%name pVariant Variant
%name pListConcrete ListConcrete
%name pListAbsDef ListAbsDef
%name pListCncDef ListCncDef
%name pListCId ListCId
%name pListTerm ListTerm
%name pListExp ListExp
%name pListString ListString
%name pListVariant ListVariant
-- no lexer declaration
%monad { Err } { thenM } { returnM }
%tokentype { Token }
%token
';' { PT _ (TS ";") }
'(' { PT _ (TS "(") }
')' { PT _ (TS ")") }
'{' { PT _ (TS "{") }
'}' { PT _ (TS "}") }
':' { PT _ (TS ":") }
'=' { PT _ (TS "=") }
'->' { PT _ (TS "->") }
'?' { PT _ (TS "?") }
'[' { PT _ (TS "[") }
']' { PT _ (TS "]") }
'!' { PT _ (TS "!") }
'$' { PT _ (TS "$") }
'[|' { PT _ (TS "[|") }
'|]' { PT _ (TS "|]") }
'+' { PT _ (TS "+") }
'@' { PT _ (TS "@") }
'#' { PT _ (TS "#") }
'/' { PT _ (TS "/") }
',' { PT _ (TS ",") }
'abstract' { PT _ (TS "abstract") }
'concrete' { PT _ (TS "concrete") }
'grammar' { PT _ (TS "grammar") }
'pre' { PT _ (TS "pre") }
L_quoted { PT _ (TL $$) }
L_integ { PT _ (TI $$) }
L_doubl { PT _ (TD $$) }
L_CId { PT _ (T_CId $$) }
L_err { _ }
%%
String :: { String } : L_quoted { $1 }
Integer :: { Integer } : L_integ { (read $1) :: Integer }
Double :: { Double } : L_doubl { (read $1) :: Double }
CId :: { CId} : L_CId { CId ($1)}
Grammar :: { Grammar }
Grammar : Header ';' Abstract ';' ListConcrete { Grm $1 $3 (reverse $5) }
Header :: { Header }
Header : 'grammar' CId '(' ListCId ')' { Hdr $2 $4 }
Abstract :: { Abstract }
Abstract : 'abstract' '{' ListAbsDef '}' { Abs (reverse $3) }
Concrete :: { Concrete }
Concrete : 'concrete' CId '{' ListCncDef '}' { Cnc $2 (reverse $4) }
AbsDef :: { AbsDef }
AbsDef : CId ':' Type '=' Exp { Fun $1 $3 $5 }
CncDef :: { CncDef }
CncDef : CId '=' Term { Lin $1 $3 }
Type :: { Type }
Type : ListCId '->' CId { Typ $1 $3 }
Exp :: { Exp }
Exp : '(' Atom ListExp ')' { Tr $2 (reverse $3) }
| Atom { trA_ $1 }
Atom :: { Atom }
Atom : CId { AC $1 }
| String { AS $1 }
| Integer { AI $1 }
| Double { AF $1 }
| '?' { AM }
Term :: { Term }
Term : '[' ListTerm ']' { R $2 }
| '(' Term '!' Term ')' { P $2 $4 }
| '(' ListTerm ')' { S $2 }
| Tokn { K $1 }
| '$' Integer { V $2 }
| Integer { C $1 }
| CId { F $1 }
| '[|' ListTerm '|]' { FV $2 }
| '(' String '+' Term ')' { W $2 $4 }
| '(' Term '@' Term ')' { RP $2 $4 }
| '?' { TM }
| '(' CId '->' Term ')' { L $2 $4 }
| '#' CId { BV $2 }
Tokn :: { Tokn }
Tokn : String { KS $1 }
| '[' 'pre' ListString '[' ListVariant ']' ']' { KP (reverse $3) $5 }
Variant :: { Variant }
Variant : ListString '/' ListString { Var (reverse $1) (reverse $3) }
ListConcrete :: { [Concrete] }
ListConcrete : {- empty -} { [] }
| ListConcrete Concrete ';' { flip (:) $1 $2 }
ListAbsDef :: { [AbsDef] }
ListAbsDef : {- empty -} { [] }
| ListAbsDef AbsDef ';' { flip (:) $1 $2 }
ListCncDef :: { [CncDef] }
ListCncDef : {- empty -} { [] }
| ListCncDef CncDef ';' { flip (:) $1 $2 }
ListCId :: { [CId] }
ListCId : {- empty -} { [] }
| CId { (:[]) $1 }
| CId ',' ListCId { (:) $1 $3 }
ListTerm :: { [Term] }
ListTerm : {- empty -} { [] }
| Term { (:[]) $1 }
| Term ',' ListTerm { (:) $1 $3 }
ListExp :: { [Exp] }
ListExp : {- empty -} { [] }
| ListExp Exp { flip (:) $1 $2 }
ListString :: { [String] }
ListString : {- empty -} { [] }
| ListString String { flip (:) $1 $2 }
ListVariant :: { [Variant] }
ListVariant : {- empty -} { [] }
| Variant { (:[]) $1 }
| Variant ',' ListVariant { (:) $1 $3 }
{
returnM :: a -> Err a
returnM = return
thenM :: Err a -> (a -> Err b) -> Err b
thenM = (>>=)
happyError :: [Token] -> Err a
happyError ts =
Bad $ "syntax error at " ++ tokenPos ts ++
case ts of
[] -> []
[Err _] -> " due to lexer error"
_ -> " before " ++ unwords (map prToken (take 4 ts))
myLexer = tokens
trA_ a_ = Tr a_ []
}

148
src/tools/c/GFCC/Print.hs Normal file
View File

@@ -0,0 +1,148 @@
{-# OPTIONS_GHC -fglasgow-exts #-}
module GFCC.Print where
-- pretty-printer generated by the BNF converter
import GFCC.Abs
import Data.Char
import Data.List (intersperse)
-- the top-level printing method
printTree :: Print a => a -> String
printTree = render . prt 0
type Doc = [ShowS] -> [ShowS]
doc :: ShowS -> Doc
doc = (:)
render :: Doc -> String
render d = rend 0 (map ($ "") $ d []) "" where
rend i ss = case ss of
"[" :ts -> showChar '[' . rend i ts
"(" :ts -> showChar '(' . rend i ts
"{" :ts -> showChar '{' . new (i+1) . rend (i+1) ts
"}" : ";":ts -> new (i-1) . space "}" . showChar ';' . new (i-1) . rend (i-1) ts
"}" :ts -> new (i-1) . showChar '}' . new (i-1) . rend (i-1) ts
";" :ts -> showChar ';' . new i . rend i ts
t : "," :ts -> showString t . space "," . rend i ts
t : ")" :ts -> showString t . showChar ')' . rend i ts
t : "]" :ts -> showString t . showChar ']' . rend i ts
t :ts -> space t . rend i ts
_ -> id
new i = showChar '\n' . replicateS (2*i) (showChar ' ') . dropWhile isSpace
space t = showString t . (\s -> if null s then "" else (' ':s))
parenth :: Doc -> Doc
parenth ss = doc (showChar '(') . ss . doc (showChar ')')
concatS :: [ShowS] -> ShowS
concatS = foldr (.) id
concatD :: [Doc] -> Doc
concatD = foldr (.) id
unwordsD :: [Doc] -> Doc
unwordsD = concatD . intersperse (doc (showChar ' '))
replicateS :: Int -> ShowS -> ShowS
replicateS n f = concatS (replicate n f)
-- the printer class does the job
class Print a where
prt :: Int -> a -> Doc
instance Print Char where
prt _ s = doc (showChar '\'' . mkEsc '\'' s . showChar '\'')
instance Print String where
prt _ s = doc (showChar '"' . concatS (map (mkEsc '"') s) . showChar '"')
mkEsc :: Char -> Char -> ShowS
mkEsc q s = case s of
_ | s == q -> showChar '\\' . showChar s
'\\'-> showString "\\\\"
'\n' -> showString "\\n"
'\t' -> showString "\\t"
_ -> showChar s
prPrec :: Int -> Int -> Doc -> Doc
prPrec i j = if j<i then parenth else id
instance Print Integer where
prt _ x = doc (shows x)
instance Print Double where
prt _ x = doc (shows x)
instance Print (Tree c) where
prt _i e = case e of
Grm header abstract concretes -> prPrec _i 0 (concatD [prt 0 header , doc (showString ";") , prt 0 abstract , doc (showString ";") , prt 0 concretes])
Hdr cid cids -> prPrec _i 0 (concatD [doc (showString "grammar") , prt 0 cid , doc (showString "(") , prt 0 cids , doc (showString ")")])
Abs absdefs -> prPrec _i 0 (concatD [doc (showString "abstract") , doc (showString "{") , prt 0 absdefs , doc (showString "}")])
Cnc cid cncdefs -> prPrec _i 0 (concatD [doc (showString "concrete") , prt 0 cid , doc (showString "{") , prt 0 cncdefs , doc (showString "}")])
Fun cid type' exp -> prPrec _i 0 (concatD [prt 0 cid , doc (showString ":") , prt 0 type' , doc (showString "=") , prt 0 exp])
Lin cid term -> prPrec _i 0 (concatD [prt 0 cid , doc (showString "=") , prt 0 term])
Typ cids cid -> prPrec _i 0 (concatD [prt 0 cids , doc (showString "->") , prt 0 cid])
Tr atom exps -> prPrec _i 0 (concatD [doc (showString "(") , prt 0 atom , prt 0 exps , doc (showString ")")])
AC cid -> prPrec _i 0 (concatD [prt 0 cid])
AS str -> prPrec _i 0 (concatD [prt 0 str])
AI n -> prPrec _i 0 (concatD [prt 0 n])
AF d -> prPrec _i 0 (concatD [prt 0 d])
AM -> prPrec _i 0 (concatD [doc (showString "?")])
R terms -> prPrec _i 0 (concatD [doc (showString "[") , prt 0 terms , doc (showString "]")])
P term0 term1 -> prPrec _i 0 (concatD [doc (showString "(") , prt 0 term0 , doc (showString "!") , prt 0 term1 , doc (showString ")")])
S terms -> prPrec _i 0 (concatD [doc (showString "(") , prt 0 terms , doc (showString ")")])
K tokn -> prPrec _i 0 (concatD [prt 0 tokn])
V n -> prPrec _i 0 (concatD [doc (showString "$") , prt 0 n])
C n -> prPrec _i 0 (concatD [prt 0 n])
F cid -> prPrec _i 0 (concatD [prt 0 cid])
FV terms -> prPrec _i 0 (concatD [doc (showString "[|") , prt 0 terms , doc (showString "|]")])
W str term -> prPrec _i 0 (concatD [doc (showString "(") , prt 0 str , doc (showString "+") , prt 0 term , doc (showString ")")])
RP term0 term1 -> prPrec _i 0 (concatD [doc (showString "(") , prt 0 term0 , doc (showString "@") , prt 0 term1 , doc (showString ")")])
TM -> prPrec _i 0 (concatD [doc (showString "?")])
L cid term -> prPrec _i 0 (concatD [doc (showString "(") , prt 0 cid , doc (showString "->") , prt 0 term , doc (showString ")")])
BV cid -> prPrec _i 0 (concatD [doc (showString "#") , prt 0 cid])
KS str -> prPrec _i 0 (concatD [prt 0 str])
KP strs variants -> prPrec _i 0 (concatD [doc (showString "[") , doc (showString "pre") , prt 0 strs , doc (showString "[") , prt 0 variants , doc (showString "]") , doc (showString "]")])
Var strs0 strs1 -> prPrec _i 0 (concatD [prt 0 strs0 , doc (showString "/") , prt 0 strs1])
CId str -> prPrec _i 0 (doc (showString str))
instance Print [Concrete] where
prt _ es = case es of
[] -> (concatD [])
x:xs -> (concatD [prt 0 x , doc (showString ";") , prt 0 xs])
instance Print [AbsDef] where
prt _ es = case es of
[] -> (concatD [])
x:xs -> (concatD [prt 0 x , doc (showString ";") , prt 0 xs])
instance Print [CncDef] where
prt _ es = case es of
[] -> (concatD [])
x:xs -> (concatD [prt 0 x , doc (showString ";") , prt 0 xs])
instance Print [CId] where
prt _ es = case es of
[] -> (concatD [])
[x] -> (concatD [prt 0 x])
x:xs -> (concatD [prt 0 x , doc (showString ",") , prt 0 xs])
instance Print [Term] where
prt _ es = case es of
[] -> (concatD [])
[x] -> (concatD [prt 0 x])
x:xs -> (concatD [prt 0 x , doc (showString ",") , prt 0 xs])
instance Print [Exp] where
prt _ es = case es of
[] -> (concatD [])
x:xs -> (concatD [prt 0 x , prt 0 xs])
instance Print [String] where
prt _ es = case es of
[] -> (concatD [])
x:xs -> (concatD [prt 0 x , prt 0 xs])
instance Print [Variant] where
prt _ es = case es of
[] -> (concatD [])
[x] -> (concatD [prt 0 x])
x:xs -> (concatD [prt 0 x , doc (showString ",") , prt 0 xs])

58
src/tools/c/GFCC/Test.hs Normal file
View File

@@ -0,0 +1,58 @@
-- automatically generated by BNF Converter
module Main where
import IO ( stdin, hGetContents )
import System ( getArgs, getProgName )
import GFCC.Lex
import GFCC.Par
import GFCC.Skel
import GFCC.Print
import GFCC.Abs
import GFCC.ErrM
type ParseFun a = [Token] -> Err a
myLLexer = myLexer
type Verbosity = Int
putStrV :: Verbosity -> String -> IO ()
putStrV v s = if v > 1 then putStrLn s else return ()
runFile :: (Print a, Show a) => Verbosity -> ParseFun a -> FilePath -> IO ()
runFile v p f = putStrLn f >> readFile f >>= run v p
run :: (Print a, Show a) => Verbosity -> ParseFun a -> String -> IO ()
run v p s = let ts = myLLexer s in case p ts of
Bad s -> do putStrLn "\nParse Failed...\n"
putStrV v "Tokens:"
putStrV v $ show ts
putStrLn s
Ok tree -> do putStrLn "\nParse Successful!"
showTree v tree
showTree :: (Show a, Print a) => Int -> a -> IO ()
showTree v tree
= do
putStrV v $ "\n[Abstract Syntax]\n\n" ++ show tree
putStrV v $ "\n[Linearized tree]\n\n" ++ printTree tree
main :: IO ()
main = do args <- getArgs
case args of
[] -> hGetContents stdin >>= run 2 pGrammar
"-s":fs -> mapM_ (runFile 0 pGrammar) fs
fs -> mapM_ (runFile 2 pGrammar) fs

25
src/tools/c/Makefile Normal file
View File

@@ -0,0 +1,25 @@
GHC = ghc
GHCFLAGS =
.PHONY: all gfcc2c clean
all: gfcc2c
gfcc2c:
$(GHC) $(GHCFLAGS) --make -o $@ gfcc2c.hs
bnfc:
bnfc -gadt -d ../../GF/Canon/GFCC/GFCC.cf
-rm -f GFCC/Doc.tex GFCC/Skel.hs
happy -gca GFCC/Par.y
alex -g GFCC/Lex.x
clean:
-rm -f gfcc2c
-rm -f *.o *.hi
-rm -f GFCC/*.hi GFCC/*.o
bnfcclean: clean
-rm -f GFCC/*.bak
-rm -f GFCC/Lex.* GFCC/Par.* GFCC/Layout.* GFCC/Skel.* GFCC/Print.* GFCC/Test.* GFCC/Abs.* GFCC/ComposOp.* GFCC/Test GFCC/ErrM.* GFCC/SharedString.*
-rmdir -p GFCC/

View File

@@ -0,0 +1,47 @@
GFDIR=../../../../../
LIBGFCC_INCLUDES = $(GFDIR)/lib/c
LIBGFCC_LIBDIR = $(GFDIR)/lib/c
GFCC2C = $(GFDIR)/bin/gfcc2c
TEST_PROG = bronzeage-test
GRAMMAR_DIR = $(GFDIR)/examples/bronzeage
GRAMMAR_MODULES = Bronzeage BronzeageEng BronzeageSwe
GRAMMAR_H_FILES = $(addsuffix .h, $(GRAMMAR_MODULES))
GRAMMAR_C_FILES = $(addsuffix .c, $(GRAMMAR_MODULES))
GRAMMAR_O_FILES = $(addsuffix .o, $(GRAMMAR_MODULES))
CFLAGS += -O2
CPPFLAGS += -I$(LIBGFCC_INCLUDES)
.PHONY: clean
all: bronzeage.gfcc $(TEST_PROG)
$(TEST_PROG): $(GRAMMAR_O_FILES) $(TEST_PROG).o $(LIBGFCC_LIBDIR)/libgfcc.a
$(TEST_PROG).o: $(GRAMMAR_H_FILES) $(GRAMMAR_O_FILES) $(TEST_PROG).c
$(GRAMMAR_H_FILES) $(GRAMMAR_C_FILES): $(GFCC2C) bronzeage.gfcc
$(GFCC2C) bronzeage.gfcc
bronzeage.gfcc:
echo "i -optimize=all $(GRAMMAR_DIR)/BronzeageEng.gf" > mkBronzeage.gfs
echo "i -optimize=all $(GRAMMAR_DIR)/BronzeageSwe.gf" >> mkBronzeage.gfs
echo "s" >> mkBronzeage.gfs
echo "pm -printer=gfcc | wf bronzeage.gfcc" >> mkBronzeage.gfs
cat mkBronzeage.gfs | gf
rm -f mkBronzeage.gfs
clean:
-rm -f $(TEST_PROG) *.o
distclean: clean
-rm -f $(GRAMMAR_H_FILES) $(GRAMMAR_C_FILES)
-rm -f bronzeage.gfcc

View File

@@ -0,0 +1,31 @@
#include "Bronzeage.h"
#include "BronzeageEng.h"
#include <unistd.h>
int main() {
Tree *tree =
mk_PhrPos(
mk_SentV(
mk_lie_V(),
mk_NumCN(
mk_two_Num(),
mk_UseN(mk_wife_N())
)
)
);
int i;
for (i = 0; i < 1000; i++) {
Term *term;
term = BronzeageEng_lin(tree);
term_print(stdout, term);
fputs("\n", stdout);
}
tree_free(tree);
return 0;
}

223
src/tools/c/gfcc2c.hs Normal file
View File

@@ -0,0 +1,223 @@
import GFCC.Abs
import GFCC.ErrM
import GFCC.Lex
import GFCC.Par
import Control.Monad
import Data.Char
import Data.List
import Numeric
import System.Environment
import System.Exit
import System.IO
constrType :: Grammar -> String
constrType g = unlines $
["typedef enum { "]
++ map (\x -> " " ++ x ++ "," ) ds
++ ["} Fun;"]
where fs = [id2c n | (n,_) <- constructors g ]
ds = case fs of
[] -> []
(x:xs) -> (x ++ " = ATOM_FIRST_FUN"):xs
mkFunSigs :: Grammar -> String
mkFunSigs g = unlines [mkFunSig n ats | (n,(ats,_)) <- constructors g]
mkFunSig :: CId -> [CId] -> String
mkFunSig n ats =
"extern Tree *mk_" ++ id2c n ++ "(" ++ commaSep adecls ++ ");"
where
adecls = map ("Tree *" ++) args
args = [ "x" ++ show x | x <- [0..c-1] ]
c = length ats
mkFuns :: Grammar -> String
mkFuns g = unlines [mkFun n ats | (n,(ats,_)) <- constructors g]
mkFun :: CId -> [CId] -> String
mkFun n ats = unlines $
["extern Tree *mk_" ++ id2c n ++ "(" ++ commaSep adecls ++ ") {",
" Tree *t = tree_fun(" ++ id2c n ++ "," ++ show c ++ ");"]
++ [" tree_set_child(" ++ commaSep ["t",show i, args!!i] ++ ");" | i <- [0..c-1]]
++ [" return t;",
"}"]
where
adecls = map ("Tree *" ++) args
args = [ "x" ++ show x | x <- [0..c-1] ]
c = length ats
doDie :: String -> [String] -> [String]
doDie s args = ["fprintf(" ++ commaSep ("stderr":show s':args) ++ ");",
"exit(1);"]
where s' = "Error: " ++ s ++ "\n"
mkLin :: Grammar -> CId -> String
mkLin g l = unlines $
["extern Term *" ++ langLinName_ l ++ "(Tree *t) {",
" Term **cs = NULL;",
" int n = arity(t);",
" if (n > 0) {",
" int i;",
" cs = (Term**)term_alloc(n * sizeof(Term *));", -- FIXME: handle failure
" for (i = 0; i < n; i++) {",
" cs[i] = " ++ langLinName_ l ++ "(tree_get_child(t,i));",
" }",
" }",
"",
" switch (t->type) {",
" case ATOM_STRING: return term_str(t->value.string_value);",
-- " case ATOM_INTEGER: return NULL;", -- FIXME!
-- " case ATOM_DOUBLE: return NULL;", -- FIXME!
" case ATOM_META: return term_meta();"]
++ [" case " ++ id2c n ++ ": return " ++ linFunName n ++ "(cs);"
| (n,_) <- constructors g]
++ [" default: "]
++ map (" " ++) (doDie (langLinName_ l ++ " %d") ["t->type"])
++ [" return NULL;",
" }",
"}",
"",
"extern Term *" ++ langLinName l ++ "(Tree *t) {",
" Term *r;",
" term_alloc_pool(1000000);", -- FIXME: size?
" r = " ++ langLinName_ l ++ "(t);",
" /* term_free_pool(); */", -- FIXME: copy term?
" return r;",
"}"]
langLinName :: CId -> String
langLinName n = id2c n ++ "_lin"
langLinName_ :: CId -> String
langLinName_ n = id2c n ++ "_lin_"
linFunName :: CId -> String
linFunName n = "lin_" ++ id2c n
mkLinFuns :: [CncDef] -> String
mkLinFuns cs = unlines $ map mkLinFunSig cs ++ [""] ++ map mkLinFun cs
mkLinFunSig :: CncDef -> String
mkLinFunSig (Lin n t) =
"static Term *" ++ linFunName n ++ "(Term **cs);"
mkLinFun :: CncDef -> String
mkLinFun (Lin (CId n) t) | "__" `isPrefixOf` n = ""
mkLinFun (Lin n t) = unlines [
"static Term *" ++ linFunName n ++ "(Term **cs) {",
" return " ++ term2c t ++ ";",
"}"
]
term2c :: Tree a -> String
term2c t = case t of
-- terms
R terms -> fun "term_array" terms
-- an optimization of t!n where n is a constant int
P term0 (C n) -> "term_sel_int("++ term2c term0 ++ "," ++ show n ++ ")"
P term0 term1 -> "term_sel(" ++ term2c term0 ++ "," ++ term2c term1 ++ ")"
S terms -> fun "term_seq" terms
K tokn -> term2c tokn
V n -> "cs[" ++ show n ++ "]"
C n -> "term_int(" ++ show n ++ ")"
F cid -> linFunName cid ++ "(cs)"
FV terms -> fun "term_variants" terms
W str term -> "term_suffix(" ++ string2c str ++ "," ++ term2c term ++ ")"
RP term0 term1 -> "term_rp(" ++ term2c term0 ++ "," ++ term2c term1 ++ ")"
TM -> "term_meta()"
-- tokens
KS s -> "term_str(" ++ string2c s ++ ")"
KP strs vars -> error $ show t -- FIXME: pre token
_ -> error $ show t
where fun f ts = f ++ "(" ++ commaSep (show (length ts):map term2c ts) ++ ")"
commaSep = concat . intersperse ","
id2c :: CId -> String
id2c (CId s) = s -- FIXME: convert ticks
string2c :: String -> String
string2c s = "\"" ++ concatEsc (map esc s) ++ "\""
where
esc c | isAscii c && isPrint c = [c]
esc '\n' = "\\n"
esc c = "\\x" ++ map toUpper (showHex (ord c) "")
concatEsc [] = ""
concatEsc (x:xs) | length x <= 2 = x ++ concatEsc xs
| otherwise = x ++ "\" \"" ++ concatEsc xs
lang2file :: CId -> String -> String
lang2file n ext = id2c n ++ "." ++ ext
constructors :: Grammar -> [(CId, ([CId],CId))]
constructors (Grm _ (Abs ads) _) = [(n,(ats,rt)) | Fun n (Typ ats rt) _ <- ads]
absHFile :: Grammar -> FilePath
absHFile (Grm (Hdr a _) _ _) = lang2file a "h"
cncHFile :: Concrete -> FilePath
cncHFile (Cnc l _) = lang2file l "h"
mkAbsH :: Grammar -> String
mkAbsH g = unlines ["#include \"gfcc-tree.h\"",
"#include \"gfcc-term.h\"",
constrType g,
"",
mkFunSigs g]
mkAbsC :: Grammar -> String
mkAbsC g = unlines [include (absHFile g),
"",
mkFuns g]
mkCncH :: Grammar -> Concrete -> String
mkCncH g (Cnc l _) = unlines
[include (absHFile g),
"",
"extern Term *" ++ langLinName l ++ "(Tree *);"]
mkCncC :: Grammar -> Concrete -> String
mkCncC g c@(Cnc l cds) = unlines $
["#include <stdio.h>",
"#include <stdlib.h>",
include (cncHFile c),
""]
++ [mkLinFuns cds, mkLin g l]
mkH :: FilePath -> String -> (FilePath, String)
mkH f c = (f, c')
where c' = unlines ["#ifndef " ++ s, "#define " ++ s, "", c, "#endif"]
s = [if x=='.' then '_' else toUpper x | x <- f]
include :: FilePath -> String
include f = "#include " ++ show f
-- returns list of file name, file contents
gfcc2c :: Grammar -> [(FilePath, String)]
gfcc2c g@(Grm (Hdr a _) _ cs) =
[mkH (absHFile g) (mkAbsH g), (lang2file a "c", mkAbsC g)]
++ concat [[mkH (cncHFile cnc) (mkCncH g cnc),(lang2file c "c", mkCncC g cnc)] | cnc@(Cnc c _) <- cs]
parse :: String -> Err Grammar
parse = pGrammar . myLexer
die :: String -> IO ()
die s = do hPutStrLn stderr "Usage: gfcc2c <gfcc file>"
exitFailure
createFile :: FilePath -> String -> IO ()
createFile f c = do hPutStrLn stderr $ "Writing " ++ f ++ "..."
writeFile f c
main :: IO ()
main = do args <- getArgs
case args of
[file] -> do c <- readFile file
case parse c of
Bad err -> die err
Ok g -> do let fs = gfcc2c g
mapM_ (uncurry createFile) fs
_ -> die "Usage: gfcc2c <gfcc file>"