File: lexstate.ml

package info (click to toggle)
hevea 2.38-1
  • links: PTS, VCS
  • area: main
  • in suites: forky, sid
  • size: 3,824 kB
  • sloc: ml: 19,525; sh: 505; makefile: 311; ansic: 132
file content (848 lines) | stat: -rw-r--r-- 21,537 bytes parent folder | download
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
(***********************************************************************)
(*                                                                     *)
(*                          HEVEA                                      *)
(*                                                                     *)
(*  Luc Maranget, projet PARA, INRIA Rocquencourt                      *)
(*                                                                     *)
(*  Copyright 1998 Institut National de Recherche en Informatique et   *)
(*  Automatique.  Distributed only by permission.                      *)
(*                                                                     *)
(***********************************************************************)

open Printf
open Misc
open Lexing
open MyStack



(* Commands nature *)
type action =
  | Subst of string list
  | Toks of string list
  | CamlCode of (Lexing.lexbuf -> unit)

let body_to_string = String.concat ""

let pretty_body chan = List.iter(fprintf chan "%s")

let pretty_action acs =
   match acs with
   | Subst s    ->
       eprintf "{%a}" (fun chan -> List.iter (fprintf chan "\"%s\" ")) s
   | Toks l ->
       List.iter
         (fun s -> Printf.fprintf stderr "{%s}, " s)
         l
   | CamlCode _ -> prerr_string "*code*"

let rec is_empty_list = function
  | [] -> true
  | x::xs -> String.length x = 0 && is_empty_list xs

type pat = string list * string list


let pretty_pat (_,args) =
  List.iter (fun s -> prerr_string s ; prerr_char ',') args

let is_subst body = match body with
| CamlCode _ -> false
| _ -> true

let latex_pat opts n =
  let n_opts = List.length opts in
  let rec do_rec r i =
    if i <=  n_opts  then r
    else do_rec (("#"^string_of_int i)::r) (i-1) in
  opts,do_rec [] n

let zero_pat = latex_pat [] 0
and one_pat  = latex_pat [] 1

(* Environments *)
type subst = Top | Env of string list arg array
and 'a arg = {arg : 'a ; subst : subst }

let mkarg arg subst = {arg=arg ; subst=subst }



type alltt = Not | Inside | Macro

let effective = function
  | Inside -> true
  | _      -> false

let subst = ref Top
and alltt = ref Not

let stack_subst = MyStack.create "stack_subst"
and stack_alltt = MyStack.create_init "stack_alltt" Not

let get_subst () = !subst
let top_subst = Top



let pretty_subst = function
  | Top -> prerr_endline "Top level"
  | Env args ->      
      if Array.length args <> 0 then begin
        prerr_endline "Env: " ;
        for i = 0 to Array.length args - 1 do
          prerr_string "\t'" ;
          eprintf "%a" pretty_body args.(i).arg  ;
          prerr_endline "'"
        done
      end

let rec pretty_subst_rec indent = function
  | Top -> prerr_string indent ; prerr_endline "Top level"
  | Env args ->      
      if Array.length args <> 0 then begin
        prerr_string indent ;
        prerr_endline "Env: " ;
        for i = 0 to Array.length args - 1 do
          prerr_string indent ;
          prerr_string ("  #"^string_of_int (i+1)^" ``");
          pretty_body stderr args.(i).arg ;
          prerr_endline "''" ;
          pretty_subst_rec ("  "^indent) args.(i).subst
        done
      end

let full_pretty_subst s = pretty_subst_rec "  " s

exception Error of string
exception SubstTop
type jax = JaxOut | JaxInline | JaxDisplay
  
(* Status flags *)
let display = ref false
and spaced_display = ref false
and raw_chars = ref false
and in_math = ref false
and jaxauto = ref false
and injaxauto = ref JaxOut
and whitepre = ref false
and optarg = ref false
and styleloaded = ref false
and activebrace = ref true
and html = 
  ref
    (match !Parse_opts.destination with
    | Parse_opts.Html -> true
    | Parse_opts.Info | Parse_opts.Text -> false)
and text = 
  ref
    (match !Parse_opts.destination with
    | Parse_opts.Html -> false
    | Parse_opts.Info | Parse_opts.Text -> true)
and alltt_loaded = ref false

(* Additional variables for videoc *)
and withinLispComment = ref false
and afterLispCommentNewlines = ref 0
(* Additional flags for transformations *)
;;
type case = Upper | Lower | Neutral
let case = ref Neutral
;;


let string_to_arg arg = {arg=arg ; subst= !subst }

(* Stacks for flags *)
let stack_in_math = MyStack.create "stack_in_math"
and stack_display = MyStack.create "stack_display"

(* Stacks for entry stream  *)
let stack_lexbuf = MyStack.create "stack_lexbuf"
;;

let pretty_lexbuf lb =
  let  pos = lb.lex_curr_pos and len = Bytes.length lb.lex_buffer in
  prerr_endline "Buff contents:" ;
  let size = if !verbose > 3 then len-pos else min (len-pos) 80 in
  if size <> len-pos then begin
    prerr_string "<<" ;
    prerr_string (Bytes.sub_string lb.lex_buffer pos (size/2)) ;
    prerr_string "... (omitted) ..." ;
    prerr_string (Bytes.sub_string lb.lex_buffer (len-size/2-1) (size/2)) ;
    prerr_endline ">>"
  end else
    prerr_endline ("<<"^Bytes.sub_string lb.lex_buffer pos size^">>");
  prerr_endline ("curr_pos="^string_of_int lb.lex_curr_pos);
  prerr_endline "End of buff"
;;

  
(* arguments inside macros*)
type closenv = string array t


(* catcodes *)

let plain_of_char = function
  | '{' -> 0
  | '}' -> 1
  | '$' -> 2
  | '&' -> 3
  | '#' -> 4
  | '^' -> 5
  | '_' -> 6
  | '~' -> 7
  | '\\' -> 8
  | '%'  -> 9
  | '\'' -> 10
  | '`' -> 11
  | '-' -> 12
  | '"' -> 13 (* '"' *)
  | c   ->
      raise
        (Fatal ("Internal catcode table error: '"^String.make 1 c^"'"))

and plain = Array.make 14 true

let is_plain c = plain.(plain_of_char c)
and set_plain c =
(*  if c = '_' then eprintf "set_plain %c\n" c ; *)
  plain.(plain_of_char c) <- true
and unset_plain c =
(*  if c = '_' then eprintf "unset_plain %c\n" c ; *)
  plain.(plain_of_char c) <- false
and plain_back b c =
(*  if c = '_' then eprintf "plain_back %c <- %b\n" c b ; *)
  plain.(plain_of_char c) <- b


let top_level () = match !subst with Top -> true | _ -> false
and is_top = function
  | Top -> true
  | _   -> false


let prerr_args () = pretty_subst !subst


let scan_arg lexfun i  = match !subst with
  | Top ->  raise SubstTop
  | Env args ->
      if i >= Array.length args then begin
        if !verbose > 1 then begin
          prerr_string ("Subst arg #"^string_of_int (i+1)^" -> not found") ;
          pretty_subst !subst
        end ;
        raise (Error "Macro argument not found")
      end;
      let arg = args.(i) in
      if !verbose > 1 then begin
        eprintf
          "Subst arg #%i -> %a\n" i pretty_body arg.arg
      end ;
      let r = lexfun arg in
      r

and scan_body do_exec body args = match body with
| CamlCode _|Toks _ -> do_exec body
| Subst _ -> 
    let old_subst = !subst in
    subst := args ;
    let r = do_exec body in
    subst := old_subst ;
    r

(* Recoding and restoring lexbufs *)

let record_lexbuf lexbuf subst =
  MyStack.push stack_subst subst ;
  MyStack.push stack_lexbuf lexbuf ;

and previous_lexbuf () =
  let lexbuf = MyStack.pop stack_lexbuf in
  subst := MyStack.pop stack_subst ;
  lexbuf
;;

(* Saving and restoring lexing status *)

let stack_lexstate = MyStack.create "stack_lexstate"

let top_lexstate () = MyStack.empty stack_lexstate

let save_lexstate () =
  let old_stack = MyStack.save stack_subst in
  MyStack.push stack_subst !subst ;
  push stack_lexstate
    (MyStack.save stack_lexbuf,
     MyStack.save stack_subst) ;
  MyStack.restore stack_subst old_stack

and restore_lexstate () =
  let lexbufs,substs = pop stack_lexstate in
  MyStack.restore stack_lexbuf lexbufs ;
  MyStack.restore stack_subst substs ;
  subst := MyStack.pop stack_subst

(* Flags save and restore *)
let save_flags () = 
  push stack_display !display ;
  push stack_in_math !in_math

and restore_flags () =
  in_math := pop stack_in_math ;
  display := pop stack_display

(* Total checkpoint of lexstate *)
type saved_lexstate = 
(Lexing.lexbuf MyStack.saved * subst MyStack.saved) MyStack.saved *
bool MyStack.saved * bool MyStack.saved

let check_lexstate () =
  save_lexstate () ;
  save_flags () ;
  let r =
    MyStack.save stack_lexstate,
    MyStack.save stack_display,
    MyStack.save stack_in_math in
  restore_lexstate () ;
  restore_flags () ;
  r

and hot_lexstate (l,d,m) =
  MyStack.restore stack_lexstate l ;
  MyStack.restore stack_display d ;
  MyStack.restore stack_in_math m ;
  restore_lexstate ()  ;
  restore_flags ()
;;

(* Blank lexing status *)
let start_lexstate () =
  save_lexstate () ;
  MyStack.restore stack_lexbuf (MyStack.empty_saved) ;
  MyStack.restore stack_subst (MyStack.empty_saved)

let start_lexstate_subst this_subst =
  start_lexstate () ;
  subst := this_subst
;;

let flushing = ref false
;;


let start_normal this_subst =
  start_lexstate () ;
  save_flags () ;
  display := false ;
  in_math := false ;
  subst := this_subst

and end_normal () =
  restore_flags () ;
  restore_lexstate ()
;;

let full_peek_char lexbuf =
  let rec full_peek lexbuf =
    try
      Save.peek_next_char lexbuf
    with Not_found ->
      if MyStack.empty stack_lexbuf then
        raise Not_found
      else
        full_peek (previous_lexbuf ()) in
  full_peek lexbuf
        
let full_save_arg eoferror mkarg parg lexfun lexbuf =
  let rec save_rec lexbuf =
    try
      let arg = lexfun lexbuf in
      mkarg arg !subst
    with Save.Eof -> begin
        if MyStack.empty stack_lexbuf then
           eoferror () 
        else begin
          let lexbuf = previous_lexbuf () in
          if !verbose > 1 then begin
            prerr_endline "popping stack_lexbuf in full_save_arg";
            pretty_lexbuf lexbuf ;
            prerr_args ()
          end;
          save_rec lexbuf
        end
    end in

  let start_pos = Location.get_pos () in
  try 
    Save.seen_par := false ;
    save_lexstate () ;
    let r = save_rec lexbuf in
    restore_lexstate () ;
    if !verbose > 2 then
      prerr_endline ("Arg parsed: '"^parg r^"'") ;
    r
  with
  | (Save.Error _ | Error _) as e ->
      restore_lexstate () ;
      Save.seen_par := false ;
      Location.print_this_pos start_pos ;
      prerr_endline "Parsing of argument failed" ;
      raise e
  | e ->
      restore_lexstate () ;
      raise e
;;

let full_save_arg_limits eoferror parg lexfun lexbuf =
  let rec save_rec opt some_space lexbuf =
    try
      lexfun opt some_space lexbuf
    with Save.LimitEof (lim,some_space) -> begin
        if MyStack.empty stack_lexbuf then
          match lim with
          | None -> eoferror () 
          | _ -> (lim,some_space)
        else begin
          let lexbuf = previous_lexbuf () in
          if !verbose > 1 then begin
            prerr_endline "popping stack_lexbuf in full_save_arg_limits";
            pretty_lexbuf lexbuf ;
            prerr_args ()
          end;
          save_rec lim some_space lexbuf
        end
    end in

  let start_pos = Location.get_pos () in
  try 
    Save.seen_par := false ;
    save_lexstate () ;
    let r = save_rec None false lexbuf in
    restore_lexstate () ;
    if !verbose > 2 then
      prerr_endline ("Arg parsed: '"^parg r^"'") ;
    r
  with
  | (Save.Error _ | Error _) as e ->
      restore_lexstate () ;
      Save.seen_par := false ;
      Location.print_this_pos start_pos ;
      prerr_endline "Parsing of argument failed" ;
      raise e
  | e ->
      restore_lexstate () ;
      raise e
;;


type ok = No of string | Yes of string list
;;

let parg {arg=arg} = arg
and pargs {arg=args} = String.concat ", " args
and parg_list {arg=xs} = body_to_string xs

and pok = function
  | {arg=Yes s} -> String.concat "" s
  | {arg=No s} -> "* default arg: ["^s^"] *"


let eof_arg () =
  Save.empty_buffs () ;
  raise (Error "Eof while looking for argument")

let save_arg lexbuf =
  full_save_arg eof_arg mkarg parg Save.arg lexbuf
and save_body lexbuf =
    full_save_arg eof_arg mkarg parg_list Save.arg_list lexbuf
and save_arg_with_delim delim lexbuf =
  full_save_arg eof_arg mkarg parg (Save.with_delim delim) lexbuf
and save_filename lexbuf =
  full_save_arg eof_arg mkarg parg Save.filename lexbuf
and save_verbatim lexbuf =
  full_save_arg eof_arg mkarg parg Save.arg_verbatim lexbuf
and save_xy_arg lexbuf =
  full_save_arg eof_arg mkarg parg Save.xy_arg lexbuf
and save_cite_arg lexbuf =
  full_save_arg eof_arg mkarg pargs Save.cite_arg lexbuf

type sup_sub = {
  limits : Misc.limits option;
  space : bool; (* Some space has been eaten *)
  sup : string arg ;
  sub : string arg ;
} 

let plimits (lim,sp) =
  (match lim with
  | Some Limits ->    "\\limits"
  | Some NoLimits ->  "\\nolimits"
  | Some IntLimits -> "\\intlimits"
  | None          -> "*no limit info*")
  ^ (if sp then "+spaces" else "")

exception Over
let eof_over () = raise Over

let save_limits lexbuf =
  let rec do_rec (res:Misc.limits option * bool) =
    try
      let r =
        full_save_arg_limits
          eof_over plimits  Save.get_limits lexbuf in
      match r with
      | None,_ -> res
      | Some _,_ -> do_rec r
    with
    | Over -> res in
  do_rec (None,false)

let mkoptionarg opt subst = match opt with
| None -> None
| Some s -> Some (mkarg s subst)

and poptionarg = function
| None -> "*None*"
| Some a -> a.arg

let save_sup lexbuf =
  try
   full_save_arg eof_over mkoptionarg poptionarg Save.get_sup lexbuf
  with
  | Over -> None

and save_sub lexbuf =
  try
    full_save_arg eof_over mkoptionarg poptionarg Save.get_sub lexbuf
  with
  | Over -> None

let unoption = function
  | None   -> {arg="" ; subst=top_subst }
  | Some a -> a

let save_sup_sub lexbuf =
  let limits,space = save_limits lexbuf in
  match save_sup lexbuf with
  | None ->
      let sub = save_sub lexbuf in
      let sup = save_sup lexbuf in
      {limits; space; sup = unoption sup; sub = unoption sub; }
  | Some sup ->
      let sub = save_sub lexbuf in
      {limits; space; sup = sup; sub = unoption sub; }

let protect_save_string lexfun lexbuf =
  full_save_arg eof_arg
    (fun s _ -> s)
    (fun s -> s)
    lexfun lexbuf

let eof_opt default () = {arg=No default ; subst=Top }

let save_arg_opt default lexbuf =
  let r = 
    full_save_arg
      (eof_opt default)
      mkarg
      pok
      (fun lexbuf ->
        try Yes (Save.opt_list lexbuf) with          
        | Save.NoOpt -> No default)
      lexbuf in
  match r.arg with
  | Yes _ -> r
  | No  _ -> mkarg (No default) !subst
      
  
;;


let from_ok okarg = match okarg.arg with
  | Yes s ->
      optarg := true ;
      mkarg s okarg.subst
  | No s  ->
      optarg := false ;
      mkarg [s] okarg.subst

let pretty_ok = function
  Yes s -> "+"^String.concat "" s^"+"
| No s  -> "-"^s^"-"
;;


let norm_arg s =
  String.length s = 2 && s.[0] = '#' &&
  ('0' <= s.[1] && s.[1] <= '9')

let list_arg a = { a with arg = [a.arg] }

let rec parse_args_norm pat lexbuf = match pat with
|   [] -> []
| s :: (ss :: _ as pat) when norm_arg s && norm_arg ss ->
    let arg = save_body lexbuf in
    let r = parse_args_norm pat lexbuf in
     arg :: r
| s :: ss :: pat when norm_arg s && not (norm_arg ss) ->
    let arg = save_arg_with_delim ss lexbuf in
    list_arg arg :: parse_args_norm pat lexbuf
| s :: pat when not (norm_arg s) ->
    Save.skip_delim s lexbuf ;
    parse_args_norm pat lexbuf
| _ :: pat ->
    let arg = save_body lexbuf in
    let r = parse_args_norm pat lexbuf in
    arg :: r
;;


let skip_csname lexbuf =
  let _ = Save.csname (fun x -> x) (fun x -> x) lexbuf in
  ()


let skip_opt lexbuf =
  let _ =  save_arg_opt "" lexbuf  in
  ()

and save_opt def lexbuf = from_ok (save_arg_opt def lexbuf)
;;

let rec save_opts pat lexbuf = match pat with
  [] -> []
| def::rest ->
   let arg = save_arg_opt def lexbuf in
   let r = save_opts rest lexbuf in
   arg :: r
;;


let parse_args (popt,pat) lexbuf =
  Save.seen_par := false ;
  let opts =  save_opts popt lexbuf in
  begin match pat with
  | s :: ss :: _ when norm_arg s && not (norm_arg ss) ->
      Save.skip_blanks_init lexbuf
  | _ -> ()
  end ;
  let args =  parse_args_norm pat lexbuf in
  (opts,args)
;;

let make_stack name pat lexbuf =
  try
    let (opts,args) = parse_args pat lexbuf in
    let args = Array.of_list (List.map from_ok opts@args) in
    if !verbose > 1 then begin
      Printf.fprintf stderr "make_stack for macro: %s "  name ;
      pretty_pat pat ;
      prerr_endline "";
      for i = 0 to Array.length args-1 do
        Printf.fprintf stderr "\t#%d = %a\n" (i+1) pretty_body args.(i).arg ;
        pretty_subst (args.(i).subst)
      done
    end ;
    Env args
  with Save.Delim delim ->
    raise
      (Error
         ("Use of "^name^
          " does not match its definition (delimiter: "^delim^")"))
    
;;

let scan_this lexfun s =
  start_lexstate ();
  if !verbose > 1 then begin
    Printf.fprintf stderr "scan_this : [%s]" s ;
    prerr_endline ""  
  end ;
  let lexbuf = MyLexing.from_string s in
  let r = lexfun lexbuf in
  if !verbose > 1 then begin
    Printf.fprintf stderr "scan_this : over" ;
    prerr_endline ""
  end ;
  restore_lexstate ();
  r

and scan_this_list lexfun xs =
  start_lexstate ();
  if !verbose > 1 then begin
    eprintf "scan_this_list : [%a]" pretty_body xs ;
    prerr_endline ""  
  end ;
  let lexbuf = MyLexing.from_list xs in
  let r = lexfun lexbuf in
  if !verbose > 1 then begin
    Printf.fprintf stderr "scan_this_list : over" ;
    prerr_endline ""
  end ;
  restore_lexstate ();
  r

and scan_this_arg lexfun {arg=s ; subst=this_subst } =
  start_lexstate () ;
  subst := this_subst ;
  if !verbose > 1 then begin
    Printf.fprintf stderr "scan_this_arg : [%s]" s ;
    prerr_endline ""  
  end ;
  let lexbuf = MyLexing.from_string s in
  let r = lexfun lexbuf in
  if !verbose > 1 then begin
    Printf.fprintf stderr "scan_this_arg : over" ;
    prerr_endline ""
  end ;
  restore_lexstate ();
  r

and scan_this_arg_list lexfun {arg=xs ; subst=this_subst } =
  start_lexstate () ;
  subst := this_subst ;
  if !verbose > 1 then begin
    Printf.fprintf stderr "scan_this_arg_list : [%a]\n%!"
      pretty_body xs
  end ;
  let lexbuf = MyLexing.from_list xs in
  let r = lexfun lexbuf in
  if !verbose > 1 then begin
    Printf.fprintf stderr "scan_this_arg : over\n%!"
  end ;
  restore_lexstate ();
  r

;;

let scan_this_may_cont lexfun lexbuf cur_subst
    {arg=s ; subst=env } =
  if !verbose > 1 then begin
    Printf.fprintf stderr "scan_this_may_cont : [%s]" s ;
    prerr_endline "" ;
    if !verbose > 1 then begin
      prerr_endline "Pushing lexbuf and env" ;
      pretty_lexbuf lexbuf ;
      pretty_subst !subst
    end
  end ;
  save_lexstate ();
  record_lexbuf lexbuf cur_subst ;
  subst := env ;
  let lexer = MyLexing.from_string s in
  let r = lexfun lexer in

  restore_lexstate ();
  if !verbose > 1 then begin
    Printf.fprintf stderr "scan_this_may_cont : over" ;
    prerr_endline ""
  end ;
  r

let scan_this_list_may_cont lexfun lexbuf cur_subst
    {arg=s ; subst=env } =
  if !verbose > 1 then begin
    eprintf "scan_this_list_may_cont : [%a]\n%!" pretty_body s ;
    if !verbose > 1 then begin
      prerr_endline "Pushing lexbuf and env" ;
      pretty_lexbuf lexbuf ;
      pretty_subst !subst
    end
  end ;
  save_lexstate ();
  record_lexbuf lexbuf cur_subst ;
  subst := env ;
  let lexer = MyLexing.from_list s in
  let r = lexfun lexer in

  restore_lexstate ();
  if !verbose > 1 then begin
    Printf.fprintf stderr "scan_this_list_may_cont : over" ;
    prerr_endline ""
  end ;
  r

let real_input_file loc_verb main filename input =
  if !verbose > 0 then
    prerr_endline ("Input file: "^filename) ;
  let buf = Lexing.from_channel input in
  Location.set filename buf ;
  let old_verb = !verbose in
  verbose := loc_verb ;
  if !verbose > 1 then prerr_endline ("scanning: "^filename) ;
  start_lexstate () ;
  let old_lexstate = MyStack.save stack_lexstate in
  subst := Top ;
  begin try  main buf with
  | Misc.EndInput ->
      MyStack.restore  stack_lexstate old_lexstate
  | e ->
      MyStack.restore  stack_lexstate old_lexstate ;
      restore_lexstate ();
      close_in input ;
      verbose := old_verb ;
(*   NO  Location.restore () ;  for proper error messages *)
      raise e
  end ;
  restore_lexstate ();
  if !verbose > 1 then prerr_endline ("scanning over: "^filename) ;    
  close_in input ;
  verbose := old_verb ;
  Location.restore ()  

let input_file loc_verb main filename =
  try
    let filename,input = Myfiles.open_tex filename in
    real_input_file loc_verb main filename input
  with Myfiles.Except -> begin
    if !verbose > 0 then
      prerr_endline ("Not opening file: "^filename) ;
    raise  Myfiles.Except
  end
 | Myfiles.Error m as x -> begin
     Misc.warning m ;
     raise x
 end


(* Hot start *)
type saved = (string * bool ref) list * bool list

let cell_list = ref []

let checkpoint () =
  !cell_list, List.map (fun (_,cell) -> !cell) !cell_list ;

and hot_start (cells, values)  =
  let rec start_rec cells values = match cells, values with
  | [],[] -> ()
  | (name,cell)::rcells, value :: rvalues ->
      if !verbose > 1 then begin
      prerr_endline
        ("Restoring "^name^" as "^if value then "true" else "false")
      end ;
      cell := value ;
      start_rec rcells rvalues
  | _,_ ->
      Misc.fatal ("Trouble in Lexstate.hot_start") in
  start_rec cells values ;
  cell_list := cells
  

let register_cell name cell =
  cell_list :=  (name,cell) :: !cell_list

and unregister_cell name =
  let rec un_rec = function
    | [] ->
        Misc.warning ("Cannot unregister cell: "^name) ;
        []
    | (xname,cell) :: rest ->
        if xname = name then rest
        else
          (xname,cell) :: un_rec rest in
  cell_list := un_rec !cell_list