我想在Haskell中实现一个命令式语言解释器(用于教育目的).但是我很难为我的翻译创建正确的架构:我应该如何存储变量?如何实现嵌套函数调用?我该如何实现变量范围?如何在我的语言中添加调试功能?我应该使用monads/monad变压器/其他技术吗?等等
有没有人知道关于这个主题的好文章/论文/教程/来源?
我正在尝试使用parsec库在haskell中实现简单的解析器(用于学习目的).所以我写了一堆数据结构和相关的函数,如下所示:
data SourceElement
= StatementSourceElement Statement
| FunctionSourceElement FunctionName FunctionBody
data Statement
= IfStatement Expr Statement Statement
| WhileStatement Expr Statement
data FunctionBody = FunctionBody [SourceElement]
parseSourceElement :: Parser SourceElement
parseSourceElement = ...
parseFunctionBody :: Parser FunctionBody
parseFunctionBody = ...
Run Code Online (Sandbox Code Playgroud)
它工作正常.现在我想将这些东西分成两个模块来分离FunctionBody和Statement数据结构(因为可读性问题).但我不能!原因是SourceElement和之间的循环依赖FunctionBody.
那么,有什么方法可以解决这个问题吗?
是否有可能以某种方式获得某些自定义类型的解析错误?例如,从错误中获取有关解析上下文的更多信息会很酷.以文本消息的形式出现错误信息似乎不太方便.
我有用haskell写的原始翻译.这个解释器可以正确处理return语句(参见我之前的问题).
现在我想将全局状态添加到我的解释器中.可以从全局代码或函数代码更改此状态(函数的代码runCont用于提供return逻辑).
代码如下:
import Control.Monad.Cont
import Control.Monad.State
type MyState = String
data Statement = Return Int | GetState | SetState MyState | FuncCall [Statement] deriving (Show)
data Value = Undefined | Value Int | StateValue MyState deriving (Show)
type Eval a = StateT MyState (Cont (Value, MyState)) a
runEval ::(Eval Value) -> MyState -> (Value, MyState)
runEval eval state = runCont (runStateT eval state) id
evalProg :: [Statement] -> Value
evalProg stmts …Run Code Online (Sandbox Code Playgroud) 我有一些代码来评估原始程序.程序是一个语句列表(表达式,块,返回语句).评估结果是最后评估的表达式.评估员也应妥善处理return陈述(即首次出现后停止评估return).
为了实现这个逻辑,我传递了特殊的回调函数(NextStep),它在当前语句之后进行下一个评估步骤.处理return语句时我不调用下一步:
data Statement =
Expr Int
| Block [Statement]
| Return Int
deriving (Show, Eq)
data Value =
Undefined
| Value Int
deriving (Show, Eq)
type NextStep = Value -> Value
evalStmt :: Statement -> NextStep -> Value
evalStmt (Expr val) next =
let res = Value val
in next res
evalStmt (Block stmts) next = evalBlock stmts next
evalStmt (Return val) next = Value val
evalBlock :: [Statement] -> NextStep -> Value …Run Code Online (Sandbox Code Playgroud) 是否可以编写c ++模板/宏来检查两个函数是否具有相同的签名(返回类型和参数列表)?
这是一个我想如何使用它的简单示例:
int foo(const std::string& s) {...}
int bar(const std::string& s) {...}
if (SAME_SIGNATURES(foo, bar))
{
// do something useful... make Qt signal-slot connection for example...
}
else
{
// signatures mismatch.. report a problem or something...
}
Run Code Online (Sandbox Code Playgroud)
那么它有可能或者只是一个白日梦吗?
PS其实我对c ++ 2003标准感兴趣.
我的程序在执行期间崩溃并在控制台上写入Segmentation fault (core dumped)。但当前工作目录中没有任何生成的文件。问题是在哪里可以找到生成的故障转储文件?我正在使用 Ubuntu 13.04 / Erlang R15B01
我想做这样的事情:
#define NUM_ARGS() 2
#define MYMACRO0(...) "no args"
#define MYMACRO1(...) "one arg"
#define MYMACRO2(...) "two args"
#define MYMACRO(num,...) MYMACRO##num(__VA_ARGS__)
#define GENERATE(...) MYMACRO(NUM_ARGS(),__VA_ARGS__)
Run Code Online (Sandbox Code Playgroud)
我期望它评估为"两个参数".但相反,我有
MYMACRONUM_ARGS()(1,1)
Run Code Online (Sandbox Code Playgroud)
有没有办法做我想要的(使用visual c ++)?
PS最终我想实现转储所有变量的记录器.下一个代码
int myInt = 7;
string myStr("Hello Galaxy!");
DUMP_VARS(myInt, myStr);
Run Code Online (Sandbox Code Playgroud)
将产生日志记录 "myInt = 7; myStr = Hello Galaxy!"
我的程序中有令牌数据类型.看起来像这样:
data Token
= StringToken Strin
| NumberToken Integer
| IfToken
| ElseToken
... -- lots of tokens here
Run Code Online (Sandbox Code Playgroud)
我在我的解析器中使用这种数据类型,它运行正常.但现在我想向令牌添加一些额外的信息(源位置信息).所以我可以更改我的数据类型声明并使用记录:
data Token
= StringToken {value :: String, srcLoc :: SourceLocation}
| NumberToken {value :: String, srcLoc :: SourceLocation}
| IfToken {srcLoc :: SourceLocation}
| ElseToken {srcLoc :: SourceLocation}
... -- lots of tokens here
Run Code Online (Sandbox Code Playgroud)
但这个解决方案对我来说似乎并不实用和美观.那么这个问题有更好的解决方案吗?谢谢.
我正在尝试在haskell中实现简单的命令式语言.
一般来说,我的程序是一个语句列表(如算术表达式,if/then,块语句).我的评估者有简单的状态:词汇范围的堆栈.词法范围只是变量名称到值的映射.每当控制流进入功能或块时弹出词法范围,当控制流离开功能或阻塞时弹出.
但是我在尝试实现return语句评估时遇到了问题.我要做的是在主要评估函数(这里的源代码)中为return语句创建一个特例:
evalStatements :: [Statement] -> Eval MaybeValue
-- nothing to evaluate
evalStatements [] = return Nothing
-- current statement is 'return expr',
-- evaluate expr and skip the rest of statements
evalStatements (ret@(ReturnStatement _expr):_stmts) =
leaveLexEnv -- leave current lexical scope
evalStatement ret >>= return
-- this is last statement in function, eval it and leave lexical scope
evalStatements [stmt] = do
res <- evalStatement stmt
leaveLexEnv -- leave current lexical scope
return res …Run Code Online (Sandbox Code Playgroud) 我的类型Foo是简单的包装Cont a a.我想使Foo类型成为类的实例Monad.我试试这个:
import Control.Monad.Cont
newtype Foo a = Foo {unFoo :: Cont a a}
instance Monad Foo where
return = Foo . return
Foo inner >>= func = Foo (inner >>= newFunc)
where newFunc x = (unFoo $ func x)
Run Code Online (Sandbox Code Playgroud)
但我得到了这个错误:
Couldn't match type `a' with `b'
`a' is a rigid type variable bound by
the type signature for >>= :: Foo a -> (a -> Foo b) -> Foo b …Run Code Online (Sandbox Code Playgroud)