|
|
@@ -1,106 +1,169 @@
|
|
|
(** Utility functions used by multiple phases. *)
|
|
|
-(**
|
|
|
-Extended description...
|
|
|
-*)
|
|
|
|
|
|
-(** *)
|
|
|
-val repeat : string -> int -> string
|
|
|
-
|
|
|
-(** *)
|
|
|
-val expand : int -> string -> string
|
|
|
-
|
|
|
-(** Logging functions, they print to stderr and consider the verbosity flag *)
|
|
|
-val hline : string
|
|
|
-
|
|
|
-(** *)
|
|
|
-val prt_line : string -> unit
|
|
|
-
|
|
|
-(** *)
|
|
|
-val prt_node : Types.node -> unit
|
|
|
+(** {2 Generating variables} *)
|
|
|
|
|
|
-(** *)
|
|
|
-val log_line : int -> string -> unit
|
|
|
-
|
|
|
-(** *)
|
|
|
-val log_plain_line : int -> string -> unit
|
|
|
-
|
|
|
-(** *)
|
|
|
-val log_node : int -> Types.node -> unit
|
|
|
-
|
|
|
-(** Generate a fresh variable from a given prefix, e.g. "foo" -> "foo$1" *)
|
|
|
+(** Generate a new variable from a given prefix, e.g. ["foo"] becomes ["foo$1"].
|
|
|
+ Uses an [int] reference defined in the implementation file as a counter to
|
|
|
+ assert uniqueness of the generated variable. *)
|
|
|
val fresh_var : string -> string
|
|
|
|
|
|
-(** Generate a fresg constant from a given prefix, e.g. "foo" -> "foo$$1" *)
|
|
|
+(** Generate a new constant (a variable that is known to be assigned only once
|
|
|
+ in total) from a given prefix, e.g. ["foo"] becomes ["foo$$1"]. Uses the
|
|
|
+ same counter as {!fresh_var}. *)
|
|
|
val fresh_const : string -> string
|
|
|
|
|
|
-(** Generate an Types.location tuple from Lexing data structures *)
|
|
|
-val loc_from_lexpos : Lexing.position -> Lexing.position -> Types.location
|
|
|
+(** {2 AST traversal} *)
|
|
|
|
|
|
-(** Default transformation traversal for AST nodes *)
|
|
|
+(** Default transformation traversal for AST nodes of arbitrary constructor.
|
|
|
+ For each constructor that has one or more children of type {!Types.node},
|
|
|
+ the children are transformed with the given transformation function, and a
|
|
|
+ new node is returned with the transformed children. For [Program] nodes,
|
|
|
+ {!flatten_blocks} is called on the resulting declaration list. This allows
|
|
|
+ the transformation function to return multiple nodes as a replacement, in
|
|
|
+ the form of a [Block] node with multiple children. *)
|
|
|
val transform_children : (Types.node -> Types.node) -> Types.node -> Types.node
|
|
|
|
|
|
-(** Add a single annotation to a node (no traversal) *)
|
|
|
+(** Flatten [Block] nodes into containing node lists.
|
|
|
+ E.g., [[A; Block [B; Block [C; D]]; E] -> [A; B; C; D; E]].
|
|
|
+ Traverses into elements of the list recursively first, so this is
|
|
|
+ essentially a traversal, as can be seen in the example. Therefore the best
|
|
|
+ practice is to call this function once on the children of a [Program] node
|
|
|
+ after any traversal that may generate [Block] nodes that need to be
|
|
|
+ flattened. *)
|
|
|
+val flatten_blocks : Types.node list -> Types.node list
|
|
|
+
|
|
|
+(** Extract the list of child nodes from a [Block] node. *)
|
|
|
+val block_body : Types.node -> Types.node list
|
|
|
+
|
|
|
+(** {2 AST node annotations} *)
|
|
|
+
|
|
|
+(** Add a single annotation to a node. *)
|
|
|
val annotate : Types.annotation -> Types.node -> Types.node
|
|
|
|
|
|
-(** Extract annotation from node *)
|
|
|
+(** Extract annotations from a node of arbitrary constructor. *)
|
|
|
val annof : Types.node -> Types.annotation list
|
|
|
|
|
|
-(** *)
|
|
|
+(** Get the value of the [Loc] annotation of a node, or {!noloc} if no location
|
|
|
+ can be found. *)
|
|
|
val locof : Types.node -> Types.location
|
|
|
|
|
|
-(** *)
|
|
|
+(** Empty node location: [("", 0, 0, 0, 0)]. Used then location of a node is
|
|
|
+ unknown (if the annotation was removed at some point) or
|
|
|
+ non-existant/irrelevant (for generated nodes on which no errors will occur --
|
|
|
+ hopefully...). *)
|
|
|
+val noloc : Types.location
|
|
|
+
|
|
|
+(** Get the value of the [Depth] annotation of a node. Raises
|
|
|
+ {!Types.InvalidNode} if the annotation can not be found. *)
|
|
|
val depthof : Types.node -> int
|
|
|
|
|
|
-(** *)
|
|
|
+(** Get the value of the [Index] annotation of a node. Raises
|
|
|
+ {!Types.InvalidNode} if the annotation can not be found. *)
|
|
|
val indexof : Types.node -> int
|
|
|
|
|
|
-(** *)
|
|
|
+(** Get the value of the [Type] annotation of a node. Some node types
|
|
|
+ do not need to be annotated since they have inherent types. For example, a
|
|
|
+ [VarDec] node has a type attribute, and a [Dim] node is always an [Int]
|
|
|
+ (because array dimensions are integers). All nodes which have inherent types
|
|
|
+ are [VarDec], [Param], [FunDec], [FunDef], [GlobalDec], [GlobalDef],
|
|
|
+ [TypeCast], and [Dim]. Raises a {!Types.InvalidNode} if the annotation can
|
|
|
+ not be found, and the type has no inherent type. *)
|
|
|
val typeof : Types.node -> Types.ctype
|
|
|
|
|
|
-(** *)
|
|
|
+(** Get the value of the [LabelName] annotation of a node. Raises
|
|
|
+ {!Types.InvalidNode} if the annotation can not be found. *)
|
|
|
val labelof : Types.node -> string
|
|
|
|
|
|
-(** *)
|
|
|
+(** Get the basic type of a declaration, removing array dimensions *)
|
|
|
+val basetypeof : Types.node -> Types.ctype
|
|
|
+
|
|
|
+(** Get the value of the name attribute from a variable or function declaration
|
|
|
+ (similar to {!typeof} for nodes that have types attributes). Raises
|
|
|
+ {!Types.InvalidNode} if the node is not one of [GlobalDec], [GlobalDef],
|
|
|
+ [FunDec], [FunDef], [VarDec], [Param], or [Dim]. *)
|
|
|
+val nameof : Types.node -> string
|
|
|
+
|
|
|
+(** Get the CiviC data type of a constant value. *)
|
|
|
val const_type : Types.const -> Types.ctype
|
|
|
|
|
|
-(** Print file location to stderr *)
|
|
|
-val prerr_loc : Types.location -> unit
|
|
|
+(** Check if a constant value is eligible for creating optimized assembly
|
|
|
+ instructions. E.g. [Intval (-1)] is eligible because the instruction
|
|
|
+ [iloadc_m1] exists. Used to decide on which {!Types.instr} constructor to
|
|
|
+ use during the assembly phases. This function always returns [false] when
|
|
|
+ optimizations are disabled (when {!Globals.args}[.optimize = false]). *)
|
|
|
+val is_immediate_const : Types.const -> bool
|
|
|
|
|
|
-(** Print file location to stderr *)
|
|
|
-val prerr_loc_msg : Types.location -> string -> unit
|
|
|
+(** Check if a node has an array type. I.e., [Array] or [ArrayDims]. *)
|
|
|
+val is_array : Types.node -> bool
|
|
|
|
|
|
-(** Flatten Block nodes into the given array of nodes *)
|
|
|
-val flatten_blocks : Types.node list -> Types.node list
|
|
|
+(** {2 Logging} *)
|
|
|
|
|
|
-(** Extract the node list from a Block node *)
|
|
|
-val block_body : Types.node -> Types.node list
|
|
|
+(** Horizontal line of ['-'] characters, used to separate output sections. *)
|
|
|
+val hline : string
|
|
|
|
|
|
-(** Get the basic type of a declaration, removing array dimensions *)
|
|
|
-val basetypeof : Types.node -> Types.ctype
|
|
|
+(** Print the stringification of a node to [stderr] (uses
|
|
|
+ {!Stringify.node2str}). *)
|
|
|
+val prt_node : Types.node -> unit
|
|
|
|
|
|
-(** Get name from variable or function declaration *)
|
|
|
-val nameof : Types.node -> string
|
|
|
+(** Output a line to stderr if the verbosity level in {!Globals.args} is at
|
|
|
+ least as high as the specified verbosity level. The line is indented with a
|
|
|
+ number of spaces to match the longest phase identifier (so that logged lines
|
|
|
+ align with ideitifiers logged by {!Main.main}). A newline is added
|
|
|
+ automatically. *)
|
|
|
+val log_line : int -> string -> unit
|
|
|
|
|
|
-(** *)
|
|
|
-val optmap : ('a -> 'b) -> 'a list option -> 'b list option
|
|
|
+(** Print a line to [stderr] without indent (but do add a newline). *)
|
|
|
+val log_plain_line : int -> string -> unit
|
|
|
|
|
|
-(** *)
|
|
|
-val optmapl : ('a -> 'b) -> 'a list option -> 'b list
|
|
|
+(** Same as {!log_line}, but prints a node stringification instead of a literal
|
|
|
+ string. *)
|
|
|
+val log_node : int -> Types.node -> unit
|
|
|
|
|
|
-(** List.mapi clone (only available in OCaml version >= 4.00 *)
|
|
|
-val mapi : (int -> 'a -> 'b) -> 'a list -> 'b list
|
|
|
+(** Generate an Types.location tuple from Lexing data structures *)
|
|
|
+val loc_from_lexpos : Lexing.position -> Lexing.position -> Types.location
|
|
|
|
|
|
-(** *)
|
|
|
-val is_immediate_const : Types.const -> bool
|
|
|
+(** Print location tuple to stderr. Produces
|
|
|
+ something like the following: {v
|
|
|
+int foo;
|
|
|
+ ^^^ v}
|
|
|
+ The location tuple is likely to originate from a node annotation, extracted
|
|
|
+ using {!locof}.*)
|
|
|
+val prerr_loc : Types.location -> unit
|
|
|
|
|
|
-(** *)
|
|
|
-val is_array : Types.node -> bool
|
|
|
+(** Print location tuple to stderr, along with an error message. Produces
|
|
|
+ something like the following: {v
|
|
|
+File "foo.cvc", line 10, characters 8-11:
|
|
|
+<message>
|
|
|
+ int foo;
|
|
|
+ ^^^ v} *)
|
|
|
+val prerr_loc_msg : Types.location -> string -> unit
|
|
|
+
|
|
|
+(** Print an error message for a node. Calls prerr_loc_msg. *)
|
|
|
+val node_error : Types.node -> string -> unit
|
|
|
|
|
|
-(** *)
|
|
|
+(** Print a warning message for a node. Calls prerr_loc_msg. *)
|
|
|
val node_warning : Types.node -> string -> unit
|
|
|
|
|
|
-(** *)
|
|
|
-val noloc : Types.location
|
|
|
+(** {2 String utitities} *)
|
|
|
+
|
|
|
+(** [repeat s n] returns a new string of [n] times [s]. *)
|
|
|
+val repeat : string -> int -> string
|
|
|
|
|
|
-(** *)
|
|
|
-val immediate_consts : Types.const list
|
|
|
+(** [expand n s] adds spaces to [s] until the resulting string is at least [n]
|
|
|
+ characters long. *)
|
|
|
+val expand : int -> string -> string
|
|
|
+
|
|
|
+(** {2 List utitities} *)
|
|
|
+
|
|
|
+(** [optmap f opt] maps [f] to the list value of [opt] if [opt] exists, and
|
|
|
+ [None] otherwise. *)
|
|
|
+val optmap : ('a -> 'b) -> 'a list option -> 'b list option
|
|
|
+
|
|
|
+(** Same as {!optmap}, but returns the list value instead, or an empty list if
|
|
|
+ [opt] is [None]. *)
|
|
|
+val optmapl : ('a -> 'b) -> 'a list option -> 'b list
|
|
|
+
|
|
|
+(** [List.mapi] clone (only available in OCaml version >= 4.00. Maps a function
|
|
|
+ to a list like [List.map] does, but the iterator function is called with the
|
|
|
+ element's index as an additional argument. *)
|
|
|
+val mapi : (int -> 'a -> 'b) -> 'a list -> 'b list
|