0

我正在编写一个简单的解析器函数,它需要一个流中的项目,并返回一个 int,但由于某种原因,编译器出于我无法理解的原因一直期待一个浮点数;特别是考虑到代码实际上是来自 llvm ocaml 教程的示例代码

我已经尝试将这两个变量类型转换为整数,并且通常只是摆弄语法,但是该函数非常简单,我无法弄清楚实际出了什么问题。我知道对于普通函数,可以指定类型, let: type->type但我不知道这将如何与解析器函数一起使用。

这是功能:

    let parse_binary_precedence = parser 
        | [< 'Token.Number n >] -> int_of_float n
        | [< >] -> 30 
    in

这是在也是问题一部分的情况下使用它的更大背景(尽管我不认为它是):

    let parse_binary_precedence = parser 
        | [< 'Token.Number n >] -> (int_of_float n)
        | [< >] -> 30 
    in
    parser 
        | [< (prefix, kind)=parse_operator; 
            'Token.Kwd op ?? "expected operator";
            prec = parse_binary_precedence;
            'Token.Kwd '(' ?? "expected '(' in operator prototype"; 
            args = parse_first_arg []; 
            'Token.Kwd ')' ?? "expected ')' in operator protoype" >] ->

我目前只是获得标准

File "parser.ml", line 108, characters 49-50:
Error: This expression has type int but an expression was expected of type
         float

类型错误。

有谁知道为什么这期待浮动?如何使函数期望一个 int?

编辑:

我现在意识到我现在措辞很糟糕,但是我意识到程序的上下文决定了函数的类型,我在问程序中的什么让它假设函数返回一个 int。似乎它超出了我发布的范围,因此我正在使用与显示的所有内容相关的代码更新我的帖子。

这是相关代码的完整集。很抱歉一开始就没有包括这个。

令牌.ml:

type token = 
    (*primary*)
    | Ident of string | Number of int
    (*control*)
    | If | Else | For 
    (*user ops*)
    | Binary | Unary

解析器.ml

let parse_prototype = 
    let rec parse_args accumulator = parser
        | [< 'Token.Kwd ','; 'Token.Ident id; e=parse_args (id :: accumulator) >] -> e
        | [< >] -> accumulator 
    in

    let parse_first_arg accumulator = parser
        | [< 'Token.Ident id; e=parse_args (id::accumulator) >] -> e
        | [< >] -> accumulator
    in
    let parse_operator = parser
        | [< 'Token.Binary >] -> "binary", 2
        | [< 'Token.Unary >] -> "unary", 1
    in
    let parse_binary_precedence = parser 
        | [< 'Token.Number n >] -> (int_of_float n) (*line 108*)
        | [< >] -> 30 
    in
    parser 
        | [< 'Token.Ident id;
            'Token.Kwd '(' ?? "expected '(' in prototype";
            args= parse_first_arg [];
            'Token.Kwd ')' ?? "expected closing ')' in prototype " >] ->
            Ast.Prototype (id, Array.of_list (List.rev args))
        | [< (prefix, kind)=parse_operator; 
            'Token.Kwd op ?? "expected operator";
            prec = parse_binary_precedence;
            'Token.Kwd '(' ?? "expected '(' in operator prototype"; 
            args = parse_first_arg [];
            'Token.Kwd ')' ?? "expected ')' in operator protoype" >] ->
            let name = prefix ^ (String.make 1 op) in
            let args = Array.of_list (List.rev args) in 

            (*verify right number of args for op*)
            if Array.length args != kind then
                raise (Stream.Error "invalid number of operands in op def")
            else 
                if kind == 1 then 
                    Ast.Prototype (name, args)
                else 
                    Ast.BinOpPrototype (name, args, prec)
        | [< >] ->
                raise (Stream.Error "expected func name in prototype")

astml

type proto = 
    | Prototype of string * string array
    | BinOpPrototype of string * string array * int
4

2 回答 2

1

错误的来源不在您显示的行中:有一个Token模块的实现parse_first_arg以及parse_operator使您的代码编译的函数。

一件可能很奇怪的事情是您的 Token.Number 将浮点数作为参数。

另请注意,camlp4 及其解析器扩展已被废弃。

于 2019-08-02T08:14:49.550 回答
0

有谁知道为什么这期待浮动?如何使函数期望一个 int?

好吧,由于您没有显示代码,因此不可能告诉您代码哪里出错了,但是我至少可以指出您对 OCaml 工作原理的概念性误解,希望它能帮助您修复代码 :)

在 OCaml 中,没有类型转换,你不能函数期待任何东西,因为类型是从你编写的代码中推断出来的。

例如,这是一个函数

 let number_of_words s = String.count s ~f:(Char.is_whitespace) + 1

它的类型是推断出来的string -> int,在任何情况下,您都可以更改它,因为该类型从根本上是由您的代码结构定义的。是编译器推断出您的函数/表达式适用的最一般上下文。

在我们的示例中,编译器知道String.count接受 type 的值string因此也s必须是 type string,它知道String.count返回 type 的值int并且(+)只能应用于整数。因此,返回的类型是int,仅此而已。

如果您将在不可接受的环境中应用您的功能,

"the phrase has " ^ number_of_words "hello, world"

编译器告诉我们,表达式number_of_words "hello, world"有 typeint但它应该有 type string。这不是因为我们的表达式是错误的,而是因为我们在错误的上下文中使用它,在string预期 a 的上下文中,所以int不适合它。在您的情况下也是如此,您在预期值prec的地方使用。float换句话说,你试图在错误的地方进行修复。

回到我们的例子,正确的表达式是

 "the phrase has " ^ string_of_int (number_of_words "hello, world")

这里string_of_float不是强制运算符,也不是类型转换运算符,OCaml 中不存在这样的东西,否则它将是不健全的。它是将 type 的值转换为 typeint的值的函数string,即,它创建一个新字符串,然后用与该数字对应的十进制数字填充它,例如,

  string_of_int 42
  - : string = "42"

返回一个包含两个字符的字符串,而不是整数,转换为字符串。

希望能帮助到你。此外,在使用 OCaml Kaleidoscope 之前,最好先学习 OCaml 中的一些教程,这是一个非常先进、过时且非常不习惯的 OCaml 编程示例。

于 2019-08-02T14:56:38.170 回答