Prechádzať zdrojové kódy

Implemented C preprocessor integration

Taddeus Kroes 12 rokov pred
rodič
commit
f0e55d0030
10 zmenil súbory, kde vykonal 98 pridanie a 32 odobranie
  1. 2 2
      Makefile
  2. 3 2
      ast.ml
  3. 6 5
      lexer.mll
  4. 8 4
      main.ml
  5. 1 1
      phases/desug.ml
  6. 51 0
      phases/load.ml
  7. 9 18
      phases/parse.ml
  8. 10 0
      phases/print.ml
  9. 6 0
      test/civic.h
  10. 2 0
      test/scope.cvc

+ 2 - 2
Makefile

@@ -1,11 +1,11 @@
 RESULT := civicc
 SOURCES := ast.ml util.mli util.ml lexer.mll parser.mly stringify.mli \
 	stringify.ml \
-	phases/parse.ml phases/print.ml phases/desug.ml \
+	phases/load.ml phases/parse.ml phases/print.ml phases/desug.ml \
 	phases/context_analysis.ml \
 	main.ml
 PRE_TARGETS := ast.cmi util.cmi
-LIBS := str
+LIBS := str unix
 
 OCAMLFLAGS := -g
 

+ 3 - 2
ast.ml

@@ -48,13 +48,14 @@ and node =
 (* container for command-line arguments *)
 type args = {
     mutable filename : string option;
-    mutable verbose : int
+    mutable verbose : int;
+    mutable cpp : bool;
 }
 
 (* intermediate representations between phases *)
 type intermediate =
     | Args of args
-    | FileContent of string * args
+    | FileContent of string * string * args
     | Ast of node * args
     | Assembly of string list * args
 

+ 6 - 5
lexer.mll

@@ -25,14 +25,15 @@ rule token = parse
          * the file name can be zero or more flags, these flags are 1, 2, 3, 4.
          * These flags can be ignored.
          *)
-        let scan line filename =
+        let scan lnum fn =
+            let filename = String.sub fn 0 (String.length fn - 1) in
             let pos = lexbuf.lex_curr_p in
             lexbuf.lex_curr_p <- {
                 pos with pos_fname = filename;
-                         pos_lnum = line - 1
+                         pos_lnum = lnum
             }
         in
-        Scanf.sscanf marker "# %d \"%s\"" scan;
+        Scanf.sscanf marker "# %d \"%s" scan;
         token lexbuf
     }
 
@@ -87,9 +88,9 @@ rule token = parse
     | [' ''\t']+            { token lexbuf }
     | "//"[^'\n']*          { token lexbuf }
     | "/*"                  { comment lexbuf }
+    | eof | '\000'          { EOF }
 
-    | eof       { EOF }
-    | _ as chr  { raise (SyntaxError ("unexpected char: " ^ Char.escaped chr)) }
+    | _ as chr { raise (SyntaxError ("unexpected char: " ^ Char.escaped chr)) }
 
 (* Multi-line comments *)
 and comment = parse

+ 8 - 4
main.ml

@@ -6,10 +6,12 @@ open Ast
  * in_channel -> int -> repr *)
 let compile args =
     let rec run_phases input = function
-        | [] -> input
+        | [] -> ()
         | h::t -> run_phases (h input) t
     in
     run_phases (Args args) [
+        Load.phase;
+        Print.phase;
         Parse.phase;
         Print.phase;
         Desug.phase;
@@ -66,12 +68,14 @@ let print_fancy_error msg loc verbose =
 let main () =
     let args = {
         filename = None;
-        verbose = 2
+        verbose = 2;
+        cpp = true;
     } in
     let args_spec = [
-        ("-v", Arg.Int (fun i -> args.verbose <- i), "Set verbosity")
+        ("-v",     Arg.Int (fun i -> args.verbose <- i),  "Set verbosity");
+        ("-nocpp", Arg.Unit (fun i -> args.cpp <- false), "Disable C preprocessor");
     ] in
-    let usage = "Usage: " ^ Sys.argv.(0) ^ " [ -v VERBOSITY ] FILE" in
+    let usage = "Usage: " ^ Sys.argv.(0) ^ " [-nocpp] [-v <verbosity>] <file>" in
 
     try
         try

+ 1 - 1
phases/desug.ml

@@ -89,7 +89,7 @@ let rec array_init = function
 *)
 
 let rec phase input =
-    print_endline "- Desugaring";
+    prerr_endline "- Desugaring";
     match input with
     | Ast (node, args) ->
         Ast (var_init node, args)

+ 51 - 0
phases/load.ml

@@ -0,0 +1,51 @@
+open Printf
+open Ast
+
+let input_all ic =
+    let n = in_channel_length ic in
+    let buf = String.create n in
+    really_input ic buf 0 n;
+    close_in ic;
+    buf
+
+let phase ir =
+    prerr_endline "- Load input file";
+    match ir with
+    | Args args ->
+        let display_name = match args.filename with
+            | Some filename -> filename
+            | None -> "<stdin>"
+        in
+
+        if args.cpp then
+            let _ = prerr_endline "- Run C preprocessor" in
+
+            let cpp_out = match args.filename with
+                | Some filename ->
+                    Unix.open_process_in ("cpp " ^ filename)
+                | None ->
+                    let content = input_all stdin in
+                    let (cpp_out, cpp_in) = Unix.open_process "cpp" in
+                    output_string cpp_in content;
+                    close_out cpp_in;
+                    cpp_out
+            in
+
+            (* Read preprocessed code from cpp's stdout *)
+            let bufsize = 1024 in
+            let newbuf () = String.create bufsize in
+            let rec read_all buf pos =
+                let nread = input cpp_out buf pos bufsize in
+                if nread = 0
+                    then (close_in cpp_out; buf)
+                    else read_all (String.concat "" [buf; newbuf ()]) nread
+            in
+            let preprocessed = read_all (newbuf ()) 0 in
+            FileContent (display_name, preprocessed, args)
+        else
+            let infile = match args.filename with
+                | Some filename -> open_in filename
+                | None -> stdin
+            in
+            FileContent (display_name, input_all infile, args)
+    | _ -> raise (InvalidInput "load")

+ 9 - 18
phases/parse.ml

@@ -1,36 +1,27 @@
 open Lexing
-open Printf
 open Ast
 
 let get_loc lexbuf =
     Util.loc_from_lexpos lexbuf.lex_curr_p lexbuf.lex_curr_p
 
+let shift_loc (fname, ystart, yend, xstart, xend) yshift xshift =
+    (fname, ystart + yshift, yend + yshift, xstart + xshift, xend + xshift)
+
 let parse_with_error lexbuf =
     try Some (Parser.program Lexer.token lexbuf) with
     | Lexer.SyntaxError msg ->
-        raise (LocError (get_loc lexbuf, msg))
+        raise (LocError (shift_loc (get_loc lexbuf) 0 (-1), msg))
     | Parser.Error ->
         raise (LocError (get_loc lexbuf, "syntax error"))
 
 let phase input =
-    print_endline "- Parse input";
+    prerr_endline "- Parse input";
     match input with
-    | Args args ->
-        let infile = match args.filename with
-            | Some value -> open_in value
-            | None -> stdin
-        in
-        let display_name = match args.filename with
-            | Some value -> value
-            | None -> "stdin"
-        in
-
-        let lexbuf = Lexing.from_channel infile in
+    | FileContent (display_name, content, args) ->
+        let lexbuf = Lexing.from_string content in
         lexbuf.lex_curr_p <- { lexbuf.lex_curr_p with pos_fname = display_name };
         let ast = parse_with_error lexbuf in
-        close_in infile;
-
         (match ast with
-            | None -> raise (CompileError "error during parsing")
-            | Some ast -> Ast (ast, args))
+            | None -> raise (CompileError "no syntax tree was constructed")
+            | Some node -> Ast (node, args))
     | _ -> raise (InvalidInput "parse")

+ 10 - 0
phases/print.ml

@@ -9,4 +9,14 @@ let phase = function
             prerr_endline "--------------------------------------------------"
         );
         input
+
+    | FileContent (display_name, content, args) as input ->
+        if args.verbose >= 2 then (
+            prerr_endline "--------------------------------------------------";
+            prerr_endline (display_name ^ ":\n");
+            prerr_endline content;
+            prerr_endline "--------------------------------------------------"
+        );
+        input
+
     | _ -> raise (InvalidInput "print")

+ 6 - 0
test/civic.h

@@ -0,0 +1,6 @@
+extern void printInt(int val);
+extern void printFloat(float val);
+extern int scanInt();
+extern float scanFloat();
+extern void printSpaces(int num);
+extern void printNewlines( int num);

+ 2 - 0
test/scope.cvc

@@ -1,3 +1,5 @@
+#include "civic.h"
+
 void foo() {
     foo = bar;
 }