~ubuntu-branches/ubuntu/hardy/texmacs/hardy

« back to all changes in this revision

Viewing changes to src/Data/Convert/Tex/parsetex.cpp

  • Committer: Bazaar Package Importer
  • Author(s): Ralf Treinen
  • Date: 2004-04-19 20:34:00 UTC
  • Revision ID: james.westby@ubuntu.com-20040419203400-g4e34ih0315wcn8v
Tags: upstream-1.0.3-R2
ImportĀ upstreamĀ versionĀ 1.0.3-R2

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
 
 
2
/******************************************************************************
 
3
* MODULE     : parsetex.cpp
 
4
* DESCRIPTION: conversion of tex/latex strings into logical tex/latex trees
 
5
* COPYRIGHT  : (C) 1999  Joris van der Hoeven
 
6
*******************************************************************************
 
7
* This software falls under the GNU general public license and comes WITHOUT
 
8
* ANY WARRANTY WHATSOEVER. See the file $TEXMACS_PATH/LICENSE for more details.
 
9
* If you don't have this file, write to the Free Software Foundation, Inc.,
 
10
* 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
 
11
******************************************************************************/
 
12
 
 
13
#include "Tex/convert_tex.hpp"
 
14
 
 
15
/******************************************************************************
 
16
* The latex_parser structure
 
17
*******************************************************************************
 
18
*
 
19
* During the parsing, the following global variables are used:
 
20
*
 
21
*     command_type   Contains the types of all currently defined tex commands.
 
22
*                    This is either 'command' 'modifier' 'operator'
 
23
*                    'environment' 'list' 'symbol' 'big-symbol' or 'user'.
 
24
*     command_arity  Contains the corresponding arity.
 
25
*     command_def    Contains the definitions of user commands.
 
26
*
 
27
* The command_type hashmap also contains come special fields
 
28
*
 
29
*     \<sub>         Stands for the subscript command
 
30
*     \<sup>         Stands for the supscript command
 
31
*
 
32
*     !mode          Gives the current mode ("text" or "math").
 
33
*     !verbatim      Verbatim mode ("true" or "false")
 
34
*     !em            Emphasized mode ("true" or "false")
 
35
*
 
36
*******************************************************************************
 
37
* WARNING: we recently put the standard LaTeX macros in latex_type and
 
38
* latex_arity instead of command_type and command_arity.
 
39
******************************************************************************/
 
40
 
 
41
struct latex_parser {
 
42
  latex_parser () {}
 
43
  void latex_error (string s, int i, string message);
 
44
 
 
45
  tree parse           (string s, int& i, char stop= '\0', bool change= false);
 
46
  tree parse_backslash (string s, int& i);
 
47
  tree parse_symbol    (string s, int& i);
 
48
  tree parse_command   (string s, int& i, string which);
 
49
  tree parse_unknown   (string s, int& i, string which);
 
50
  tree parse_verbatim  (string s, int& i, string end);
 
51
};
 
52
 
 
53
/******************************************************************************
 
54
* Error handling
 
55
******************************************************************************/
 
56
 
 
57
void
 
58
latex_parser::latex_error (string s, int i, string message) {
 
59
  cerr << "Latex error] " << message << "\n";
 
60
  if (i>30) s= "..." * s (i-27, N(s));
 
61
  if (N(s)>60) s= s (0, 57) * "...";
 
62
  cerr << "Latex error] in " << s << "\n";
 
63
}
 
64
 
 
65
/******************************************************************************
 
66
* Main parsing routine
 
67
******************************************************************************/
 
68
 
 
69
tree
 
70
latex_parser::parse (string s, int& i, char stop, bool change) {
 
71
  int n= N(s);
 
72
  tree t (CONCAT);
 
73
 
 
74
  command_type ->extend ();
 
75
  command_arity->extend ();
 
76
  command_def  ->extend ();
 
77
 
 
78
  while ((i<n) && ((s[i]==' ') || (s[i]=='\t') || (s[i]=='\n'))) i++;
 
79
  while ((i<n) && (s[i]!=stop)) {
 
80
    switch (s[i]) {
 
81
    case ' ':
 
82
    case '~':
 
83
    case '\t':
 
84
      while ((i<n) && ((s[i]==' ') || (s[i]=='~') || (s[i]=='\t'))) i++;
 
85
      if ((i<n) && (s[i]!='\n')) t << " ";
 
86
      break;
 
87
    case '\n': {
 
88
      int ln=0;
 
89
      while ((i<n) && ((s[i]==' ') || (s[i]=='\t') || (s[i]=='\n')))
 
90
        if (s[i++]=='\n') ln++;
 
91
      if (i<n) {
 
92
        if (ln == 1) t << " ";
 
93
        else t << "\n";
 
94
      }
 
95
      break;
 
96
    }
 
97
    case '%':
 
98
      if (test (s, i, "%%%%%%%%%% Start TeXmacs macros\n")) {
 
99
        while ((i<n) && (!test (s, i, "%%%%%%%%%% End TeXmacs macros\n")))
 
100
          i++;
 
101
        i += 30;
 
102
      }
 
103
      else {
 
104
        while ((i<n) && (s[i]!='\n')) i++;
 
105
        if (i<n) i++;
 
106
        int ln=0;
 
107
        while ((i<n) && ((s[i]==' ') || (s[i]=='\t') || (s[i]=='\n')))
 
108
          if (s[i++]=='\n') ln++;
 
109
        if (ln > 0) {
 
110
          if ((N(t)>0) && ((t[N(t)-1]==" ") || (t[N(t)-1]=="\n")))
 
111
            t[N(t)-1]= "\n";
 
112
          else t << "\n";
 
113
        }
 
114
      }
 
115
      break;
 
116
    case '#':
 
117
      i++;
 
118
      if (i==n) return t;
 
119
      if (is_numeric (s[i])) {
 
120
        t << s (i-1, i+1);
 
121
        i++;
 
122
      }
 
123
      else t << s (i-1, i);
 
124
      break;
 
125
    case '\\':
 
126
      if (((i+7)<n) && (s(i,i+5)=="\\over") && (!is_alpha (s (i+5, i+7)))) {
 
127
        i+=5;
 
128
        tree arg= parse_command (s, i, "\\over");
 
129
        while ((N(t)>=1) &&
 
130
               ((t[N(t)-1] == " ") || (t[N(t)-1] == tree (TUPLE, "\\ "))))
 
131
          t= t (0, N(t)-1);
 
132
        if (is_tuple (arg, "\\over", 1) && (N(t)>=1))
 
133
          t[N(t)-1]= tree (TUPLE, "\\frac", t[N(t)-1], arg[1]);
 
134
      }
 
135
      else if (((i+5)<n) && (s(i,i+3)=="\\sp") && (!is_alpha(s[i+3]))) {
 
136
        i+=3;
 
137
        t << parse_command (s, i, "\\<sup>");
 
138
      }
 
139
      else if (((i+5)<n) && (s(i,i+3)=="\\sb") && (!is_alpha(s[i+3]))) {
 
140
        i+=3;
 
141
        t << parse_command (s, i, "\\<sub>");
 
142
      }
 
143
      else if (((i+10)<n) && (s(i,i+8)=="\\pmatrix")) {
 
144
        i+=8;
 
145
        tree arg= parse_command (s, i, "\\pmatrix");
 
146
        if (is_tuple (arg, "\\pmatrix", 1)) arg= arg[1];
 
147
        t << tree (TUPLE, "\\begin-pmatrix");
 
148
        if (is_concat (arg)) t << A (arg);
 
149
        else t << arg;
 
150
        t << tree (TUPLE, "\\end-pmatrix");
 
151
      }
 
152
      else  {
 
153
        tree u= parse_backslash (s, i);
 
154
        if (u != "") t << u;
 
155
      }
 
156
      break;
 
157
    case '\'':
 
158
      i++;
 
159
      if (command_type ["!mode"] == "math") {
 
160
        int start= i-1;
 
161
        while ((i < N(s)) && (s[i] == '\'')) i++;
 
162
        t << tuple ("\\prime", s (start, i));
 
163
      }
 
164
      else t << s (i-1, i);
 
165
      break;
 
166
    case '*':
 
167
      if (command_type ["!mode"] == "math") t << tree (TUPLE, "\\ast");
 
168
      else t << "*";
 
169
      i++;
 
170
      break;
 
171
    case '_':
 
172
      i++;
 
173
      t << parse_command (s, i, "\\<sub>");
 
174
      /*
 
175
      if (command_type ["!mode"] == "math")
 
176
        t << parse_command (s, i, "\\<sub>");
 
177
      else t << s (i-1, i);
 
178
      */
 
179
      break;
 
180
    case '^':
 
181
      i++;
 
182
      t << parse_command (s, i, "\\<sup>");
 
183
      /*
 
184
      if (command_type ["!mode"] == "math")
 
185
        t << parse_command (s, i, "\\<sup>");
 
186
      else t << s (i-1, i);
 
187
      */
 
188
      break;
 
189
    case '<':
 
190
      t << tree (TUPLE, "\\<less>");
 
191
      i++;
 
192
      break;
 
193
    case '>':
 
194
      t << tree (TUPLE, "\\<gtr>");
 
195
      i++;
 
196
      break;
 
197
    case '\244':
 
198
      i++;
 
199
      t << parse_verbatim (s, i, "\244");
 
200
      break;
 
201
    case '{': {
 
202
      i++;
 
203
      t << parse (s, i, '}');
 
204
      if (i<n) i++;
 
205
 
 
206
      int ln=0;
 
207
      if ((i<n) && (s[i]!=' ') && (s[i]!='\t') && (s[i]!='\n')) break;
 
208
      while ((i<n) && ((s[i]==' ') || (s[i]=='\t') || (s[i]=='\n')))
 
209
        if (s[i++]=='\n') ln++;
 
210
      if (ln >= 2) t << "\n"; else t << tree (TUPLE, "\\ ");
 
211
      break;
 
212
    }
 
213
    case '$': {
 
214
      bool flag= false;
 
215
      i++;
 
216
      if ((i<n) & (s[i]=='$')) {
 
217
        i++;
 
218
        flag=true;
 
219
        t << tree (TUPLE, "\\begin-displaymath");
 
220
      }
 
221
      else t << tree (TUPLE, "\\begin-math");
 
222
      command_type ("!mode")= "math";
 
223
      t << parse (s, i, '$');
 
224
      command_type ("!mode")= "text";
 
225
      if ((i<n) && (s[i]=='$')) i++;
 
226
      if (flag) {
 
227
        if ((i<n) && (s[i]=='$')) i++;
 
228
        t << tree (TUPLE, "\\end-displaymath");
 
229
      }
 
230
      else t << tree (TUPLE, "\\end-math");
 
231
      break;
 
232
    }
 
233
    default:
 
234
      t << s (i, i+1);
 
235
      i++;
 
236
      break;
 
237
    }
 
238
  }
 
239
 
 
240
  if (change) {
 
241
    command_type ->merge ();
 
242
    command_arity->merge ();
 
243
    command_def  ->merge ();
 
244
  }
 
245
  else {
 
246
    command_type ->shorten ();
 
247
    command_arity->shorten ();
 
248
    command_def  ->shorten ();
 
249
  }
 
250
 
 
251
  if (N(t)==0) return "";
 
252
  if (N(t)==1) return t[0];
 
253
  return t;
 
254
}
 
255
 
 
256
/******************************************************************************
 
257
* Parsing commands
 
258
******************************************************************************/
 
259
 
 
260
tree
 
261
latex_parser::parse_backslash (string s, int& i) {
 
262
  int n= N(s);
 
263
  if (((i+7)<n) && (s(i,i+5)=="\\verb")) {
 
264
    i+=6;
 
265
    return parse_verbatim (s, i, s(i-1,i));
 
266
  }
 
267
  if (((i+29)<n) && (s(i,i+16)=="\\begin{verbatim}")) {
 
268
    i+=16;
 
269
    return parse_verbatim (s, i, "\\end{verbatim}");
 
270
  }
 
271
 
 
272
  /************************ special commands *********************************/
 
273
  i++;
 
274
  if (i==n) return "";
 
275
  if (s[i]==' ') {
 
276
    i++;
 
277
    return tree (TUPLE, "\\ ");
 
278
  }
 
279
  if (!is_alpha(s[i])) {
 
280
    i++;
 
281
    if (s[i-1]=='(') return parse_command (s, i, "\\begin-math");
 
282
    if (s[i-1]==')') return parse_command (s, i, "\\end-math");
 
283
    if (s[i-1]=='[') return parse_command (s, i, "\\begin-displaymath");
 
284
    if (s[i-1]==']') return parse_command (s, i, "\\end-displaymath");
 
285
    return parse_command (s, i, s (i-2, i));
 
286
  }
 
287
 
 
288
  /************************* normal commands *********************************/
 
289
  int start= i-1;
 
290
  while ((i<n) && is_alpha (s[i])) i++;
 
291
  if ((i<n) && (s[i]=='*')) i++;
 
292
  string r= s (start, i);
 
293
  if ((r == "\\begin") || (r == "\\end")) {
 
294
    while ((i<n) && ((s[i]==' ') || (s[i]=='\t') || (s[i]=='\n'))) i++;
 
295
    if ((i==n) || (s[i]!='{')) {
 
296
      latex_error (s, i, "begin or end which environment ?");
 
297
      return "";
 
298
    }
 
299
    i++; start= i;
 
300
    while ((i<n) && (s[i]!='}')) i++;
 
301
    r = r * "-" * s (start, i);
 
302
    if (i<n) i++;
 
303
  }
 
304
  return parse_command (s, i, r);
 
305
}
 
306
 
 
307
static string
 
308
sharp_to_arg (string s, tree args) {
 
309
  int i;
 
310
  string r;
 
311
  for (i=0; i<N(s); i++)
 
312
    if ((s[i]=='#') && ((i+1)<N(s)) && (s[i+1]>='1') && (s[i+1]<='9')) {
 
313
      int nr= ((int) s[++i]) - ((int) '0');
 
314
      if (N(args)>nr) r << as_string (args[nr]);
 
315
    }
 
316
    else r << s[i];
 
317
  return r;
 
318
}
 
319
 
 
320
tree
 
321
latex_parser::parse_symbol (string s, int& i) {
 
322
  int start= i;
 
323
  if ((s[i] == '*') && (command_type ["!mode"] == "math")) {
 
324
    i++; return tree (TUPLE, "\\ast"); }
 
325
  if (s[i] == '<') { i++; return tree (TUPLE, "\\<less>"); }
 
326
  if (s[i] == '>') { i++; return tree (TUPLE, "\\<gtr>"); }
 
327
  if (s[i] != '\\') { i++; return s(start, i); }
 
328
  i++;
 
329
  if (i == N(s)) return tree (TUPLE, "\\backslash");
 
330
  if (!is_alpha (s[i])) { i++; return s(start, i); }
 
331
  while ((i<N(s)) && is_alpha (s[i])) i++;
 
332
  if ((i<N(s)) && (s[i]=='*')) i++;
 
333
  return s(start,i);
 
334
}
 
335
 
 
336
tree
 
337
latex_parser::parse_command (string s, int& i, string cmd) {
 
338
  /*
 
339
  cout << cmd << " [" << command_type [cmd] << ", "
 
340
       << command_type ["!mode"] << "]" << LF;
 
341
  */
 
342
  if (cmd == "\\newcommand") cmd= "\\def";
 
343
  if (cmd == "\\renewcommand") cmd= "\\def";
 
344
  if (cmd == "\\renewenvironment") cmd= "\\newenvironment";
 
345
  if (cmd == "\\begin-split") cmd= "\\begin-eqsplit";
 
346
  if (cmd == "\\end-split") cmd= "\\end-eqsplit";
 
347
  if (cmd == "\\begin-split*") cmd= "\\begin-eqsplit*";
 
348
  if (cmd == "\\end-split*") cmd= "\\end-eqsplit*";
 
349
  if ((!command_type->contains (cmd)) &&
 
350
      (latex_type [cmd] == "undefined"))
 
351
    return parse_unknown (s, i, cmd);
 
352
 
 
353
  if (latex_type [cmd] == "math-environment") {
 
354
    if (cmd (0, 6) == "\\begin") command_type ("!mode") = "math";
 
355
    else command_type ("!mode") = "text";
 
356
  }
 
357
 
 
358
  bool mbox_flag=
 
359
    ((cmd == "\\text") || (cmd == "\\mbox")) &&
 
360
    (command_type ["!mode"] == "math");
 
361
  if (mbox_flag) command_type ("!mode") = "text";
 
362
 
 
363
  int  n     = N(s);
 
364
  int  arity =
 
365
    (latex_type [cmd]=="undefined")? command_arity (cmd): latex_arity [cmd];
 
366
  bool option= (arity<0);
 
367
  if (option) arity= -1-arity;
 
368
 
 
369
  /************************ retrieve arguments *******************************/
 
370
  tree t (TUPLE, copy (cmd)); // parsed arguments
 
371
  tree u (TUPLE, copy (cmd)); // unparsed arguments
 
372
  while ((i<n) && ((arity>0) || option)) {
 
373
    int j=i;
 
374
    while ((j<n) && ((s[j]==' ') || (s[j]=='\t') || (s[j]=='\n'))) j++;
 
375
    if (j==n) break;
 
376
    if (option && (s[j]=='[')) {
 
377
      j++;
 
378
      i=j;
 
379
      t << parse (s, i, ']');
 
380
      u << s (j, i);
 
381
      if (i<n) i++;
 
382
      t[0]->label= t[0]->label * "*";
 
383
      option= false;
 
384
    }
 
385
    else if ((arity>0) && (s[j]=='{')) {
 
386
      j++;
 
387
      i=j;
 
388
      if ((N(t)==1) && (cmd == "\\def")) {
 
389
        while ((i<n) && (s[i]!='}')) i++;
 
390
        t << s (j, i);
 
391
      }
 
392
      else t << parse (s, i, '}');
 
393
      u << s (j, i);
 
394
      if (i<n) i++;
 
395
      arity--;
 
396
    }
 
397
    else if (option && (s[j]=='#') && (cmd == "\\def")) {
 
398
      while ((j+3 <= n) && is_numeric (s[j+1]) && (s[j+2] == '#')) j+=2;
 
399
      if (j+2<=n) {
 
400
        t << s (j+1, j+2);
 
401
        u << s (j+1, j+2);
 
402
        i= j+2;
 
403
      }
 
404
      t[0]->label= t[0]->label * "*";
 
405
      option= false;
 
406
    }
 
407
    else {
 
408
      if (arity>0) {
 
409
        i=j;
 
410
        tree st= parse_symbol (s, i);
 
411
        t << st;
 
412
        u << st;
 
413
        arity--;
 
414
      }
 
415
      else break;
 
416
    }
 
417
  }
 
418
  if (arity>0) latex_error (s, i, "too little arguments for " * cmd);
 
419
 
 
420
  /******************** new commands and environments ************************/
 
421
  if (is_tuple (t, "\\def", 2)) {
 
422
    string var= as_string (t[1]);
 
423
    command_type  (var)= "user";
 
424
    command_arity (var)= 0;
 
425
    command_def   (var)= as_string (u[2]);
 
426
  }
 
427
  if (is_tuple (t, "\\def*", 3)) {
 
428
    string var= as_string (t[1]);
 
429
    command_type  (var)= "user";
 
430
    command_arity (var)= as_int (t[2]);
 
431
    command_def   (var)= as_string (u[3]);
 
432
  }
 
433
  if (is_tuple (t, "\\newenvironment", 3)) {
 
434
    string var= "\\begin-" * as_string (t[1]);
 
435
    command_type  (var)= "user";
 
436
    command_arity (var)= 0;
 
437
    command_def   (var)= as_string (u[2]);
 
438
    var= "\\end-" * as_string (t[1]);
 
439
    command_type  (var)= "user";
 
440
    command_arity (var)= 0;
 
441
    command_def   (var)= as_string (u[3]);
 
442
  }
 
443
  if (is_tuple (t, "\\newenvironment*", 4)) {
 
444
    string var= "\\begin-" * as_string (t[1]);
 
445
    command_type  (var)= "user";
 
446
    command_arity (var)= as_int (t[2]);
 
447
    command_def   (var)= as_string (u[3]);
 
448
    var= "\\end-" * as_string (t[1]);
 
449
    command_type  (var)= "user";
 
450
    command_arity (var)= 0;
 
451
    command_def   (var)= as_string (u[4]);
 
452
  }
 
453
 
 
454
  /***************** environment changes for user commands  ******************/
 
455
  if (command_type[cmd] == "user") {
 
456
    int pos= 0;
 
457
    (void) parse (sharp_to_arg (command_def[cmd], u), pos, '\0', true);
 
458
    // t= parse (sharp_to_arg (command_def[cmd], u), pos, '\0', true);
 
459
    // variant if you want to replace macros by their definitions
 
460
  }
 
461
 
 
462
  if (mbox_flag) command_type ("!mode") = "math";
 
463
  return t;
 
464
}
 
465
 
 
466
tree
 
467
latex_parser::parse_unknown (string s, int& i, string cmd) {
 
468
  int  n     = N(s);
 
469
  bool option= false;
 
470
 
 
471
  tree t (TUPLE, copy (cmd));
 
472
  while (i<n) {
 
473
    int j=i;
 
474
    while ((j<n) && ((s[j]==' ') || (s[j]=='\t') || (s[j]=='\n'))) j++;
 
475
    if (j==n) break;
 
476
    if (option && (s[j]=='[')) {
 
477
      j++;
 
478
      i=j;
 
479
      t << parse (s, i, ']');
 
480
      if (i<n) i++;
 
481
      t[0]->label= t[0]->label * "*";
 
482
      option= false;
 
483
    }
 
484
    else if (s[j]=='{') {
 
485
      j++;
 
486
      i=j;
 
487
      t << parse (s, i, '}');
 
488
      if (i<n) i++;
 
489
    }
 
490
    else break;
 
491
  }
 
492
  return t;
 
493
}
 
494
 
 
495
/******************************************************************************
 
496
* Parsing verbatim text
 
497
******************************************************************************/
 
498
 
 
499
tree
 
500
latex_parser::parse_verbatim (string s, int& i, string end) {
 
501
  int start=i, n= N(s), e= N(end);
 
502
  while ((i<(n-e)) && (s(i,i+e)!=end)) i++;
 
503
  i+=e;
 
504
  return tree (CONCAT,
 
505
               tree (TUPLE, "\\begin-verbatim"),
 
506
               s(start,i-e),
 
507
               tree (TUPLE, "\\end-verbatim"));
 
508
}
 
509
 
 
510
/******************************************************************************
 
511
* This routine may be used to transform accented characters to the Cork format
 
512
******************************************************************************/
 
513
 
 
514
static char Cork_unaccented[128]= {
 
515
  'A', ' ', 'C', 'C', 'D', 'E', ' ', 'G',
 
516
  'L', 'L', ' ', 'N', 'N', ' ', 'O', 'R',
 
517
  'R', 'S', 'S', 'S', 'T', 'T', 'U', 'U',
 
518
  'Y', 'Z', 'Z', 'Z', ' ', 'I', 'd', ' ',
 
519
  'a', ' ', 'c', 'c', 'd', 'e', ' ', 'g',
 
520
  'l', 'l', ' ', 'n', 'n', ' ', 'o', 'r',
 
521
  'r', 's', 's', 's', 't', 't', 'u', 'u',
 
522
  'y', 'z', 'z', 'z', ' ', ' ', ' ', ' ',
 
523
  'A', 'A', 'A', 'A', 'A', 'A', ' ', 'C',
 
524
  'E', 'E', 'E', 'E', 'I', 'I', 'I', 'I',
 
525
  'D', 'N', 'O', 'O', 'O', 'O', 'O', ' ',
 
526
  ' ', 'U', 'U', 'U', 'U', 'Y', ' ', ' ',
 
527
  'a', 'a', 'a', 'a', 'a', 'a', ' ', 'c',
 
528
  'e', 'e', 'e', 'e', 16 , 16 , 16 , 16 ,
 
529
  'd', 'n', 'o', 'o', 'o', 'o', 'o', ' ',
 
530
  ' ', 'u', 'u', 'u', 'u', 'y', ' ', ' '
 
531
};
 
532
 
 
533
static char Cork_accent[128]= {
 
534
  'u' , ' ' , '\'', 'v' , 'v' , 'v' , ' ' , 'u' ,
 
535
  '\'', ' ' , ' ' , '\'', 'v' , ' ' , 'H' , '\'',
 
536
  'v' , '\'', 'v' , 'c' , 'v' , 'c' , 'H' , ' ' ,
 
537
  '\"', '\'', 'v' , '.' , ' ' , '.' , '=' , ' ' , // "
 
538
  'u' , ' ' , '\'', 'v' , 'v' , 'v' , ' ' , 'u' ,
 
539
  '\'', ' ' , ' ' , '\'', 'v' , ' ' , 'H' , '\'',
 
540
  'v' , '\'', 'v' , 'c' , 'v' , 'c' , 'H' , ' ' ,
 
541
  '\"', '\'', 'v' , '.' , ' ' , ' ' , ' ' , ' ' , // "
 
542
  '`' , '\'', '^' , '~' , '\"', ' ' , ' ' , 'c' , // "
 
543
  '`' , '\'', '^' , '\"', '`' , '\'', '^' , '\"', // "
 
544
  '=' , '~' , '`' , '\'', '^' , '~' , '\"', ' ' , // "
 
545
  ' ' , '`' , '\'', '^' , '\"', '\'', ' ' , ' ' , // "
 
546
  '`' , '\'', '^' , '~' , '\"', ' ' , ' ' , 'c' , // "
 
547
  '`' , '\'', '^' , '\"', '`' , '\'', '^' , '\"', // "
 
548
  '=' , '~' , '`' , '\'', '^' , '~' , '\"', ' ' , // "
 
549
  ' ' , '`' , '\'', '^' , '\"', '\'', ' ' , ' '   // "
 
550
};
 
551
 
 
552
tree
 
553
accented_to_Cork (tree t) {
 
554
  if (arity (t) == 0) return t;
 
555
  int i, n=N(t);
 
556
  tree r (t, n);
 
557
  for (i=0; i<n; i++) r[i]= accented_to_Cork (t[i]);
 
558
  if (is_compound (t[0])) return r;
 
559
 
 
560
  string s= t[0]->label;
 
561
  if ((N(s)==2) && (s[0]=='\\') && (n==2) &&
 
562
      is_atomic (t[1]) && (N(t[1]->label)<=2)) {
 
563
    string v= t[1]->label;
 
564
    if (N(v)==0) {
 
565
      if (s[1] == '`' ) {
 
566
        string ret_s (1);
 
567
        ret_s[0]= '\000';
 
568
        return ret_s;
 
569
      }
 
570
      if (s[1] == '\'') return "\001";
 
571
      if (s[1] == '^' ) return "\136";
 
572
      if (s[1] == '\"') return "\004"; // "
 
573
      if (s[1] == '~' ) return "\176";
 
574
      if (s[1] == '=' ) return "\026";
 
575
      if (s[1] == '.' ) return "\137";
 
576
      if (s[1] == 'u' ) return "\025";
 
577
      if (s[1] == 'v' ) return "\024";
 
578
      if (s[1] == 'H' ) return "\175";
 
579
      if (s[1] == 'c' ) return "\030";
 
580
    }
 
581
    else {
 
582
      char c1= v[0], c2= s[1];
 
583
      if (v=="\\i") c1= (char) 16;
 
584
      if ((N(v)==1) || (v=="\\i"))
 
585
        for (i=0; i<127; i++)
 
586
          if ((Cork_unaccented[i]==c1) && (Cork_accent[i]==c2))
 
587
            return tree (string ((char) (i+128)));
 
588
    }
 
589
  }
 
590
  return r;
 
591
}
 
592
 
 
593
/******************************************************************************
 
594
* Interface
 
595
******************************************************************************/
 
596
 
 
597
tree
 
598
parse_latex (string s) {
 
599
  tree t;
 
600
  s= dos_to_better (s);
 
601
  int i=0;
 
602
  latex_parser ltx;
 
603
  command_type ("!mode") = "text";
 
604
  command_type ("!em") = "false";
 
605
  t= accented_to_Cork (ltx.parse (s, i));
 
606
  command_type ("!mode") = "text";
 
607
  command_type ("!em") = "false";
 
608
  return t;
 
609
}
 
610
 
 
611
tree
 
612
parse_latex_document (string s) {
 
613
  return compound ("!file", parse_latex (s));
 
614
}