changeset 17269:5b088598df1d

Add simple TeX parser based on flex/bison. * libinterp/corefcn/oct-tex-lexer.ll, libinterp/corefcn/oct-tex-pareser.yy: New files. * libinterp/Makefile.am (BUILT_SOURCES): Add oct-tex-lexer.cc and oct-tex-parser.cc. * libinterp/corefcn/modules.mk (corefcn/oct-tex-lexer.cc, corefcn/oct-tex-parser.h): New rules. * libinterp/corefcn/txt-eng-ft.h (ft_render::text_to_pixels, ft_render::get_extent): Add interpreter argument. * libinterp/corefcn/txt-eng-ft.cc (ft_render::text_to_pixels, ft_render::get_extent): Likewise. Use text_parser::parse(). * libinterp/corefcn/gl-render.cc (opengl_renderer::text_to_pixels): Use new interpreter argument. * libinterp/corefcn/graphics.cc (axes::properties::get_ticklabel_extents): Likewise. (uicontrol::properties::update_text_extent): Use text_parser::parse. * libinterp/corefcn/txt-eng.h (memory, string, caseless-str.h, dMatrix.h): New includes. (class text_element_subscript): Renamed from text_subscript_element. (class text_element_supserscript): Renamed from text_superscript_element. (class text_element_symbol, class text_element_fontstyle, class text_element_fontname, class text_element_fontsize, class text_element_color): New classes. (text_element_list::text_element_list(text_element*)): New constructor. (text_element_subscript::text_element_subscript(text_element*), text_element_subscript::text_element::subscript(char)): New constructors. (text_element_subscript::elem): New member. (text_element_subscript::get_element): New method. Returns it. (text_element_subscript::~text_element_subscript): New destructor. Delete it. (text_element_subscript::text_element_subscript()): Make default constructor private. (text_element_superscript::text_element_superscript(text_element*), text_element_superscript::text_element::superscript(char)): New constructors. (text_element_superscript::elem): New member. (text_element_superscript::get_element): New method. Returns it. (text_element_superscript::~text_element_superscript): New destructor. Delete it. (text_element_superscript::text_element_superscript()): Make default constructor private. (text_processor::visit(text_element_symbol), text_processor::visit(text_element_fontstyle), text_processor::visit(text_element_fontname), text_processor::visit(text_element_fontsize), text_processor::visit(text_element_color)): New methods. (text_parser::parse): New static method. (class text_parser_tex): New class.
author Michael Goffioul <michael.goffioul@gmail.com>
date Sun, 18 Aug 2013 16:36:38 -0400
parents 1c21f264d26f
children ba865ea9c7e9
files libinterp/Makefile.am libinterp/corefcn/gl-render.cc libinterp/corefcn/graphics.cc libinterp/corefcn/module.mk libinterp/corefcn/oct-tex-lexer.ll libinterp/corefcn/oct-tex-parser.yy libinterp/corefcn/txt-eng-ft.cc libinterp/corefcn/txt-eng-ft.h libinterp/corefcn/txt-eng.h
diffstat 9 files changed, 615 insertions(+), 27 deletions(-) [+]
line wrap: on
line diff
--- a/libinterp/Makefile.am	Sat Aug 17 11:45:20 2013 -0700
+++ b/libinterp/Makefile.am	Sun Aug 18 16:36:38 2013 -0400
@@ -51,6 +51,8 @@
   corefcn/defaults.h \
   corefcn/graphics-props.cc \
   corefcn/graphics.h \
+  corefcn/oct-tex-lexer.cc \
+  corefcn/oct-tex-parser.cc \
   operators/ops.cc \
   parse-tree/lex.cc \
   parse-tree/oct-gperf.h \
--- a/libinterp/corefcn/gl-render.cc	Sat Aug 17 11:45:20 2013 -0700
+++ b/libinterp/corefcn/gl-render.cc	Sun Aug 18 16:36:38 2013 -0400
@@ -3009,7 +3009,7 @@
 {
 #if HAVE_FREETYPE
   text_renderer.text_to_pixels (txt, pixels, bbox,
-                                halign, valign, rotation);
+                                halign, valign, rotation, "none");
 #endif
 }
 
--- a/libinterp/corefcn/graphics.cc	Sat Aug 17 11:45:20 2013 -0700
+++ b/libinterp/corefcn/graphics.cc	Sun Aug 18 16:36:38 2013 -0400
@@ -6292,7 +6292,7 @@
           label.erase (0, label.find_first_not_of (" "));
           label = label.substr (0, label.find_last_not_of (" ")+1);
 #ifdef HAVE_FREETYPE
-          ext = text_renderer.get_extent (label);
+          ext = text_renderer.get_extent (label, 0.0, "none");
           wmax = std::max (wmax, ext(0));
           hmax = std::max (hmax, ext(1));
 #else
@@ -7573,7 +7573,7 @@
   // FIXME: parsed content should be cached for efficiency
   // FIXME: support multiline text
 
-  elt = text_parser_none ().parse (get_string_string ());
+  elt = text_parser::parse (get_string_string (), "none");
 #ifdef HAVE_FONTCONFIG
   text_renderer.set_font (get_fontname (),
                           get_fontweight (),
--- a/libinterp/corefcn/module.mk	Sat Aug 17 11:45:20 2013 -0700
+++ b/libinterp/corefcn/module.mk	Sun Aug 18 16:36:38 2013 -0400
@@ -209,6 +209,8 @@
   corefcn/oct-procbuf.cc \
   corefcn/oct-stream.cc \
   corefcn/oct-strstrm.cc \
+  corefcn/oct-tex-lexer.ll \
+  corefcn/oct-tex-parser.yy \
   corefcn/octave-link.cc \
   corefcn/pager.cc \
   corefcn/pinv.cc \
@@ -295,3 +297,5 @@
 corefcn_libcorefcn_la_SOURCES = $(COREFCN_SRC)
 corefcn_libcorefcn_la_CPPFLAGS = $(liboctinterp_la_CPPFLAGS) $(FFTW_XCPPFLAGS)
 
+corefcn/oct-tex-lexer.cc: LEX_OUTPUT_ROOT := lex.octave_tex_
+corefcn/oct-tex-parser.h: corefcn/oct-tex-parser.yy
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/libinterp/corefcn/oct-tex-lexer.ll	Sun Aug 18 16:36:38 2013 -0400
@@ -0,0 +1,149 @@
+/*
+
+Copyright (C) 2013 Michael Goffioul
+
+This file is part of Octave.
+
+Octave is free software; you can redistribute it and/or modify it
+under the terms of the GNU General Public License as published by the
+Free Software Foundation; either version 3 of the License, or (at your
+option) any later version.
+
+Octave is distributed in the hope that it will be useful, but WITHOUT
+ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+for more details.
+
+You should have received a copy of the GNU General Public License
+along with Octave; see the file COPYING.  If not, see
+<http://www.gnu.org/licenses/>.
+
+*/
+
+%option prefix = "octave_tex_"
+%option noyywrap
+%option reentrant
+%option bison-bridge
+
+%top {
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include "txt-eng.h"
+#include "oct-tex-parser.h"
+}
+
+%x	NUM_MODE
+%x	MAYBE_NUM_MODE
+%x	COMMAND
+
+D       [0-9]
+ID	[a-zA-Z]
+NUM	(({D}+\.?{D}*)|(\.{D}+))
+
+%%
+
+%{
+// Numeric values
+%}
+
+<NUM_MODE>{NUM}		{
+    int nread;
+
+    nread = sscanf (yytext, "%lf", &(yylval->num));
+    if (nread == 1)
+      return NUM;
+  }
+<NUM_MODE>[ \t]+	{ }
+<NUM_MODE>.		{ yyless (0); BEGIN (INITIAL); }
+
+<MAYBE_NUM_MODE>"{"	{ BEGIN (NUM_MODE); return START; }
+<MAYBE_NUM_MODE>.	{ yyless (0); BEGIN (INITIAL); }
+
+%{
+// Simple commands
+%}
+
+"\\bf"		{ return BF; }
+"\\it"		{ return IT; }
+"\\sl"		{ return SL; }
+"\\rm"		{ return RM; }
+
+%{
+// Generic font commands
+%}
+
+"\\fontname"	{ return FONTNAME; }
+"\\fontsize"	{ BEGIN (MAYBE_NUM_MODE); return FONTSIZE; }
+"\\color[rgb]"	{ BEGIN (MAYBE_NUM_MODE); return COLOR_RGB; }
+"\\color"	{ return COLOR; }
+
+%{
+// Special characters
+%}
+
+"{"	{ return START; }
+"}"	{ return END; }
+"^"	{ return SUPER; }
+"_"	{ return SUB; }
+
+"\\{"	|
+"\\}"	|
+"\\^"	|
+"\\_"	|
+"\\\\"	{ yylval->ch = yytext[1]; return CH; }
+
+%{
+// Symbols
+%}
+
+"\\"		{ BEGIN(COMMAND); return CMD; }
+<COMMAND>{ID}	{ yylval->ch = yytext[0]; return ID; }
+<COMMAND>.	{ BEGIN(INITIAL); yyless (0); }
+
+%{
+// Generic character
+%}
+
+.	{ yylval->ch = yytext[0]; return CH; }
+
+%%
+
+bool
+text_parser_tex::init_lexer (const std::string& s)
+{
+  if (! scanner)
+    octave_tex_lex_init (&scanner);
+
+  if (scanner)
+    {
+      if (buffer_state)
+        {
+          octave_tex__delete_buffer (reinterpret_cast<YY_BUFFER_STATE> (buffer_state),
+                                     scanner);
+          buffer_state = 0;
+        }
+
+      buffer_state = octave_tex__scan_bytes (s.data (), s.length (), scanner);
+    }
+
+  return (scanner && buffer_state);
+}
+
+void
+text_parser_tex::destroy_lexer (void)
+{
+  if (buffer_state)
+    {
+      octave_tex__delete_buffer (reinterpret_cast<YY_BUFFER_STATE> (buffer_state),
+                                 scanner);
+      buffer_state = 0;
+    }
+
+  if (scanner)
+    {
+      octave_tex_lex_destroy (scanner);
+      scanner = 0;
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/libinterp/corefcn/oct-tex-parser.yy	Sun Aug 18 16:36:38 2013 -0400
@@ -0,0 +1,206 @@
+/*
+
+Copyright (C) 2013 Michael Goffioul
+
+This file is part of Octave.
+
+Octave is free software; you can redistribute it and/or modify it
+under the terms of the GNU General Public License as published by the
+Free Software Foundation; either version 3 of the License, or (at your
+option) any later version.
+
+Octave is distributed in the hope that it will be useful, but WITHOUT
+ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+for more details.
+
+You should have received a copy of the GNU General Public License
+along with Octave; see the file COPYING.  If not, see
+<http://www.gnu.org/licenses/>.
+
+*/
+
+%{
+#define YYDEBUG 1
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include "txt-eng.h"
+#include "oct-tex-parser.h"
+
+extern int octave_tex_lex (YYSTYPE *, void *);
+static void yyerror (text_parser_tex& parser, const char *s);
+
+#define scanner parser.get_scanner ()
+%}
+
+%name-prefix="octave_tex_"
+%define api.pure
+%parse-param { text_parser_tex& parser } 
+%lex-param { void *scanner }
+
+%code requires {#include <string>}
+
+%union {
+  /* Leaf symbols produced by the scanner */
+  char                       ch;
+  double                     num;
+
+  /* Used for string buffering */
+  std::string*               str;
+
+  /* Objects produced by the parser */
+  text_element*              e_base;
+  text_element_list*         e_list;
+}
+
+%token BF IT SL RM CMD
+%token FONTNAME FONTSIZE
+%token COLOR COLOR_RGB
+%token START END SUPER SUB
+%token<ch> CH ID
+%token<num> NUM
+
+%type<str> simple_string identifier
+%type<e_base> string_element symbol_element
+%type<e_base> superscript_element subscript_element
+%type<e_base> font_modifier_element fontname_element fontsize_element color_element
+%type<e_list> string_element_list scoped_string_element_list
+
+/* Make sure there's no memory leak on parse error. */
+%destructor { } <ch> <num>
+%destructor { delete $$; } <*>
+
+%nonassoc STR
+%nonassoc CH
+
+%start string
+
+%%
+
+simple_string			: CH
+				  { $$ = new std::string (1, $1); }
+				| simple_string CH
+				  { $1->append (1, $2); $$ = $1; }
+				;
+
+identifier			: ID
+				  { $$ = new std::string (1, $1); }
+				| identifier ID
+				  { $1->append (1, $2); $$ = $1; }
+				;
+
+symbol_element			: CMD identifier
+				  {
+				    printf ("symbol: %s\n", $2->c_str ());
+				    $$ = new text_element_symbol (*$2);
+				    delete $2;
+				  }
+				;
+
+font_modifier_element		: BF
+				  { $$ = new text_element_fontstyle (text_element_fontstyle::bold); }
+				| IT
+				  { $$ = new text_element_fontstyle (text_element_fontstyle::italic); }
+				| SL
+				  { $$ = new text_element_fontstyle (text_element_fontstyle::oblique); }
+				| RM
+				  { $$ = new text_element_fontstyle (text_element_fontstyle::normal); }
+				;
+
+fontsize_element		: FONTSIZE START NUM END
+				  { $$ = new text_element_fontsize ($3); }
+				;
+
+fontname_element		: FONTNAME START simple_string END
+				  {
+				    printf ("fontname: %s\n", $3->c_str ());
+				    $$ = new text_element_fontname (*$3);
+				    delete $3;
+				  }
+				;
+
+color_element			: COLOR START simple_string END
+				  {
+				    printf ("color: %s\n", $3->c_str ());
+				    $$ = new text_element_color (*$3);
+				    delete $3;
+				  }
+				| COLOR_RGB START NUM NUM NUM END
+				  {
+				    printf ("color: %g %g %g\n", $3, $4, $5);
+				    $$ = new text_element_color ($3, $4, $5);
+				  }
+				;
+
+string_element			: simple_string %prec STR
+				  {
+				    printf ("string: \"%s\"\n", $1->c_str ());
+				    $$ = new text_element_string (*$1);
+				    delete $1;
+				  }
+				| scoped_string_element_list
+				  /* This is just to avoid a warning in bison. */
+				  { $$ = $1; }
+				| symbol_element
+				| font_modifier_element
+				| fontsize_element
+				| fontname_element
+				| color_element
+				| superscript_element
+				| subscript_element
+				;
+
+superscript_element		: SUPER CH
+				  { $$ = new text_element_superscript ($2); }
+				| SUPER scoped_string_element_list
+				  { $$ = new text_element_superscript ($2); }
+				;
+
+subscript_element		: SUB CH
+				  { $$ = new text_element_subscript ($2); }
+				| SUB scoped_string_element_list
+				  { $$ = new text_element_subscript ($2); }
+				;
+
+string_element_list		: string_element
+				  { $$ = new text_element_list ($1); }
+				| string_element_list string_element
+				  { $1->push_back ($2); $$ = $1; }
+				;
+
+scoped_string_element_list	: START string_element_list END
+				  { $$ = $2; }
+				;
+
+string				: /* empty */
+				  { parser.set_parse_result (new text_element_string ("")); }
+				| string_element_list
+				  { parser.set_parse_result ($1); }
+				;
+
+%%
+
+text_element*
+text_parser_tex::parse (const std::string& s)
+{
+  octave_tex_debug = 0;
+
+  if (init_lexer (s))
+    {
+      result = 0;
+
+      if (octave_tex_parse (*this) == 0)
+        return result;
+    }
+
+  return new text_element_string (s);
+}
+
+static void
+yyerror (text_parser_tex&, const char *s)
+{
+  fprintf (stderr, "parse error: %s\n", s);
+}
--- a/libinterp/corefcn/txt-eng-ft.cc	Sat Aug 17 11:45:20 2013 -0700
+++ b/libinterp/corefcn/txt-eng-ft.cc	Sun Aug 18 16:36:38 2013 -0400
@@ -594,9 +594,10 @@
 }
 
 Matrix
-ft_render::get_extent (const std::string& txt, double rotation)
+ft_render::get_extent (const std::string& txt, double rotation,
+                       const caseless_str& interpreter)
 {
-  text_element *elt = text_parser_none ().parse (txt);
+  text_element *elt = text_parser::parse (txt, interpreter);
   Matrix extent = get_extent (elt, rotation);
   delete elt;
 
@@ -621,14 +622,15 @@
 void
 ft_render::text_to_pixels (const std::string& txt,
                            uint8NDArray& pixels_, Matrix& box,
-                           int halign, int valign, double rotation)
+                           int halign, int valign, double rotation,
+                           const caseless_str& interpreter)
 {
   // FIXME: clip "rotation" between 0 and 360
   int rot_mode = rotation_to_mode (rotation);
 
   multiline_halign = halign;
 
-  text_element *elt = text_parser_none ().parse (txt);
+  text_element *elt = text_parser::parse (txt, interpreter);
   pixels_ = render (elt, box, rot_mode);
   delete elt;
 
--- a/libinterp/corefcn/txt-eng-ft.h	Sat Aug 17 11:45:20 2013 -0700
+++ b/libinterp/corefcn/txt-eng-ft.h	Sun Aug 18 16:36:38 2013 -0400
@@ -68,7 +68,8 @@
                        int rotation = ROTATION_0);
 
   Matrix get_extent (text_element *elt, double rotation = 0.0);
-  Matrix get_extent (const std::string& txt, double rotation = 0.0);
+  Matrix get_extent (const std::string& txt, double rotation = 0.0,
+                     const caseless_str& interpreter = "tex");
 
   void set_font (const std::string& name, const std::string& weight,
                  const std::string& angle, double size);
@@ -79,7 +80,8 @@
 
   void text_to_pixels (const std::string& txt,
                        uint8NDArray& pixels_, Matrix& bbox,
-                       int halign, int valign, double rotation);
+                       int halign, int valign, double rotation,
+                       const caseless_str& interpreter = "tex");
 
 private:
   int rotation_to_mode (double rotation) const;
--- a/libinterp/corefcn/txt-eng.h	Sat Aug 17 11:45:20 2013 -0700
+++ b/libinterp/corefcn/txt-eng.h	Sun Aug 18 16:36:38 2013 -0400
@@ -23,13 +23,18 @@
 #if ! defined (txt_eng_h)
 #define txt_eng_h 1
 
+#include <memory>
+#include <string>
+
 #include "base-list.h"
+#include "caseless-str.h"
+#include "dMatrix.h"
 
 class text_element;
 class text_element_string;
 class text_element_list;
-class text_subscript_element;
-class text_superscript_element;
+class text_element_subscript;
+class text_element_superscript;
 
 class text_processor;
 
@@ -54,7 +59,7 @@
 {
 public:
   text_element_string (const std::string& s = "")
-      : text_element (), str (s) { }
+    : text_element (), str (s) { }
 
   ~text_element_string (void) { }
 
@@ -71,13 +76,30 @@
 
 class
 OCTINTERP_API
+text_element_symbol : public text_element_string
+{
+public:
+  text_element_symbol (const std::string& sym)
+    : text_element_string (sym) { }
+
+  ~text_element_symbol (void) { }
+
+  void accept (text_processor& p);
+};
+
+class
+OCTINTERP_API
 text_element_list :
     public text_element,
     public octave_base_list<text_element *>
 {
 public:
   text_element_list (void)
-      : text_element (), octave_base_list<text_element*> () { }
+    : text_element (), octave_base_list<text_element*> () { }
+
+  text_element_list (text_element* e)
+    : text_element (), octave_base_list<text_element*> ()
+    { push_back (e); }
 
   ~text_element_list (void)
     {
@@ -94,28 +116,164 @@
 
 class
 OCTINTERP_API
-text_subscript_element : public text_element_list
+text_element_subscript : public text_element
+{
+public:
+  text_element_subscript (text_element* e)
+    : text_element (), elem (e) { }
+
+  text_element_subscript (char c)
+    : text_element ()
+    { elem = new text_element_string (std::string (1, c)); }
+
+  ~text_element_subscript (void)
+    { delete elem; }
+
+  void accept (text_processor& p);
+
+  text_element* get_element (void) { return elem; }
+
+private:
+  text_element* elem;
+
+private:
+  text_element_subscript (void);
+};
+
+class
+OCTINTERP_API
+text_element_superscript : public text_element
 {
 public:
-  text_subscript_element (void)
-      : text_element_list () { }
+  text_element_superscript (text_element* e)
+    : text_element (), elem (e) { }
 
-  ~text_subscript_element (void) { }
+  text_element_superscript (char c)
+    : text_element ()
+    { elem = new text_element_string (std::string (1, c)); }
+
+  ~text_element_superscript (void)
+    { delete elem; }
 
   void accept (text_processor& p);
+
+  text_element* get_element (void) { return elem; }
+
+private:
+  text_element* elem;
+
+private:
+  text_element_superscript (void);
+};
+
+class
+OCTINTERP_API
+text_element_fontstyle : public text_element
+{
+public:
+  enum fontstyle
+    {
+      normal,
+      bold,
+      italic,
+      oblique
+    };
+
+  text_element_fontstyle (fontstyle st)
+    : text_element (), style (st) { }
+
+  ~text_element_fontstyle (void) { }
+
+  void accept (text_processor& p);
+
+private:
+  fontstyle style;
+
+private:
+  text_element_fontstyle (void);
 };
 
 class
 OCTINTERP_API
-text_superscript_element : public text_element_list
+text_element_fontname : public text_element
+{
+public:
+  text_element_fontname (const std::string& fname)
+    : text_element (), name (fname) { }
+
+  ~text_element_fontname (void) { }
+
+  const std::string& fontname (void) const { return name; }
+
+  void accept (text_processor& p);
+
+private:
+  std::string name;
+
+private:
+  text_element_fontname (void);
+};
+
+class
+OCTINTERP_API
+text_element_fontsize : public text_element
 {
 public:
-  text_superscript_element (void)
-      : text_element_list () { }
+  text_element_fontsize (double fsize)
+    : text_element (), size (fsize) { }
 
-  ~text_superscript_element (void) { }
+  ~text_element_fontsize (void) { }
+
+  double fontsize (void) const { return size; }
 
   void accept (text_processor& p);
+
+private:
+  double size;
+
+private:
+  text_element_fontsize (void);
+};
+
+class
+OCTINTERP_API
+text_element_color : public text_element
+{
+public:
+  text_element_color (double r, double g, double b)
+    : text_element (), rgb (1, 3, 0.0)
+    {
+      rgb(0) = r;
+      rgb(1) = g;
+      rgb(2) = b;
+    }
+
+  text_element_color (const std::string& cname)
+    : text_element (), rgb (1, 3, 0.0)
+    {
+#define ASSIGN_COLOR(r,g,b) { rgb(0) = r; rgb(1) = g; rgb(2) = b; }
+      if (cname == "red") ASSIGN_COLOR(1, 0, 0)
+      else if (cname == "green") ASSIGN_COLOR(0, 1, 0)
+      else if (cname == "yellow") ASSIGN_COLOR(1, 1, 0)
+      else if (cname == "magenta") ASSIGN_COLOR(1, 0, 1)
+      else if (cname == "blue") ASSIGN_COLOR(0, 0, 1)
+      else if (cname == "black") ASSIGN_COLOR(0, 0, 0)
+      else if (cname == "white") ASSIGN_COLOR(1, 1, 1)
+      else if (cname == "gray") ASSIGN_COLOR(.5, .5, .5)
+      else if (cname == "darkGreen") ASSIGN_COLOR(0, .5, 0)
+      else if (cname == "orange") ASSIGN_COLOR(1, .65, 0)
+      else if (cname == "lightBlue") ASSIGN_COLOR(0.68, .85, .9)
+#undef ASSIGN_COLOR
+    }
+
+  ~text_element_color (void) { }
+
+  Matrix get_color (void) { return rgb; }
+
+  void accept (text_processor& p);
+
+private:
+  Matrix rgb;
 };
 
 class
@@ -125,6 +283,8 @@
 public:
   virtual void visit (text_element_string& e) = 0;
 
+  virtual void visit (text_element_symbol&) { }
+
   virtual void visit (text_element_list& e)
     {
       for (text_element_list::iterator it = e.begin ();
@@ -134,11 +294,19 @@
         }
     }
 
-  virtual void visit (text_subscript_element& e)
-    { visit (dynamic_cast<text_element_list&> (e)); }
+  virtual void visit (text_element_subscript& e)
+    { e.get_element ()->accept (*this); }
+
+  virtual void visit (text_element_superscript& e)
+    { e.get_element ()->accept (*this); }
 
-  virtual void visit (text_superscript_element& e)
-    { visit (dynamic_cast<text_element_list&> (e)); }
+  virtual void visit (text_element_fontstyle&) { }
+
+  virtual void visit (text_element_fontname&) { }
+
+  virtual void visit (text_element_fontsize&) { }
+
+  virtual void visit (text_element_color&) { }
 
   virtual void reset (void) { }
 
@@ -154,9 +322,14 @@
 { p.visit (*this); }
 
 TEXT_ELEMENT_ACCEPT(text_element_string)
+TEXT_ELEMENT_ACCEPT(text_element_symbol)
 TEXT_ELEMENT_ACCEPT(text_element_list)
-TEXT_ELEMENT_ACCEPT(text_subscript_element)
-TEXT_ELEMENT_ACCEPT(text_superscript_element)
+TEXT_ELEMENT_ACCEPT(text_element_subscript)
+TEXT_ELEMENT_ACCEPT(text_element_superscript)
+TEXT_ELEMENT_ACCEPT(text_element_fontstyle)
+TEXT_ELEMENT_ACCEPT(text_element_fontname)
+TEXT_ELEMENT_ACCEPT(text_element_fontsize)
+TEXT_ELEMENT_ACCEPT(text_element_color)
 
 class
 OCTINTERP_API
@@ -168,6 +341,10 @@
   virtual ~text_parser (void) { }
 
   virtual text_element* parse (const std::string& s) = 0;
+
+public:
+  static text_element* parse (const std::string& s,
+                              const caseless_str& interpreter);
 };
 
 class
@@ -190,4 +367,50 @@
     }
 };
 
+class
+OCTINTERP_API
+text_parser_tex : public text_parser
+{
+public:
+  text_parser_tex (void)
+    : text_parser (), scanner (0), buffer_state (0), result (0)
+    { }
+
+  ~text_parser_tex (void)
+    { destroy_lexer (); }
+
+  text_element* parse (const std::string& s);
+
+  void* get_scanner (void) { return scanner; }
+
+  void set_parse_result (text_element* e) { result = e; }
+
+  text_element* get_parse_result (void) { return result; }
+
+private:
+  bool init_lexer (const std::string& s);
+
+  void destroy_lexer (void);
+
+private:
+  void* scanner;
+
+  void* buffer_state;
+
+  text_element* result;
+};
+
+inline text_element*
+text_parser::parse (const std::string& s, const caseless_str& interpreter)
+{
+  std::auto_ptr<text_parser> parser;
+
+  if (interpreter.compare ("tex"))
+    parser.reset (new text_parser_tex ());
+  else
+    parser.reset (new text_parser_none ());
+
+  return parser->parse (s);
+}
+
 #endif