How to create a program combining both Parser and Lexer - ocaml

I want to build a compiler using Ocamllex/Ocamlyacc and I want to create a main program to combine both of my OcamlParser and OcamlLexer. The thing is that I know how to do it using an input in the command line like the following code:
let _ =
try
let lexbuf = Lexing.from_channel stdin in
while true do
let result = Parser.main Lexer.token lexbuf in
print_int result; print_newline(); flush stdout
done
with Lexer.Eof ->
exit 0
But how can I do if I want to use a file as an input; I tried something like this:
let file ="add.txt"
let _ =
let ic = open_in file in
try
let lexbuf = Lexing.from_channel file in
while true do
let result = Parser.main Lexer.token lexbuf in
print_int result; print_newline(); flush stdout
done
with Lexer.Eof ->
exit 0
But it's not really working.

The following code works for me. In your version, you have some syntax errors.
let _ =
let file ="add.txt" in
let i = open_in file in
try
let lexbuf = Lexing.from_channel i in
while true do
let result = Parser.main Lexer.token lexbuf in
print_int result; print_newline(); flush stdout
done
with Lexer.Eof ->
exit 0
Putting 1+2 in "add.txt" gives me 3.

Related

Why mark stag functions are not called here?

I am trying to understand the following behaviour of OCaml Format module and semantic tags.
My code:
let prepare_ppf ppf =
let original_stag_functions = Format.pp_get_formatter_stag_functions ppf () in
let original_mark_tags_state = Format.pp_get_mark_tags ppf () in
Format.pp_set_mark_tags ppf true;
Format.pp_set_print_tags ppf false;
Format.pp_set_formatter_stag_functions ppf {
mark_open_stag = (fun stag ->
print_endline "MARK-OPEN";
match stag with
| Format.String_tag s -> Printf.sprintf "<open:%s>" s
| _ -> "<UNKNOWN>"
);
mark_close_stag = (fun stag ->
print_endline "MARK-CLOSE";
match stag with
| Format.String_tag s -> Printf.sprintf "</close:%s>" s
| _ -> "</UNKNOWN>"
);
print_open_stag = (fun _ -> print_endline "PRINT-OPEN"; ());
print_close_stag = (fun _ -> print_endline "PRINT-CLOSE"; ());
};
print_endline "PREPARED";
if Format.pp_get_mark_tags ppf () then print_endline "MARK:true";
(fun ppf ->
print_endline "RESET";
Format.pp_set_mark_tags ppf original_mark_tags_state;
Format.pp_set_formatter_stag_functions ppf original_stag_functions;)
let fprintf ppf fmt =
let reset = prepare_ppf ppf in
Format.kfprintf reset ppf fmt
let printf fmt = fprintf Format.std_formatter fmt
If I paste that into: utop version 2.8.0 (using OCaml version 4.12.0)
When I run it:
utop # printf "#{<bold>%s#}" "hello";;
PREPARED
MARK:true
RESET
<bold>hello</bold>- : unit = ()
Why are the mark_open_stag and close functions not called?
If I change line 5 to Format.pp_set_print_tags ppf true; then I see the print_open_stag and close function are called.
This is an interaction between buffering and utop handling of the stdout formatter.
The buffering issue can be seen with
printf "#{<bold>%s#}" "A very very very very very very very very very very very very very very very very very long hello world";;
which prints the half-correct
PREPARED
MARK:true
MARK-OPEN
<open:bold>A very very very very very very very very very very very very very very very very very long hello worldRESET
</bold>
Going on step further, flushing the stdout at the end with
printf "#{<bold>%s#}#." "hello";;
yields the correct output
PREPARED
MARK:true
MARK-OPEN
<open:bold>helloMARK-CLOSE
</close:bold>
RESET
The issue is thus that
printf "#{<bold>%s#}" "hello"
buffers completely all its input.
And it is utop taking the hand on the stdout formatter which triggers the printing by trying to print
- : unit = ()
This yields then
<bold>hello</bold>- : unit = ()
because at the time of the printing utop has reset the formatter configuration to its own default.

How to alter text using OCaml Containers.CCIO

In the ocaml-containers documentation, it gives a great example, how to read in a file, and write the content to a different file here. However, I am trying to see what it would take to modify the text before it is passed from the file being read to file being written.
let read_filename = "example.ts"
let filename = "example2.ts"
let () =
let modify_file ~chunks =
let r = Str.regexp "text \\([A-Za-z]+\\)" in
Str.replace_first r "\\1" chunks in
CCIO.(
with_in read_filename
(fun ic ->
let chunks = read_chunks ic in
let new_chunks = modify_file chunks in
with_out ~flags:[Open_binary] ~mode:0o644 filename
(fun oc ->
write_gen oc new_chunks
)
)
)
The issue with this code, is that the compiler complains:
File "component.ml", line 13, characters 39-45:
Error: This expression has type string gen = unit -> string option
but an expression was expected of type string
I am trying to figure out what I am doing wrong, but to no avail. Any help would be more than appreciated. Also, suggestions as to the ideal enterprise software to use in OCaml to modify text in files, is more than appreciated. Thank you.
You have a typing problem
read_chunk ic return a string gen value
from here we learn that is a function that take unit value () and return a string.
let () =
CCIO.(
let modify_file ~chunks =
let r = Str.regexp "example \\([A-Za-z]+\\)" in
match chunks () with
None -> chunks (* is the same as (fun () -> None) *)
| Some chunks ->
let chunks = Str.replace_first r "\\1" chunks in (* compute once *)
(fun () -> Some chunks) in
with_in read_filename
(fun ic ->
let chunks = read_chunks ic in
let new_chunks = modify_file ~chunks in
with_out ~flags:[Open_binary] ~mode:0o644 filename
(fun oc ->
write_gen oc new_chunks
)
)
)
EDIT:
explain the error and the change
EDIT 2:
I have modifier modify_file so it return antoher string gen and corrected the syntax error: when you use labeled argument you need to add a tilde when calling it
What is the type of modify_file. I don't see it in the manual.
You should try to add unit value () this way
let new_chunks = modify_file chunks () in and new_chunks will be of type string option
You can pattern match as option type.
EDIT:
I have seen that third parameter has type string gen
You should modify the 16th line this way:
write_gen oc (fun () -> new_chunks)

Read file line by line and store in a list

I have a input.txt file with few lines of text. I am trying to store those lines in a list l. I think I am doing correct but list l is not getting updated. please help.
let l = []
let () =
let ic = open_in "input.txt"
in
try
while true do
let line = input_line ic
in
let rec append(a, b) = match a with
|[] -> [b]
|c::cs -> c::append(cs,b)
in
append(l, line)
(* print_endline line *)
done
with End_of_file ->
close_in ic;;
Apart from Warning 10, I am not getting any error.
let l = []
Variables in OCaml are immutable, so no matter what code you write after this line, l will always be equal to [].
It looks like you are caught in imperative programming - a good thing to start with OCaml!
Typical functional and recursive programming would read a file like this:
Read a line, then append "read a line" to it. At End_of_File you finish the list with [].

executing functions in OCaml from fileinput of OCaml

How to execute (in OCaml) the lines we get from fileinput described below?
let read_file filename =
let lines = ref [] in
let chan = open_in filename in
try
while true; do
lines := input_line chan :: !lines
done; []
with End_of_file ->
close_in chan;
List.rev !lines
It's not clear (to me) what you're asking. If you have a file containing some OCaml code, one way to run it is to load it into the toplevel. First, create a file named fileread.ml containing your text. Then (from the command line):
$ ocaml
OCaml version 4.01.0
# #use "fileread.ml";;
val read_file : string -> string list = <fun>
# read_file "fileread.ml";;
- : string list =
["let read_file filename ="; "let lines = ref [] in";
"let chan = open_in filename in"; "try"; "while true; do";
"lines := input_line chan :: !lines"; "done; []"; "with End_of_file ->";
"close_in chan;"; "List.rev !lines"]
If, instead, you're asking how an OCaml program can load text and execute it as OCaml code, this isn't something OCaml can do directly. Naturally there are ways to do it; the toplevel is after all an OCaml program. But there's no simple function in OCaml for executing text, as there is in many interpreted languages (often being named eval).
If, on the third hand, you're asking how to compile and run your code, add a line like this to the end of fileread.ml:
let () = List.iter print_endline (read_file "fileread.ml")
Then compile and run as follows:
$ ocamlc -o fileread fileread.ml
$ fileread
let read_file filename =
let lines = ref [] in
let chan = open_in filename in
try
while true; do
lines := input_line chan :: !lines
done; []
with End_of_file ->
close_in chan;
List.rev !lines
let () = List.iter print_endline (read_file "fileread.ml")

How to implement "appendFile" function?

I can use the following function to overwrite a text file:
let writeFile ~filename:fn s =
let oc = open_out fn in
output_string oc s;
close_out oc ;;
Howeve, i donot know how to append a line to a text file ?
You could pass additional mode flag Open_append to open_out_gen function:
let _ =
let oc = open_out_gen [Open_creat; Open_text; Open_append] 0o640 "a.txt" in
output_string oc "append\n";
close_out oc
This is what I do:
let append_string path s =
let chan = open_out_gen [Open_wronly; Open_creat] 0o666 path
in let len = out_channel_length chan
in
begin
seek_out chan len;
output_string chan s;
close_out chan;
end