Search code examples
ocamlstdinocamllexocamlyacc

OCAML Taking multiple arguments from stdin and operating on them one by one


I have written an interpreter using ocamllex and ocamlyacc, the lexer and the parser work correctly but currently they only parse the last .txt argument it receives as oppose to all of them in turn. For example, ./interpret one.txt two.txt three.txt only parses three.txt as oppose to parsing one.txt and then two.txt and then three.txt which is what I want. So for example the parse results are as follows:

one.txt -> "1"
two.txt -> "2"
three.txt -> "3"

On calling ./interpret one.txt two.txt three.txt the current output is: 3 but I want it to be 123

Here is my main class which deals with the stdin and stdout

open Lexer
open Parser
open Arg
open Printf

let toParse c = 
    try let lexbuf = Lexing.from_channel c in  
            parser_main lexer_main lexbuf 
    with Parsing.Parse_error -> failwith "Parse failure!" ;;


let argument = ref stdin in                                         
let prog p = argument := open_in p in
let usage = "./interpreter FILE" in
parse [] prog usage ; 
let parsed = toParse !argument in
let result = eval parsed in
let _ = parsed in
flush stdout;

Thanks for your time


Solution

  • There's not really enough code here to be able to help.

    If I assume that the output is written by eval, then I see only one call to eval. But there's nothing here that deals with filenames from the command line, so it's hard to say more.

    If you are planning to read input from files, then there's no reason to be using stdin for anything as far as I can tell.

    (I know this is a very minor point, but this code doesn't constitute a class. Other languages use classes for everything, but this is a module.)

    Update

    Here's a module that works something like the Unix cat command; it writes out the contents of all the files from the command line one after the next.

    let cat () =
        for i = 1 to Array.length Sys.argv - 1 do
            let ic = open_in Sys.argv.(i) in
            let rec loop () =
                match input_line ic with
                | line -> output_string stdout (line ^ "\n"); loop ()
                | exception End_of_file -> ()
            in
            loop ();
            close_in ic
        done
    
    let () = cat ()
    

    Here's how it looks when you compile and run it.

    $ ocamlc -o mycat mycat.ml
    $ echo test line 1 > file1
    $ echo test line 2 > file2
    $ ./mycat file1 file2
    test line 1
    test line 2