Mercurial > hg > octave-lyh
changeset 17277: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 +++ b/libinterp/Makefile.am @@ -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 +++ b/libinterp/corefcn/gl-render.cc @@ -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 +++ b/libinterp/corefcn/graphics.cc @@ -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 +++ b/libinterp/corefcn/module.mk @@ -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
new file mode 100644 --- /dev/null +++ b/libinterp/corefcn/oct-tex-lexer.ll @@ -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; + } +}
new file mode 100644 --- /dev/null +++ b/libinterp/corefcn/oct-tex-parser.yy @@ -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 +++ b/libinterp/corefcn/txt-eng-ft.cc @@ -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 +++ b/libinterp/corefcn/txt-eng-ft.h @@ -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 +++ b/libinterp/corefcn/txt-eng.h @@ -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