Chapter 14
Math Classes for Symbols

   14.1 Scanning Requests
   14.2 Setting Requests
   14.3 Memory and Initialization
   14.4 Delimiters Over Next Group
      Requests
      Insertions
      Memory and Initialization
   14.5 Delimiters Over Next Character

Tex assignes class numbers 0–7 to the atoms of math formulas: 0–ordinary symbol, 1–large operator, 2–binary operation, 3–relational operation, 4–math delimiter, 5–right delimiter, 6–punctuation mark, and 7–adjustable. We use classes 7, 8, 9 as extra free ones.

14.1 Scanning Requests

{\everypar{}\special{t4ht^i}$sym... i=0, 1, 2, 3, 4,..., a, b, ...., ~ $\special{t4ht^}}

A right delimiter immediately after a math openimiter ammuses a matching pair.

<..classes for math symbols..>
 switch( special_n ){
   case 0:{ if( math_class_on ){
               open_del = 256;   pause_class = ignore_subclass_del = 0;
               math_class_on = FALSE;  <.recall intrusive flags.>
            } else { show_class = !show_class; }
            break;
          }
   case 1:{ <.save intrusive flags.>
            special_n--;
            if( (math_class = scan_class(1)) == <.num of math classes: 79.> )
              { math_class = 0; }
            else math_class_on = TRUE;
            break;
          }
   case 2:{  <.class delimiters on group.>
             break; }
  default:{ <.set config class dels.> }
 }
 -_-_-

<..vars..>+
 static BOOL math_class_on = FALSE, show_class = FALSE;
 static int open_del = 256, math_class, pause_class, ignore_subclass_del;
 -_-_-

open_del’ is used by close delimiter, if they are immediate neighbors.

<..vars..>+
 static int sv_group_dvi, sv_trace_dvi_C, sv_in_trace_char, sv_span_on,
     sv_in_span_ch;
 -_-_-

<..save intrusive flags..>
 sv_group_dvi     = group_dvi;
 sv_trace_dvi_C   = trace_dvi_C;
 sv_in_trace_char = in_trace_char;
 sv_span_on       = span_on;
 sv_in_span_ch    = in_span_ch;
 -_-_-

<..recall intrusive flags..>
 group_dvi     = sv_group_dvi;
 trace_dvi_C   = sv_trace_dvi_C;
 in_trace_char = sv_in_trace_char;
 span_on       = sv_span_on;
 in_span_ch    = sv_in_span_ch;
 -_-_-

<..header functions..>+
 static int scan_class( ARG_I(int) );
 -_-_-

<..functions..>+
 
 static int scan_class( flag )
         int flag
 ;{                                    int math_class;
    math_class = get_char();
    if(   (math_class >= ’0’ )
       && (math_class < ’0’ + <.num of math classes: 79.>) ){
       { math_class -= ’0’;    }
    } else {
         if( flag== 1 ) {
            switch( math_class ){
              case ’-’: { math_class = <.num of math classes: 79.>;
                          pause_class++;  break; }
              case ’+’: { math_class = <.num of math classes: 79.>;
                          pause_class--;  break; }
               default: { math_class = 0; }
         } } else if( flag== 2 ) {
            switch( math_class ){
              case <.ignore sub dels ch.>: {
                 math_class = <.ignore sub dels val.>;  break; }
              case <.end ignore sub dels ch.>:
                 { math_class = <.end ignore sub dels val.>;   break; }
               default: { math_class = 0; }
            }
         } else { math_class = 0; }
    }
    return math_class;
 }
 -_-_-

14.2 Setting Requests

<..header functions..>+
 static INTEGER set_ch_class( ARG_I(int) );
 -_-_-

<..functions..>+
 
 static  INTEGER set_ch_class(ch)    int ch
 ;{                              int r_ch;
    r_ch = ch - font_tbl[cur_fnt].char_f;
    if( math_class == <.math close.> ){
       store_bit_I( font_tbl[cur_fnt].math_closing, r_ch );
       *(font_tbl[cur_fnt].math + r_ch) =
               (char) ((open_del == 256)?  ch : open_del);
    } else {
       store_bit_Z( font_tbl[cur_fnt].math_closing, r_ch );
       *(font_tbl[cur_fnt].math + r_ch) = math_class;
    }
    open_del = ( math_class == <.math open.> )? ch : 256;
    <.return char width.>
 }
 -_-_-

<..set-ch-class(ch-1)..>
 set_ch_class(ch_1)
 -_-_-

<..set config class dels..>
 {                                    U_CHAR str[256], *p, ch, **q;
    math_class = scan_class(2);  ch = get_char();
    special_n -= 2;   p = str;
    while( special_n-- > 0 ){
       if(  (*(p++) = get_char()) == ch ){ p--; break; }
    }
    *p = ’\0’;
    q = (math_class > <.math classes 0..78.>)? &(<.push class del := ....>)
                        : &(open_class[math_class]);
    *q = (char *)  r_alloc((void *) open_class[math_class],
                                  1 + (size_t) strlen((char *) str));
    (IGNORED) strcpy((char *) *q, (char *) str);
    q = (math_class > <.math classes 0..78.>) ? &(<.pop class del := ....>)
                          :  &(close_class[math_class]);
    p = *q = (char *)  r_alloc((void *) *q,  1 + (size_t) special_n);
    while( special_n-- > 0 ){ *(p++) = get_char();  }
    *p = ’\0’;
    if( math_class > <.math classes 0..78.>){ <.next delimiters on group.> }
 }
 -_-_-

When ‘math_class > max math class’ is true, the delimiters are placed on the next group. In such a case a math class of ‘)’ also requests that no subdelimiter will be placed there.

<..header functions..>+
 static int math_class_of( ARG_II(int,int) );
 -_-_-

<..functions..>+
 
 static  int math_class_of(ch,cur_fnt)    int ch; int cur_fnt
 ;{                           int math_class;
    math_class = ch - font_tbl[cur_fnt].char_f;
    return ((get_bit( font_tbl[cur_fnt].math_closing, math_class))?
                 <.math close.> : *( math_class + font_tbl[cur_fnt].math));
 
 }
 -_-_-

14.3 Memory and Initialization

<..vars..>+
 static U_CHAR *open_class[<.mems for math classes (79 + 2 ).>],
      *close_class[<.mems for math classes (79 + 2 ).>];
 -_-_-

There are 79 characters in the range between the digit ‘0’ and the character ‘~’.

<..math classes 0..78..>
 78
 -_-_-

<..num of math classes: 79..>
 79
 -_-_-

The following should be characters below the digit ‘0’

<..ignore sub dels ch..>
 ’)’
 -_-_-

<..end ignore sub dels ch..>
 ’(’
 -_-_-

<..ignore sub dels val..>
 (<.num of math classes: 79.> + 1)
 -_-_-

<..end ignore sub dels val..>
 (<.num of math classes: 79.> + 2)
 -_-_-

<..mems for math classes (79 + 2 )..>
 82   one extra is needed?
 -_-_-

<..main’s init..>+
 for( math_class=0; math_class<<.num of math classes: 79.>; math_class++ ){
   open_class[math_class] = m_alloc(char, 1);
   close_class[math_class] = m_alloc(char, 1);
   *(open_class[math_class]) = *(close_class[math_class]) = ’\0’;
 }
 -_-_-

<..entries for math classes..>
 char *math, *math_closing;
 -_-_-

<..memory for math classes..>
 new_font.math_closing = m_alloc(char, n_gif_bytes );
 new_font.math = m_alloc(char, n_gif );
 -_-_-

<..init math-closing..>
 new_font.math_closing[i] =
 -_-_-

<..init math..>
 new_font.math[i] =
 -_-_-

<..merge math entries..>
 free((void *)  new_font.math_closing );
            new_font.math_closing = font_tbl[ k ].math_closing;
 free((void *)  new_font.math );
                            new_font.math = font_tbl[ k ].math;
 -_-_-

14.4 Delimiters Over Next Group

Requests

\special{t4ht^ix}’–put delimiters of class i on next group/token. If x=‘)’ ignore delimiters within the group.

<..class delimiters on group..>
 special_n -= 2;   math_class = scan_class(0);
 stack[stack_n+1].ignore_subclass_del =
    (<.ignore sub dels ch.> == get_char());
 stack[stack_n+1].active_class_del = TRUE;
 stack[stack_n+1].temp_class_del = FALSE;
 stack[stack_n+1].no_left_del = TRUE;
 stack[stack_n+1].class_open = open_class[math_class];
 stack[stack_n+1].class_close = close_class[math_class];
 -_-_-

\special{t4ht^)x*...*...}’–put the specified delimiters of class on next group, instead of the default ones. If x=‘)’, ignore delimiters within the group.

<..next delimiters on group..>
 stack[stack_n+1].ignore_subclass_del =
   (math_class == <.ignore sub dels val.>);
 stack[stack_n+1].temp_class_del = TRUE;
 stack[stack_n+1].active_class_del = TRUE;
 -_-_-

<..pop class del := .....>
 stack[stack_n+1].temp_class_close
 -_-_-

<..push class del := .....>
 stack[stack_n+1].temp_class_open
 -_-_-

Insertions

<..add push class del..>
 if( stack[stack_n].active_class_del ){
    if( show_class && !pause_class && !ignore_subclass_del ){
       <.print open del of group class.>
    }
    ignore_subclass_del =  ignore_subclass_del
                         + stack[stack_n].ignore_subclass_del;
    stack[stack_n+1].no_left_del= FALSE;
 }
 -_-_-

<..add pop class del..>
 if( stack[stack_n].active_class_del ){
    ignore_subclass_del =  ignore_subclass_del
                         - stack[stack_n].ignore_subclass_del;
    if( show_class && !pause_class && !ignore_subclass_del ){
       <.print right del of group class.>
    }
    stack[stack_n].active_class_del = FALSE;
 }
 -_-_-

Memory and Initialization

<..struct stack_entry..>+
 char *class_open, *class_close,
      *temp_class_open, *temp_class_close;
 BOOL temp_class_del, ignore_subclass_del, active_class_del,
     no_left_del, sv_no_left_del;
 -_-_-

The math class can be on a group or a token. Upon reaching the \special, the no_left_del is set to false. Upon reaching to the start of the next group (not token), the flag is set to true.

<..initialized entries for grouping stack..>+
 stack[i].class_open = stack[i].class_close
                     = (char *) 0;
 stack[i].temp_class_open  = m_alloc(char, 1 );
 stack[i].temp_class_close = m_alloc(char, 1 );
 stack[i].ignore_subclass_del = stack[i].temp_class_del
                           = stack[i].active_class_del
                           = FALSE;
 -_-_-

14.5 Delimiters Over Next Character

<..left class delNO..>
 if( show_class  && !pause_class && !ignore_subclass_del){
    if(stack[stack_n+1].no_left_del && stack[stack_n+1].active_class_del ){
        <.open del of group class on ch.>
    } else {
       math_class = math_class_of( ch, cur_fnt );
       (IGNORED) print_f( open_class[math_class]);
 }  }
 -_-_-

<..left class del..>
 if( show_class  && !pause_class && !ignore_subclass_del){
    if( !stack[stack_n].no_left_del && stack[stack_n+1].active_class_del ){
       <.open del of group class on ch.>
       if( !stack[stack_n+1].ignore_subclass_del ){
          <.left del of class on ch.>
       }
    } else {
       <.left del of class on ch.>
 }  }
 -_-_-

<..left del of class on ch..>
 math_class = math_class_of( ch, cur_fnt );
 (IGNORED) print_f( open_class[math_class]);
 -_-_-

The ‘stack[stack_n].no_left_del’ is true if we have a request for math delimiters on next group/token, and no left delimiter had been placed on a group.

<..right class delNO..>
 if( show_class && !pause_class && !ignore_subclass_del ){
    if(stack[stack_n+1].no_left_del && stack[stack_n+1].active_class_del ){
       <.right del of group class on ch.>
       stack[stack_n+1].active_class_del = FALSE;
    } else {
       (IGNORED) print_f( close_class[math_class]);
    }
 }
 -_-_-

<..right class del..>
 if( show_class && !pause_class && !ignore_subclass_del ){
    if( !stack[stack_n].no_left_del && stack[stack_n+1].active_class_del ){
       if( !stack[stack_n+1].ignore_subclass_del ){
          <.right del of class on ch.>
       }
       <.right del of group class on ch.>
       stack[stack_n+1].active_class_del = FALSE;
    } else {
       <.right del of class on ch.>
       stack[stack_n+1].active_class_del = FALSE;  %%%%%%%NEW%%%%
    }
 }
 -_-_-

<..right del of class on ch..>
 (IGNORED) print_f( close_class[math_class]);
 -_-_-

<..print right del of group class..>
 (IGNORED) print_f( (stack[stack_n].temp_class_del)?
                       stack[stack_n].temp_class_close
                    :  stack[stack_n].class_close);
 -_-_-

<..right del of group class on ch..>
 (IGNORED) print_f( (stack[stack_n+1].temp_class_del)?
                       stack[stack_n+1].temp_class_close
                    :  stack[stack_n+1].class_close);
 -_-_-

<..print open del of group class..>
 (IGNORED) print_f( (stack[stack_n].temp_class_del)?
                       stack[stack_n].temp_class_open
                    :  stack[stack_n].class_open);
 -_-_-

<..open del of group class on ch..>
 (IGNORED) print_f( (stack[stack_n+1].temp_class_del)?
                       stack[stack_n+1].temp_class_open
                    :  stack[stack_n+1].class_open);
 -_-_-