(***********************************************************************) (* *) (* F90ast *) (* *) (* Jason L. Eckhardt, Rice University *) (* *) (* Copyright 2004 Jason L. Eckhardt. All rights reserved. *) (* This file is distributed under the terms of the Q Public License *) (* version 1.0. *) (* *) (***********************************************************************) (* * This is an AST for a large subset of Fortran90. * * Some f90 features it does not currently describe include: * I/O, some intrinsics, etc. * * Also, some of the archaic F77 constructs are not implemented (e.g, * alternate entry points, assigned goto, etc.). *) (* * Short-term TODO: * - Finish all intrinsics. * - Add WHERE statement. * - Old-style specification statements (common, data, etc). * * Longer-term TODO: * - Update to Fortran95 or Fortran2000 standard. * - Add Co-Array Fortran extensions for data-parallel programming. *) let version_f90abs = "f90abs v0.1 (Jason Eckhardt)" type fbasic_type = (* The argument is the optional KIND expression. *) Ftype_character of fexpression option (* Length. *) | Ftype_complex of fexpression option | Ftype_dbl_prec | Ftype_integer of fexpression option | Ftype_logical of fexpression option | Ftype_real of fexpression option | Ftype_type of string (* User-defined type. *) and fspec_attr = Fattr_allocatable | Fattr_common | Fattr_data | Fattr_dimension of fsubscript list | Fattr_equivalence | Fattr_extent | Fattr_external | Fattr_intent_in | Fattr_intent_out | Fattr_intent_inout | Fattr_intrinsic | Fattr_optional | Fattr_parameter | Fattr_pointer | Fattr_private | Fattr_public | Fattr_save | Fattr_target and fbinary_oper = Fbinop_add (* "+" *) | Fbinop_sub (* "-" *) | Fbinop_mul (* "*" *) | Fbinop_div (* "/" *) | Fbinop_pow (* "**" *) | Fbinop_concat (* "//" *) | Fbinop_and (* ".and." *) | Fbinop_or (* ".or." *) | Fbinop_eqv (* ".eqv." *) | Fbinop_neqv (* ".neqv." *) | Fbinop_eq (* ".eq." *) | Fbinop_ne (* ".ne." *) | Fbinop_lt (* ".lt." *) | Fbinop_le (* ".le." *) | Fbinop_gt (* ".gt." *) | Fbinop_ge (* ".ge." *) and funary_oper = Funop_minus (* "-" *) | Funop_not (* ".not." *) and fintrinsic = (* Unary. *) Fintrin_abs | Fintrin_cos | Fintrin_sin | Fintrin_tan | Fintrin_asin | Fintrin_acos | Fintrin_atan | Fintrin_sinh | Fintrin_cosh | Fintrin_tanh | Fintrin_sqrt | Fintrin_exp | Fintrin_log | Fintrin_log10 | Fintrin_int | Fintrin_aint | Fintrin_anint | Fintrin_nint | Fintrin_real | Fintrin_dble | Fintrin_cmplx | Fintrin_not | Fintrin_floor | Fintrin_ceiling | Fintrin_present | Fintrin_kind | Fintrin_selected_int_kind | Fintrin_allocate | Fintrin_deallocate | Fintrin_allocated | Fintrin_nullify (* Binary. *) | Fintrin_lbound | Fintrin_ubound | Fintrin_selected_real_kind | Fintrin_ior | Fintrin_iand | Fintrin_ieor | Fintrin_ishft | Fintrin_mod | Fintrin_modulo | Fintrin_dot_product | Fintrin_matmul (* N-ary or variable. *) | Fintrin_max | Fintrin_min | Fintrin_associated and fconstant = (* Constants are represented as strings, except logical. The second argument is the optional KIND parameter (e.g., "2_akind"). *) Fconst_int of string * string option | Fconst_real of string * string option | Fconst_realdbl of string | Fconst_char of string | Fconst_logical of bool | Fconst_star (* Special "constant" used for array specs. *) and fexpression = Fexp_nop | Fexp_variable of fvar_expression | Fexp_const of fconstant | Fexp_binary of fbinary_oper * fexpression * fexpression | Fexp_unary of funary_oper * fexpression | Fexp_intrinsic of fintrinsic * fexpression list | Fexp_fcall of string * fexpression list and fvar_expression = Fvar_ident of string | Fvar_arrayref of string * fsubscript list | Fvar_pathref of fvar_expression list and fsubscript = Fsub_simple of fexpression | Fsub_triplet of fexpression option * fexpression option * fexpression option and fstatement = Fstmt_assign of fvar_expression * fexpression | Fstmt_assignptr of fexpression * fexpression | Fstmt_call of string * fexpression list | Fstmt_do of string * fexpression * fexpression * fexpression option * fstatement list | Fstmt_do_while of fexpression * fstatement list | Fstmt_if of fexpression * fstatement | Fstmt_ifthenelse of fexpression * fstatement list * fstatement list option | Fstmt_goto of string (* Gotos: Line numbers repr. as strings. *) | Fstmt_computed_goto of string list * fexpression | Fstmt_return of fexpression option | Fstmt_continue | Fstmt_stop | Fstmt_end | Fstmt_select of fexpression * fselect_body list | Fstmt_cycle (* Note: Only un-named form for now. *) | Fstmt_exit (* Note: Only un-named form for now. *) and fselect_body = Fsel_case of fexpression list * fstatement list | Fsel_default of fstatement list (* Note: USE and IMPLICIT NONE actually precede specs, but we treat them as specs for convenience. *) and fspecification = Fspec_decl of fbasic_type * fspec_attr list * (string * fexpression option) list | Fspec_udtdecl of string * fspecification list | Fspec_implicit_none | Fspec_use of string * (string * string) list option (* Name and optional rename list. *) (* Block name, subprogs, module procedure names. *) | Finterface_blk of string option * finterface_subprog list * string list and finterface_subprog = Finterface_subprog of fsubprog_header * fspecification list and fsubprog_body = { specs: fspecification list; fstmts: fstatement list; contained: fsubprog_def list; } and fsubprog_def = Fsubprog of fsubprog_header * fsubprog_body and fsubprog_header = Fhdr_function of string * string list | Fhdr_recfunction of string * string list * string | Fhdr_subroutine of string * string list | Fhdr_program of string | Fhdr_module of string and fcompilation_unit = { topdefs: fsubprog_def list } (*********************************************************************) (* Fortran pretty printer *) (*********************************************************************) (*********************************************************************) (*********************************************************************) (* F90 "free-form" allows up to 132 characters before a continuation. *) let min_indent = 6 let max_linelen = 76 let output_string = ref "" let curr_str = ref "" exception ErrorInFPP of string;; let error s = raise (ErrorInFPP s) let printstr s = curr_str := !curr_str ^ s; let len = (String.length !curr_str) in let maxline = 76 in if len > maxline then begin output_string := !output_string ^ (String.sub (!curr_str) 0 max_linelen) ^ "&\n"; curr_str := (" &" ^ (String.sub (!curr_str) max_linelen (len-max_linelen))) end let indent n = curr_str := !curr_str ^ (String.make n ' ') (* Do not use embedded newline characters, use this. *) let newln _ = output_string := (!output_string ^ !curr_str ^ "\n"); curr_str := "" let prt_delimited_list action del li = for i = 1 to (List.length li) do action (List.nth li (i-1)); if i < (List.length li) then printstr del; done let get_expr_prio fexp = match fexp with Fexp_nop -> 0 | Fexp_variable(_) -> 100 | Fexp_const(_) -> 100 | Fexp_binary(op, _, _) -> begin match op with Fbinop_add -> 78 | Fbinop_sub -> 78 | Fbinop_mul -> 79 | Fbinop_div -> 79 | Fbinop_pow -> 80 | Fbinop_concat -> 70 | Fbinop_and -> 49 | Fbinop_or -> 48 | Fbinop_eqv -> 47 | Fbinop_neqv -> 47 | Fbinop_eq -> 60 | Fbinop_ne -> 60 | Fbinop_lt -> 60 | Fbinop_le -> 60 | Fbinop_gt -> 60 | Fbinop_ge -> 60 end | Fexp_unary(op, _) -> begin match op with Funop_minus -> 78 | Funop_not -> 50 end | Fexp_intrinsic(_, _) -> 99 | Fexp_fcall(_, _) -> 99 let string_of_fbinop binop = match binop with Fbinop_add -> "+" | Fbinop_sub -> "-" | Fbinop_mul -> "*" | Fbinop_div -> "/" | Fbinop_pow -> "**" | Fbinop_concat -> "//" | Fbinop_and -> ".and." | Fbinop_or -> ".or." | Fbinop_eqv -> ".eqv." | Fbinop_neqv -> ".neqv." | Fbinop_eq -> ".eq." | Fbinop_ne -> ".ne." | Fbinop_lt -> ".lt." | Fbinop_le -> ".le." | Fbinop_gt -> ".gt." | Fbinop_ge -> ".ge." let string_of_funop unop = match unop with Funop_minus -> "-" | Funop_not -> ".not." let string_of_fintrinsic fintr = match fintr with Fintrin_abs -> "ABS" | Fintrin_cos -> "COS" | Fintrin_sin -> "SIN" | Fintrin_tan -> "TAN" | Fintrin_asin -> "ASIN" | Fintrin_acos -> "ACOS" | Fintrin_atan -> "ATAN" | Fintrin_sinh -> "SINH" | Fintrin_cosh -> "COSH" | Fintrin_tanh -> "TANH" | Fintrin_sqrt -> "SQRT" | Fintrin_exp -> "EXP" | Fintrin_log -> "LOG" | Fintrin_log10 -> "LOG10" | Fintrin_int -> "INT" | Fintrin_aint -> "AINT" | Fintrin_anint -> "ANINT" | Fintrin_nint -> "NINT" | Fintrin_real -> "REAL" | Fintrin_dble -> "DBLE" | Fintrin_cmplx -> "CMPLX" | Fintrin_not -> "NOT" | Fintrin_floor -> "FLOOR" | Fintrin_ceiling -> "CEILING" | Fintrin_present -> "PRESENT" | Fintrin_kind -> "KIND" | Fintrin_selected_int_kind -> "SELECTED_INT_KIND" | Fintrin_allocate -> "ALLOCATE" | Fintrin_deallocate -> "DEALLOCATE" | Fintrin_allocated -> "ALLOCATED" | Fintrin_nullify -> "NULLIFY" (* Binary. *) | Fintrin_lbound -> "LBOUND" | Fintrin_ubound -> "UBOUND" | Fintrin_selected_real_kind -> "SELECTED_REAL_KIND" | Fintrin_ior -> "IOR" | Fintrin_iand -> "IAND" | Fintrin_ieor -> "IEOR" | Fintrin_ishft -> "ISHFT" | Fintrin_mod -> "MOD" | Fintrin_modulo -> "MODULO" | Fintrin_dot_product -> "DOT_PRODUCT" | Fintrin_matmul -> "MATMUL" | Fintrin_max -> "MAX" | Fintrin_min -> "MIN" | Fintrin_associated -> "ASSOCIATED" let assert_nargs fintr n arglist = if (List.length arglist) <> n then error ("incorrect number of arguments for intrinsic: " ^ (string_of_fintrinsic fintr)) (* Check that an intrinsic was constructed with the proper number of args. *) let check_intrin_argcnt fintr arglist = match fintr with Fintrin_abs -> assert_nargs fintr 1 arglist | Fintrin_cos -> assert_nargs fintr 1 arglist | Fintrin_sin -> assert_nargs fintr 1 arglist | Fintrin_tan -> assert_nargs fintr 1 arglist | Fintrin_asin -> assert_nargs fintr 1 arglist | Fintrin_acos -> assert_nargs fintr 1 arglist | Fintrin_atan -> assert_nargs fintr 1 arglist | Fintrin_sinh -> assert_nargs fintr 1 arglist | Fintrin_cosh -> assert_nargs fintr 1 arglist | Fintrin_tanh -> assert_nargs fintr 1 arglist | Fintrin_sqrt -> assert_nargs fintr 1 arglist | Fintrin_exp -> assert_nargs fintr 1 arglist | Fintrin_log -> assert_nargs fintr 1 arglist | Fintrin_log10 -> assert_nargs fintr 1 arglist | Fintrin_int -> assert_nargs fintr 1 arglist | Fintrin_aint -> assert_nargs fintr 1 arglist | Fintrin_anint -> assert_nargs fintr 1 arglist | Fintrin_nint -> assert_nargs fintr 1 arglist | Fintrin_real -> assert_nargs fintr 1 arglist | Fintrin_dble -> assert_nargs fintr 1 arglist | Fintrin_cmplx -> assert_nargs fintr 1 arglist | Fintrin_not -> assert_nargs fintr 1 arglist | Fintrin_floor -> assert_nargs fintr 1 arglist | Fintrin_ceiling -> assert_nargs fintr 1 arglist | Fintrin_present -> assert_nargs fintr 1 arglist | Fintrin_kind -> assert_nargs fintr 1 arglist | Fintrin_selected_int_kind -> assert_nargs fintr 1 arglist | Fintrin_allocate -> assert_nargs fintr 1 arglist | Fintrin_deallocate -> assert_nargs fintr 1 arglist | Fintrin_allocated -> assert_nargs fintr 1 arglist | Fintrin_nullify -> assert_nargs fintr 1 arglist (* Binary. *) | Fintrin_lbound -> assert_nargs fintr 2 arglist | Fintrin_ubound -> assert_nargs fintr 2 arglist | Fintrin_selected_real_kind -> assert_nargs fintr 2 arglist | Fintrin_ior -> assert_nargs fintr 2 arglist | Fintrin_iand -> assert_nargs fintr 2 arglist | Fintrin_ieor -> assert_nargs fintr 2 arglist | Fintrin_ishft -> assert_nargs fintr 2 arglist | Fintrin_mod -> assert_nargs fintr 2 arglist | Fintrin_modulo -> assert_nargs fintr 2 arglist | Fintrin_dot_product -> assert_nargs fintr 2 arglist | Fintrin_matmul -> assert_nargs fintr 2 arglist | Fintrin_max -> if (List.length arglist) < 2 then error "too few arguments for intrinsic: MAX" | Fintrin_min -> if (List.length arglist) < 2 then error "too few arguments for intrinsic: MIN" | Fintrin_associated -> if ((List.length arglist) = 1) || ((List.length arglist) = 2) then error "incorrect number of arguments for intrinsic: ASSOCIATED" let rec fpp_fexpression (fexp: fexpression) prio = let newprio = get_expr_prio fexp in (if prio > newprio then printstr "("); begin match fexp with Fexp_nop -> printstr "C " | Fexp_variable(varexp) -> fpp_fvar_expression varexp | Fexp_const(con) -> begin match con with Fconst_int(str, str_kindo) -> printstr str; printstr (match str_kindo with None -> "" | Some(sss) -> ("_" ^ sss)) | Fconst_real(str, str_kindo) -> printstr str; printstr (match str_kindo with None -> "" | Some(sss) -> ("_" ^ sss)) | Fconst_realdbl(str) -> (* The string may have "e[sign]int" embedded; change it to "D". If there is no suffix, add "D0". *) let tmpstr = String.copy str in let changed = ref false in let len = String.length tmpstr in let i = ref 0 in while (!i < len) && (!changed = false) do if tmpstr.[!i] = 'e' || tmpstr.[!i] = 'E' then (tmpstr.[!i] <- 'D'; changed := true); incr i done; printstr (tmpstr ^ (if !changed then "" else "D0")) | Fconst_char(str) -> printstr ("'" ^ str ^ "'") | Fconst_logical(bv) -> printstr (if bv then ".true." else ".false.") | Fconst_star -> printstr "*" end | Fexp_binary(oper, exp1, exp2) -> fpp_fexpression exp1 newprio; printstr (" " ^ (string_of_fbinop oper) ^ " "); fpp_fexpression exp2 newprio | Fexp_unary(oper, exp) -> printstr (" " ^ (string_of_funop oper)); fpp_fexpression exp newprio | Fexp_intrinsic(fintr, exp_arglist) -> check_intrin_argcnt fintr exp_arglist; printstr ((string_of_fintrinsic fintr) ^ "("); let prtit = (fun item -> fpp_fexpression item 0) in prt_delimited_list prtit ", " exp_arglist; printstr ")" | Fexp_fcall(str_name, exp_arglist) -> printstr (str_name ^ "("); let prtit = (fun item -> fpp_fexpression item 0) in prt_delimited_list prtit ", " exp_arglist; printstr ")" end; (if prio > newprio then printstr ")") and fpp_fbasic_type btype = let kindprt = (fun k -> match k with None -> (); | Some(fe) -> printstr "(kind="; fpp_fexpression fe 0; printstr ")") in match btype with Ftype_character(expleno) -> printstr "character"; (match expleno with None -> () | Some(fe) -> printstr "(len="; fpp_fexpression fe 0; printstr ")") | Ftype_complex(expkindo) -> printstr "complex"; kindprt expkindo | Ftype_dbl_prec -> printstr "double precision" | Ftype_integer(expkindo) -> printstr "integer"; kindprt expkindo | Ftype_logical(expkindo) -> printstr "logical"; kindprt expkindo | Ftype_real(expkindo) -> printstr "real"; kindprt expkindo | Ftype_type(str_name) -> printstr ("type(" ^ str_name ^ ")") and fpp_fsubscript fsub = match fsub with Fsub_simple(fexp) -> fpp_fexpression fexp 0 | Fsub_triplet(expo_lb, expo_ub, expo_stride) -> (match expo_lb with None -> () | Some(lb) -> fpp_fexpression lb 0); printstr ":"; (match expo_ub with None -> () | Some(ub) -> fpp_fexpression ub 0); (match expo_stride with None -> () | Some(st) -> printstr ":"; fpp_fexpression st 0) and fpp_fvar_expression fvarexp = match fvarexp with Fvar_ident(str_name) -> printstr str_name | Fvar_arrayref(str_name, sublist) -> printstr (str_name ^ "("); prt_delimited_list fpp_fsubscript ", " sublist; printstr ")" | Fvar_pathref(varexp_list) -> prt_delimited_list fpp_fvar_expression "%" varexp_list and fpp_fspec_attr btype = match btype with Fattr_allocatable -> printstr "allocatable" | Fattr_common -> printstr "common" | Fattr_data -> printstr "data" | Fattr_dimension(sublist) -> printstr "dimension("; prt_delimited_list fpp_fsubscript ", " sublist; printstr ")" | Fattr_equivalence -> printstr "equivalence" | Fattr_extent -> printstr "extent" | Fattr_external -> printstr "external" | Fattr_intent_in -> printstr "intent(in)" | Fattr_intent_out -> printstr "intent(out)" | Fattr_intent_inout -> printstr "intent(inout)" | Fattr_intrinsic -> printstr "intrinsic" | Fattr_optional -> printstr "optional" | Fattr_parameter -> printstr "parameter" | Fattr_pointer -> printstr "pointer" | Fattr_private -> printstr "private" | Fattr_public -> printstr "public" | Fattr_save -> printstr "save" | Fattr_target -> printstr "target" let rec fpp_fstatement (fstmt : fstatement) ind = match fstmt with Fstmt_assign(varexp, exp_rhs) -> indent ind; fpp_fvar_expression varexp; printstr " = "; fpp_fexpression exp_rhs 0; newln () | Fstmt_assignptr(exp_lhs, exp_rhs) -> indent ind; fpp_fexpression exp_lhs 0; printstr " => "; fpp_fexpression exp_rhs 0; newln () | Fstmt_call(str_name, explist_args) -> indent ind; printstr ("call " ^ str_name); (if (explist_args <> []) then printstr "("; let prtit = (fun item -> fpp_fexpression item 0) in prt_delimited_list prtit ", " explist_args; printstr ")"); newln () | Fstmt_do(str_ivar, exp_lb, exp_ub, exp_stepo, do_stmts) -> indent ind; printstr ("do " ^ str_ivar ^ " = "); fpp_fexpression exp_lb 0; printstr ", "; fpp_fexpression exp_ub 0; (match exp_stepo with None -> () | Some(zzz) -> printstr ", "; fpp_fexpression zzz 0); newln (); List.iter (fun item -> fpp_fstatement item (ind+2)) do_stmts; indent ind; printstr "enddo"; newln () | Fstmt_do_while(exp_cond, do_stmts) -> indent ind; printstr "do while ("; fpp_fexpression exp_cond 0; printstr ")"; newln (); List.iter (fun item -> fpp_fstatement item (ind+2)) do_stmts; indent ind; printstr "enddo"; newln () | Fstmt_if(exp_cond, if_stmt) -> indent ind; printstr "if ("; fpp_fexpression exp_cond 0; printstr ")"; newln (); fpp_fstatement if_stmt (ind+2) | Fstmt_ifthenelse(exp_cond, then_stmts, else_stmtso) -> indent ind; printstr "if ("; fpp_fexpression exp_cond 0; printstr ") then"; newln (); List.iter (fun item -> fpp_fstatement item (ind+2)) then_stmts; (match else_stmtso with None -> () | Some(estmts) -> indent ind; printstr "else"; newln (); List.iter (fun item -> fpp_fstatement item (ind+2)) estmts); indent ind; printstr "endif"; newln () | Fstmt_goto(str_lineno) -> indent ind; printstr ("goto " ^ str_lineno); newln () | Fstmt_computed_goto(str_linelist, exp_goto) -> indent ind; printstr "goto ("; prt_delimited_list printstr ", " str_linelist; printstr "), "; fpp_fexpression exp_goto 0; newln () | Fstmt_return(exp_reto) -> indent ind; printstr "return "; (match exp_reto with None -> () | Some(exp_ret) -> fpp_fexpression exp_ret 0); (* Alternate return. *) newln () | Fstmt_continue -> indent ind; printstr "continue"; newln () | Fstmt_stop -> indent ind; printstr "stop"; newln () | Fstmt_end -> indent ind; printstr "end"; newln () | Fstmt_select(exp_sel, selbody_list) -> indent ind; printstr "select case ("; fpp_fexpression exp_sel 0; printstr ")"; newln (); if (selbody_list = []) then error "Fstmt_select with no cases"; for i = 1 to (List.length selbody_list) do match (List.nth selbody_list (i-1)) with Fsel_case(exp_list, cstmts) -> indent ind; printstr "case("; let prtit = (fun item -> fpp_fexpression item 0) in prt_delimited_list prtit ", " exp_list; printstr ")"; newln (); List.iter (fun item -> fpp_fstatement item (ind+2)) cstmts; | Fsel_default(cstmts) -> indent ind; printstr "case default"; newln (); List.iter (fun item -> fpp_fstatement item (ind+2)) cstmts; done; indent ind; printstr "end select"; newln () | Fstmt_cycle -> indent ind; printstr "cycle"; newln () | Fstmt_exit -> indent ind; printstr "exit"; newln () let rec fpp_fspecification fspec ind = match fspec with Fspec_decl(btype, attrlist, name_init_pairlist) -> indent ind; fpp_fbasic_type btype; if attrlist <> [] then (printstr ", "; prt_delimited_list fpp_fspec_attr ", " attrlist); printstr " :: "; let print_nm_init_pair = fun (itemstr, itemexpr) -> printstr itemstr; match itemexpr with None -> () | Some(exp) -> printstr "="; fpp_fexpression exp 0 in prt_delimited_list print_nm_init_pair ", " name_init_pairlist; newln () | Fspec_udtdecl(str_name, speclist) -> (* Declaration of user-defined type. *) indent ind; printstr ("type " ^ str_name); newln (); for i = 1 to (List.length speclist) do fpp_fspecification (List.nth speclist (i-1)) (ind+2); done; indent ind; printstr "end type"; newln () | Fspec_implicit_none -> indent ind; printstr "implicit none"; newln () | Fspec_use(str_name, orenamel) -> indent ind; printstr ("use " ^ str_name); (match orenamel with None -> () | Some(renamel) -> printstr ", "; let prtit = (function (localname, mname) -> printstr (localname ^ " => " ^ mname)) in prt_delimited_list prtit ", " renamel); newln () | Finterface_blk(strnameo, subproglist, str_modproclist) -> let name = (match strnameo with None -> "" | Some(ss) -> ss) in indent ind; printstr ("interface" ^ name); newln (); let dosub = (fun (Finterface_subprog(hdr, specl)) -> fpp_fsubprog_header hdr (ind+2); List.iter (fun item -> fpp_fspecification item (ind+2)) specl; fpp_finalize_subprog hdr (ind+2)) in List.iter dosub subproglist; if str_modproclist <> [] then (indent (ind+2); printstr "module procedure "; prt_delimited_list printstr ", " str_modproclist; newln ()); indent ind; printstr "end interface"; newln () and fpp_fsubprog_body body ind = List.iter (fun item -> fpp_fspecification item ind) body.specs; List.iter (fun item -> fpp_fstatement item ind) body.fstmts; if body.contained <> [] then (indent ind; printstr "contains"; newln (); List.iter (fun item -> fpp_fsubprog_def item (ind+2)) body.contained) and fpp_fsubprog_def topdef ind = let Fsubprog(hdr, body) = topdef in fpp_fsubprog_header hdr ind; fpp_fsubprog_body body ind; fpp_finalize_subprog hdr ind; and fpp_fsubprog_header hdr ind = match hdr with Fhdr_function(str_name, str_formals) -> indent ind; printstr ("function " ^ str_name ^ "("); prt_delimited_list printstr ", " str_formals; printstr ")"; newln () | Fhdr_recfunction(str_name, str_formals, str_resname) -> indent ind; printstr ("recursive function " ^ str_name ^ "("); prt_delimited_list printstr ", " str_formals; printstr (") result (" ^ str_resname ^ ")"); newln () | Fhdr_subroutine(str_name, str_formals) -> indent ind; printstr ("subroutine " ^ str_name); if str_formals <> [] then (printstr "("; prt_delimited_list printstr ", " str_formals; printstr ")"); newln () | Fhdr_program(str_name) -> indent ind; printstr ("program " ^ str_name); newln () | Fhdr_module(str_name) -> indent ind; printstr ("module " ^ str_name); newln () and fpp_finalize_subprog hdr ind = indent ind; match hdr with Fhdr_function(str_name, str_formals) -> printstr "end function"; newln () | Fhdr_recfunction(str_name, str_formals, str_resname) -> printstr "end function"; newln () | Fhdr_subroutine(str_name, str_formals) -> printstr "end subroutine"; newln () | Fhdr_program(str_name) -> printstr "end program"; newln () | Fhdr_module(str_name) -> (* (if body.fstmts <> [] then error "Fhdr_module cannot have statements"); *) printstr "end module"; newln () let fpp_fcompilation_unit pu = output_string := ""; curr_str := ""; printstr ("! This file was automatically generated: " ^ version_f90abs); newln (); List.iter (fun item -> fpp_fsubprog_def item min_indent; newln ()) pu.topdefs; !output_string (*********************************************************************) (*********************************************************************) (* Unit testing of fabs. *) let mksimpvar str = Fexp_variable(Fvar_ident(str));; let aryref = Fexp_variable(Fvar_arrayref("ary", [Fsub_simple(mksimpvar "I"); Fsub_triplet(Some(Fexp_const(Fconst_int("1", None))), Some(mksimpvar("M")), Some(Fexp_const(Fconst_int("2", None)))); Fsub_triplet(Some(Fexp_const(Fconst_int("J", None))), Some(mksimpvar("K")), None)]));; let ein1 = Fexp_intrinsic(Fintrin_cos, [aryref]);; let ein2 = Fexp_intrinsic(Fintrin_ishft, [mksimpvar("u"); mksimpvar("sc")]);; let einN = Fexp_intrinsic(Fintrin_max, [mksimpvar("p1"); mksimpvar("p2"); mksimpvar("p3")]);; let e1 = Fexp_binary(Fbinop_add, ein1, ein2);; let e2 = Fexp_binary(Fbinop_add, einN, Fexp_binary(Fbinop_and, mksimpvar("g"), mksimpvar("h")));; let ecall = Fexp_fcall("somefunc", [mksimpvar("arg")]) let seq = [Fstmt_assign(Fvar_ident("a"), e1); Fstmt_call("somesubrt",[ecall; mksimpvar("arg2")])];; let sbody = [Fsel_case([Fexp_const(Fconst_int("0",Some("mykind")))], [Fstmt_stop]); Fsel_case([Fexp_const(Fconst_int("2", Some("8"))); Fexp_const(Fconst_int("8", None))], [Fstmt_stop]); Fsel_default(seq)] let s0 = Fstmt_select(mksimpvar("g"), sbody);; let s1 = Fstmt_do("j", Fexp_const(Fconst_int("1", None)), Fexp_const(Fconst_int("8", None)), None, [s0]);; let s2 = Fstmt_do("i", Fexp_const(Fconst_int("4", None)), Fexp_const(Fconst_int("64", None)), Some(Fexp_const(Fconst_int("4", None))), [s1]);; let s3 = Fstmt_do_while(Fexp_const(Fconst_logical(false)), [s2]);; let subs= [Fsub_simple(Fexp_const(Fconst_int("5", None))); Fsub_triplet(Some(Fexp_const(Fconst_int("1", None))), (* Some(mksimpvar("M")) *) Some(Fexp_const(Fconst_star)), None)];; let specs0 = [Fspec_decl(Ftype_integer(None), [Fattr_dimension(subs)], [("glob1", None); ("glob2", None)])];; let conts0 = [Fsubprog(Fhdr_function("innerfunc1", []), { specs = []; fstmts = [Fstmt_goto("fake")] ; contained = []})];; let body0 = { specs = specs0; fstmts = []; contained = conts0; };; let subprog0 = Fsubprog(Fhdr_module("ModName"), body0);; let spintblk0 = (Fspec_decl(Ftype_character(None), [], [("ch1", None)])) ;; let intblk0 = Finterface_blk(None, [Finterface_subprog(Fhdr_subroutine("SubName", ["ch1"]), [spintblk0])], ["modproc1"; "modproc2"]);; let udtdecl = Fspec_udtdecl("a_udt", [Fspec_decl(Ftype_character(Some(Fexp_const(Fconst_int("13", None)))), [], [("ccc", None)]); Fspec_decl(Ftype_real(Some(Fexp_const(Fconst_int("2", None)))), [], [("ua", Some(Fexp_const(Fconst_real("3.14", Some("rkind"))))); ("ub", None)])]);; let udt1 = Fspec_decl(Ftype_type("a_udt"), [], [("name1", None)]);; let body1 = { specs = [Fspec_use("ModName", None (* Some([("loc1","m1"); ("loc2","m2")]) *)); Fspec_implicit_none; intblk0; Fspec_decl(Ftype_integer(None), [Fattr_target; Fattr_save], [("a", Some(Fexp_const(Fconst_int("5", None)))); ("b", Some(Fexp_const(Fconst_int("256", None))))]); udtdecl; udt1]; fstmts = [Fstmt_cycle]; contained = []; } let subprog1 = Fsubprog(Fhdr_program("ProgName"), body1);; let body2 = { specs = [Fspec_decl(Ftype_real(None), [], [("x", None)]); Fspec_decl(Ftype_dbl_prec, [Fattr_save], [("d1", None); ("d2", None); ("d3", None)]); Fspec_decl(Ftype_complex(None), [], [("cpx", None)])]; fstmts = [s3]; contained = []; } let subprog2 = Fsubprog(Fhdr_function("FuncName", ["x"; "cpx"]), body2);; let body3 = { specs = [Fspec_decl(Ftype_logical(None), [], [("gl1", Some(Fexp_const(Fconst_logical(true))))])]; fstmts = [Fstmt_exit]; contained = []; } let subprog3 = Fsubprog(Fhdr_recfunction("RecFuncName", ["n"], "fRes"), body3);; let cont4 = Fsubprog(Fhdr_function("innerfunc4", ["gh1"; "gh2"]), { specs = [Fspec_decl(Ftype_dbl_prec, [], [("dbl00", None)])]; fstmts = [Fstmt_continue] ; contained = []});; let cont45 = Fsubprog(Fhdr_subroutine("innersub45", []), { specs = [Fspec_decl(Ftype_real(None), [], [("real00", None)])]; fstmts = [Fstmt_cycle] ; contained = []});; let body4 = { specs = [Fspec_decl(Ftype_character(None), [], [("ch1", None)])]; fstmts = [Fstmt_assign((Fvar_arrayref("uary", [Fsub_simple(mksimpvar "L")])), Fexp_const(Fconst_char("A")))]; contained = [cont4; cont45]; } let subprog4 = Fsubprog(Fhdr_subroutine("SubName", ["ch1"]), body4);; let pu = { topdefs = [subprog0; subprog1; subprog2; subprog3; subprog4]; };; (* Printf.printf "%s" (fpp_fcompilation_unit pu);; *) (*********************************************************************) (*********************************************************************)