ae9dae720b
Use ksc5601.h header from XFree86 Project Inc. Patch contributed by Oliver-Rainer Wittmann with minor changes from Pedro Giffuni http://svn.apache.org/viewvc?view=revision&revision=1179296
746 lines
23 KiB
C++
746 lines
23 KiB
C++
/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
|
||
/*
|
||
* This file is part of the LibreOffice project.
|
||
*
|
||
* This Source Code Form is subject to the terms of the Mozilla Public
|
||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
||
*
|
||
* This file incorporates work covered by the following license notice:
|
||
*
|
||
* Licensed to the Apache Software Foundation (ASF) under one or more
|
||
* contributor license agreements. See the NOTICE file distributed
|
||
* with this work for additional information regarding copyright
|
||
* ownership. The ASF licenses this file to you under the Apache
|
||
* License, Version 2.0 (the "License"); you may not use this file
|
||
* except in compliance with the License. You may obtain a copy of
|
||
* the License at http://www.apache.org/licenses/LICENSE-2.0 .
|
||
*/
|
||
|
||
#include <assert.h>
|
||
#include <stdio.h>
|
||
#include <string.h>
|
||
#include <ctype.h>
|
||
|
||
// DVO: always use standard headers:
|
||
#include <istream>
|
||
#include <sstream>
|
||
using namespace std;
|
||
|
||
#include "mzstring.h"
|
||
#include "hwpeq.h"
|
||
#include <sal/types.h>
|
||
#include <sal/macros.h>
|
||
|
||
/* @Man: hwp¼ö½ÄÀ» LaTeXÀ¸·Î ¹Ù²Ù±â */
|
||
#ifdef WIN32
|
||
# define ENDL "\r\n"
|
||
#else /* !WIN32 */
|
||
# define ENDL "\n"
|
||
#endif
|
||
|
||
#define WS " \t\r\n\v\f"
|
||
|
||
#define EQ_CASE 0x01 // case sensitive cmd
|
||
#define EQ_ENV 0x02 // equiv to latex environment
|
||
#define EQ_ATOP 0x04 // must revert order
|
||
|
||
#define IS_WS(ch) (strchr(WS, ch))
|
||
#define IS_BINARY(ch) (strchr("+-<=>", ch))
|
||
|
||
#ifdef WIN32
|
||
#define STRICMP stricmp
|
||
#else
|
||
#define STRICMP strcasecmp
|
||
#endif
|
||
|
||
// sub and sup scipt script status
|
||
enum { SCRIPT_NONE, SCRIPT_SUB, SCRIPT_SUP, SCRIPT_ALL};
|
||
|
||
static int eq_word(MzString& outs, istream *strm, int script = SCRIPT_NONE);
|
||
static bool eq_sentence(MzString& outs, istream *strm, const char *end = 0);
|
||
|
||
struct hwpeq {
|
||
const char *key; // hwp math keyword
|
||
const char *latex; // corresponding latex keywork
|
||
int nargs; // # of argument
|
||
unsigned char flag; // case sensitive?
|
||
};
|
||
|
||
static hwpeq eq_tbl[] = {
|
||
{ "!=", "\\equiv ", 0, 0 },
|
||
{ "#", "\\\\", 0, 0 },
|
||
{ "+-", "\\pm ", 0, 0 },
|
||
{ "-+", "\\mp ", 0, 0 },
|
||
{ "<=", "\\leq ", 0, 0 },
|
||
{ "==", "\\equiv ", 0, 0 },
|
||
{ ">=", "\\geq ", 0, 0 },
|
||
{ "Pr", NULL, 0, 0 },
|
||
{ "^", "^", 1, 0 },
|
||
{ "_", "_", 1, 0 },
|
||
{ "`", "\\;", 0, 0 },
|
||
{ "acute", NULL, 1, 0 },
|
||
{ "aleph", NULL, 0, 0 },
|
||
{ "alpha", NULL, 0, EQ_CASE },
|
||
{ "amalg", NULL, 0, 0 },
|
||
{ "and", NULL, 0, 0 },
|
||
{ "angle", NULL, 0, 0 },
|
||
{ "angstrom", NULL, 0, 0 },
|
||
{ "approx", NULL, 0, 0 },
|
||
{ "arc", NULL, 0, 0 },
|
||
{ "arccos", NULL, 0, 0 },
|
||
{ "arch", NULL, 0, 0 },
|
||
{ "arcsin", NULL, 0, 0 },
|
||
{ "arctan", NULL, 0, 0 },
|
||
{ "arg", NULL, 0, 0 },
|
||
{ "assert", "\\vdash", 0, 0 },
|
||
{ "ast", NULL, 0, 0 },
|
||
{ "asymp", NULL, 0, 0 },
|
||
{ "atop", NULL, 1, EQ_ATOP },
|
||
{ "backslash", NULL, 0, 0 },
|
||
{ "bar", NULL, 1, 0 },
|
||
{ "because", NULL, 0, 0 },
|
||
{ "beta", NULL, 0, EQ_CASE },
|
||
{ "big", NULL, 0, EQ_CASE },
|
||
{ "bigcap", NULL, 0, 0 },
|
||
{ "bigcirc", NULL, 0, 0 },
|
||
{ "bigcup", NULL, 0, 0 },
|
||
{ "bigg", NULL, 0, EQ_CASE },
|
||
{ "bigodiv", NULL, 0, 0 },
|
||
{ "bigodot", NULL, 0, 0 },
|
||
{ "bigominus", NULL, 0, 0 },
|
||
{ "bigoplus", NULL, 0, 0 },
|
||
{ "bigotimes", NULL, 0, 0 },
|
||
{ "bigsqcap", NULL, 0, 0 },
|
||
{ "bigsqcup", NULL, 0, 0 },
|
||
{ "biguplus", NULL, 0, 0 },
|
||
{ "bigvee", NULL, 0, 0 },
|
||
{ "bigwedge", NULL, 0, 0 },
|
||
{ "binom", NULL, 2, 0 },
|
||
{ "bmatrix", NULL, 0, EQ_ENV },
|
||
{ "bold", NULL, 0, 0 },
|
||
{ "bot", NULL, 0, 0 },
|
||
{ "breve", NULL, 1, 0 },
|
||
{ "buildrel", NULL, 0, 0 }, // LATER
|
||
{ "bullet", NULL, 0, 0 },
|
||
{ "cap", NULL, 0, 0 },
|
||
{ "cases", NULL, 0, EQ_ENV },
|
||
{ "ccol", NULL, 0, 0 }, /* ¼¼·Î·Î °¡¿îµ¥ */
|
||
{ "cdot", NULL, 0, 0 },
|
||
{ "cdots", NULL, 0, 0 },
|
||
{ "check", NULL, 1, 0 },
|
||
{ "chi", NULL, 0, EQ_CASE },
|
||
{ "choose", NULL, 0, EQ_ATOP },
|
||
{ "circ", NULL, 0, 0 },
|
||
{ "col", NULL, 0, 0 }, // LATER
|
||
{ "cong", NULL, 0, 0 },
|
||
{ "coprod", NULL, 0, 0 },
|
||
{ "cos", NULL, 0, 0 },
|
||
{ "cosec", NULL, 0, 0 },
|
||
{ "cosh", NULL, 0, 0 },
|
||
{ "cot", NULL, 0, 0 },
|
||
{ "coth", NULL, 0, 0 },
|
||
{ "cpile", NULL, 0, 0 }, // LATER
|
||
{ "csc", NULL, 0, 0 },
|
||
{ "cup", NULL, 0, 0 },
|
||
{ "dagger", NULL, 0, 0 },
|
||
{ "dashv", NULL, 0, 0 },
|
||
{ "ddagger", NULL, 0, 0 },
|
||
{ "ddot", NULL, 1, 0 },
|
||
{ "ddots", NULL, 0, 0 },
|
||
{ "def", NULL, 0, 0 },
|
||
{ "deg", NULL, 0, 0 },
|
||
{ "del", NULL, 0, 0 },
|
||
{ "delta", NULL, 0, EQ_CASE },
|
||
{ "diamond", NULL, 0, 0 },
|
||
{ "dim", NULL, 0, 0 },
|
||
{ "div", NULL, 0, 0 },
|
||
{ "divide", NULL, 0, 0 },
|
||
{ "dline", NULL, 0, 0 },
|
||
{ "dmatrix", NULL, 0, EQ_ENV },
|
||
{ "dot", NULL, 1, 0 },
|
||
{ "doteq", NULL, 0, 0 },
|
||
{ "dotsaxis", NULL, 0, 0 },
|
||
{ "dotsdiag", NULL, 0, 0 },
|
||
{ "dotslow", "\\ldots", 0, 0 },
|
||
{ "dotsvert", "\\vdots", 0, 0 },
|
||
{ "downarrow", NULL, 0, EQ_CASE },
|
||
{ "dsum", "+", 0, 0 },
|
||
{ "dyad", NULL, 0, 0 }, // LATER
|
||
{ "ell", NULL, 0, 0 },
|
||
{ "emptyset", NULL, 0, 0 },
|
||
{ "epsilon", NULL, 0, EQ_CASE },
|
||
{ "eqalign", NULL, 0, EQ_ENV },
|
||
{ "equiv", NULL, 0, 0 },
|
||
{ "eta", NULL, 0, EQ_CASE },
|
||
{ "exarrow", NULL, 0, 0 },
|
||
{ "exist", "\\exists", 0, 0 },
|
||
{ "exists", NULL, 0, 0 },
|
||
{ "exp", NULL, 0, EQ_CASE },
|
||
{ "for", NULL, 0, 0 },
|
||
{ "forall", NULL, 0, 0 },
|
||
{ "from", "_", 1, 0 },
|
||
{ "gamma", NULL, 0, EQ_CASE },
|
||
{ "gcd", NULL, 0, 0 },
|
||
{ "ge", "\\geq", 0, 0 },
|
||
{ "geq", NULL, 0, 0 },
|
||
{ "ggg", NULL, 0, 0 },
|
||
{ "grad", NULL, 0, 0 },
|
||
{ "grave", NULL, 1, 0 },
|
||
{ "hat", "\\widehat", 1, 0 },
|
||
{ "hbar", NULL, 0, 0 },
|
||
{ "hom", NULL, 0, 0 },
|
||
{ "hookleft", NULL, 0, 0 },
|
||
{ "hookright", NULL, 0, 0 },
|
||
{ "identical", NULL, 0, 0 }, // LATER
|
||
{ "if", NULL, 0, 0 },
|
||
{ "imag", NULL, 0, 0 },
|
||
{ "image", NULL, 0, 0 },
|
||
{ "imath", NULL, 0, 0 },
|
||
{ "in", NULL, 0, 0 },
|
||
{ "inf", "\\infty", 0, 0 },
|
||
{ "infinity", "\\infty", 0, 0 },
|
||
{ "infty", NULL, 0, 0 },
|
||
{ "int", NULL, 0, 0 },
|
||
{ "integral", "\\int", 0, 0 },
|
||
{ "inter", "\\bigcap", 0, 0 },
|
||
{ "iota", NULL, 0, EQ_CASE },
|
||
{ "iso", NULL, 0, 0 }, // ams
|
||
{ "it", NULL, 0, 0 },
|
||
{ "jmath", NULL, 0, 0 },
|
||
{ "kappa", NULL, 0, EQ_CASE },
|
||
{ "ker", NULL, 0, 0 },
|
||
{ "lambda", NULL, 0, EQ_CASE },
|
||
{ "land", NULL, 0, 0 }, // LATER
|
||
{ "langle", NULL, 0, 0 },
|
||
{ "larrow", "\\leftarrow", 0, EQ_CASE },
|
||
{ "lbrace", NULL, 0, 0 },
|
||
{ "lbrack", "[", 0, 0 },
|
||
{ "lceil", NULL, 0, 0 },
|
||
{ "lcol", NULL, 0, 0 }, // LATER
|
||
{ "ldots", NULL, 0, 0 },
|
||
{ "le", NULL, 0, 0 },
|
||
{ "left", NULL, 0, 0 },
|
||
{ "leftarrow", NULL, 0, EQ_CASE },
|
||
{ "leq", NULL, 0, 0 },
|
||
{ "lfloor", NULL, 0, 0 },
|
||
{ "lg", NULL, 0, 0 },
|
||
{ "lim", NULL, 0, EQ_CASE },
|
||
{ "line", "\\vert", 0, 0 },
|
||
{ "liter", "\\ell", 0, 0 },
|
||
{ "lll", NULL, 0, 0 }, // ams
|
||
{ "ln", NULL, 0, 0 },
|
||
{ "log", NULL, 0, 0 },
|
||
{ "lor", "\\vee", 0, 0 },
|
||
{ "lparen", "(", 0, 0 },
|
||
{ "lpile", NULL, 0, 0 }, // LATER
|
||
{ "lrarrow", "\\leftrightarrow", 0, EQ_CASE },
|
||
{ "lrharpoons", "\\leftrightharpoons",0, 0 },
|
||
{ "mapsto", NULL, 0, 0 },
|
||
{ "massert", "\\dashv", 0, 0 },
|
||
{ "matrix", NULL, 0, EQ_ENV },
|
||
{ "max", NULL, 0, 0 },
|
||
{ "mho", NULL, 0, 0 }, // ams
|
||
{ "min", NULL, 0, 0 },
|
||
{ "minusplus", NULL, 0, 0 },
|
||
{ "mit", "", 0, 0 }, // font
|
||
{ "mod", "\\bmod", 0, 0 },
|
||
{ "models", NULL, 0, 0 },
|
||
{ "msangle", NULL, 0, 0 }, // LATER
|
||
{ "mu", NULL, 0, EQ_CASE },
|
||
{ "nabla", NULL, 0, 0 },
|
||
{ "ne", NULL, 0, 0 },
|
||
{ "nearrow", NULL, 0, 0 },
|
||
{ "neg", NULL, 0, 0 },
|
||
{ "neq", NULL, 0, 0 },
|
||
{ "nequiv", NULL, 0, 0 },
|
||
{ "ni", NULL, 0, 0 },
|
||
{ "not", NULL, 0, 0 },
|
||
{ "notin", NULL, 0, 0 },
|
||
{ "nu", NULL, 0, EQ_CASE },
|
||
{ "nwarrow", NULL, 0, 0 },
|
||
{ "odiv", NULL, 0, 0 },
|
||
{ "odot", NULL, 0, 0 },
|
||
{ "oint", NULL, 0, 0 },
|
||
{ "omega", NULL, 0, EQ_CASE },
|
||
{ "omicron", NULL, 0, EQ_CASE },
|
||
{ "ominus", NULL, 0, 0 },
|
||
{ "oplus", NULL, 0, 0 },
|
||
{ "or ", NULL, 0, 0 },
|
||
{ "oslash", NULL, 0, 0 },
|
||
{ "otimes", NULL, 0, 0 },
|
||
{ "over", NULL, 1, EQ_ATOP },
|
||
{ "overline", NULL, 1, 0 },
|
||
{ "owns", "\\ni", 0, 0 },
|
||
{ "parallel", NULL, 0, 0 },
|
||
{ "partial", NULL, 0, 0 },
|
||
{ "phantom", NULL, 0, 0 },
|
||
{ "phi", NULL, 0, EQ_CASE },
|
||
{ "pi", NULL, 0, EQ_CASE },
|
||
{ "pile", NULL, 0, 0 }, // LATER
|
||
{ "plusminus", "\\pm", 0, 0 },
|
||
{ "pmatrix", NULL, 0, EQ_ENV },
|
||
{ "prec", NULL, 0, 0 },
|
||
{ "prep", NULL, 0, 0 },
|
||
{ "prime", NULL, 0, 0 },
|
||
{ "prod", NULL, 0, 0 },
|
||
{ "propto", NULL, 0, 0 },
|
||
{ "psi", NULL, 0, EQ_CASE },
|
||
{ "rangle", NULL, 0, 0 },
|
||
{ "rarrow", "\\rightarrow", 0, EQ_CASE },
|
||
{ "rbrace", "]", 0, 0 },
|
||
{ "rbrace", NULL, 0, 0 },
|
||
{ "rceil", NULL, 0, 0 },
|
||
{ "rcol", NULL, 0, 0 }, // LATER
|
||
{ "real", "\\Re", 0, 0 },
|
||
{ "reimage", NULL, 0, 0 },
|
||
{ "rel", NULL, 0, 0 },
|
||
{ "rfloor", NULL, 0, 0 },
|
||
{ "rho", NULL, 0, EQ_CASE },
|
||
{ "right", NULL, 0, 0 },
|
||
{ "rightarrow", NULL, 0, EQ_CASE },
|
||
{ "rlharpoons", NULL, 0, 0 },
|
||
{ "rm", NULL, 0, 0 },
|
||
{ "root", "\\sqrt", 1, 0 },
|
||
{ "rparen", ")", 0, 0 },
|
||
{ "rpile", NULL, 0, 0 }, // LATER
|
||
{ "rtangle", NULL, 0, 0 },
|
||
{ "sangle", NULL, 0, 0 },
|
||
{ "scale", NULL, 0, 0 },
|
||
{ "searrow", NULL, 0, 0 },
|
||
{ "sec", NULL, 0, 0 },
|
||
{ "sigma", NULL, 0, EQ_CASE },
|
||
{ "sim", NULL, 0, 0 },
|
||
{ "simeq", NULL, 0, 0 },
|
||
{ "sin", NULL, 0, 0 },
|
||
{ "sinh", NULL, 0, 0 },
|
||
{ "slash", NULL, 0, 0 },
|
||
{ "smallint", NULL, 0, 0 },
|
||
{ "smallinter", NULL, 0, 0 },
|
||
{ "smalloint", NULL, 0, 0 },
|
||
{ "smallprod", NULL, 0, 0 },
|
||
{ "smallsum", NULL, 0, 0 },
|
||
{ "smallunion", NULL, 0, 0 },
|
||
{ "smcoprod", NULL, 0, 0 },
|
||
{ "sqcap", NULL, 0, 0 },
|
||
{ "sqcup", NULL, 0, 0 },
|
||
{ "sqrt", NULL, 1, 0 },
|
||
{ "sqsubset", NULL, 0, 0 },
|
||
{ "sqsubseteq", NULL, 0, 0 },
|
||
{ "sqsupset", NULL, 0, 0 },
|
||
{ "sqsupseteq", NULL, 0, 0 },
|
||
{ "star", NULL, 0, 0 },
|
||
{ "sub", "_", 0, 0 },
|
||
{ "subset", NULL, 0, 0 },
|
||
{ "subseteq", NULL, 0, 0 },
|
||
{ "succ", NULL, 0, 0 },
|
||
{ "sum", NULL, 0, 0 },
|
||
{ "sup", "^", 0, 0 },
|
||
{ "superset", NULL, 0, 0 },
|
||
{ "supset", NULL, 0, 0 },
|
||
{ "supseteq", NULL, 0, 0 },
|
||
{ "swarrow", NULL, 0, 0 },
|
||
{ "tan", NULL, 0, 0 },
|
||
{ "tanh", NULL, 0, 0 },
|
||
{ "tau", NULL, 0, EQ_CASE },
|
||
{ "therefore", NULL, 0, 0 },
|
||
{ "theta", NULL, 0, EQ_CASE },
|
||
{ "tilde", "\\widetilde", 1, 0 },
|
||
{ "times", NULL, 0, 0 },
|
||
{ "to", "^", 1, 0 },
|
||
{ "top", NULL, 0, 0 },
|
||
{ "triangle", NULL, 0, 0 },
|
||
{ "triangled", NULL, 0, 0 },
|
||
{ "trianglel", NULL, 0, 0 },
|
||
{ "triangler", NULL, 0, 0 },
|
||
{ "triangleu", NULL, 0, 0 },
|
||
{ "udarrow", "\\updownarrow",0, EQ_CASE },
|
||
{ "under", "\\underline", 1, 0 },
|
||
{ "underline", "\\underline", 1, 0 },
|
||
{ "union", "\\bigcup", 0, 0 },
|
||
{ "uparrow", NULL, 0, EQ_CASE },
|
||
{ "uplus", NULL, 0, 0 },
|
||
{ "upsilon", NULL, 0, EQ_CASE },
|
||
{ "varepsilon", NULL, 0, 0 },
|
||
{ "varphi", NULL, 0, 0 },
|
||
{ "varpi", NULL, 0, 0 },
|
||
{ "varrho", NULL, 0, 0 },
|
||
{ "varsigma", NULL, 0, 0 },
|
||
{ "vartheta", NULL, 0, 0 },
|
||
{ "varupsilon", NULL, 0, 0 },
|
||
{ "vdash", NULL, 0, 0 },
|
||
{ "vdots", NULL, 0, 0 },
|
||
{ "vec", NULL, 1, 0 },
|
||
{ "vee", NULL, 0, 0 },
|
||
{ "vert", NULL, 0, 0 },
|
||
{ "wedge", NULL, 0, 0 },
|
||
{ "wp", NULL, 0, 0 },
|
||
{ "xi", NULL, 0, EQ_CASE },
|
||
{ "xor", NULL, 0, 0 },
|
||
{ "zeta", NULL, 0, EQ_CASE }
|
||
};
|
||
|
||
static hwpeq *lookup_eqn(char *str)
|
||
{
|
||
static int eqCount = SAL_N_ELEMENTS(eq_tbl);
|
||
int m, k, l = 0, r = eqCount;
|
||
hwpeq *result = 0;
|
||
|
||
while( l < r ) {
|
||
m = (l + r) / 2;
|
||
k = strcmp(eq_tbl[m].key, str);
|
||
if( k == 0 ) {
|
||
result = eq_tbl + m;;
|
||
break;
|
||
}
|
||
else if( k < 0 )
|
||
l = m + 1;
|
||
else
|
||
r = m;
|
||
}
|
||
return result;
|
||
}
|
||
|
||
/* ùÀÚ¸¸ ´ë¹®ÀÚÀ̰ųª ÀüºÎ ´ë¹®ÀÚ¸é ¼Ò¹®ÀÚ·Î ¹Ù²Û´Ù. */
|
||
|
||
static char *make_keyword( char *keyword, const char *token)
|
||
{
|
||
assert(keyword);
|
||
char *ptr;
|
||
int result = true, len = strlen(token);
|
||
|
||
if( 255 < len )
|
||
strncpy(keyword, token, 255);
|
||
else
|
||
strcpy(keyword, token);
|
||
|
||
if( (token[0] & 0x80) || islower(token[0]) ||
|
||
strlen(token) < 2 )
|
||
return keyword;
|
||
|
||
int capital = isupper(keyword[1]);
|
||
for( ptr = keyword + 2; *ptr && result; ptr++ )
|
||
if( (*ptr & 0x80) ||
|
||
(!capital && isupper(*ptr)) ||
|
||
(capital && islower(*ptr)) )
|
||
result = false;
|
||
|
||
if( result ) {
|
||
ptr = keyword;
|
||
while( *ptr ) {
|
||
if( isupper(*ptr) )
|
||
*ptr = sal::static_int_cast<char>(tolower(*ptr));
|
||
ptr++;
|
||
}
|
||
}
|
||
return keyword;
|
||
}
|
||
|
||
// token reading funtion
|
||
struct eq_stack {
|
||
MzString white;
|
||
MzString token;
|
||
istream *strm;
|
||
|
||
eq_stack() { strm = 0; };
|
||
bool state(istream *s) {
|
||
if( strm != s) { white = 0; token = 0; }
|
||
return token.length() != 0;
|
||
}
|
||
};
|
||
|
||
static eq_stack *stk = 0;
|
||
|
||
void push_token(MzString &white, MzString &token, istream *strm)
|
||
{
|
||
// one time stack
|
||
assert(stk->state(strm) == false);
|
||
|
||
stk->white = white;
|
||
stk->token = token;
|
||
stk->strm = strm;
|
||
}
|
||
|
||
/*
|
||
ÀÐÀº ÅäÅ«ÀÇ ±æÀ̸¦ ¹ÝȯÇÑ´Ù. */
|
||
/* control char, control sequence, binary sequence,
|
||
alphabet string, sigle character */
|
||
static int next_token(MzString &white, MzString &token, istream *strm)
|
||
{
|
||
register int ch = 0;
|
||
|
||
if( stk->state(strm) ) {
|
||
white = stk->white;
|
||
token = stk->token;
|
||
stk->token = 0;
|
||
stk->white = 0;
|
||
return token.length();
|
||
}
|
||
|
||
token = 0;
|
||
white = 0;
|
||
if( !strm->good() || (ch = strm->get()) == EOF )
|
||
return 0;
|
||
|
||
// read preceeding ws
|
||
if( IS_WS(ch) ) {
|
||
do white << (char) ch;
|
||
while( IS_WS(ch = strm->get()) );
|
||
}
|
||
|
||
if( ch == '\\' || ch & 0x80 || isalpha(ch) ) {
|
||
if( ch == '\\' ) {
|
||
token << (char) ch;
|
||
ch = strm->get();
|
||
}
|
||
do {
|
||
token << (char) ch;
|
||
ch = strm->get();
|
||
} while( ch != EOF && (ch & 0x80 || isalpha(ch)) ) ;
|
||
strm->putback(sal::static_int_cast<char>(ch));
|
||
/* sub, sub, over, atop Ư¼ö ó¸®
|
||
±× ÀÌÀ¯´Â next_state()¿¡ ¿µÇâÀ» ¹ÌÄ¡±â ¶§¹®ÀÌ´Ù.
|
||
*/
|
||
if( !STRICMP("sub", token) || !STRICMP("from", token) ||
|
||
!STRICMP("sup", token) || !STRICMP("to", token) ||
|
||
!STRICMP("over", token) || !STRICMP("atop", token) ||
|
||
!STRICMP("left", token) || !STRICMP("right", token) )
|
||
{
|
||
char buf[256];
|
||
make_keyword(buf, token);
|
||
token = buf;
|
||
}
|
||
if( !token.compare("sub") || !token.compare("from") )
|
||
token = "_";
|
||
if( !token.compare("sup") || !token.compare("to") )
|
||
token = "^";
|
||
}
|
||
else if( IS_BINARY(ch) ) {
|
||
do token << (char) ch;
|
||
while( IS_BINARY(ch = strm->get()) );
|
||
strm->putback(sal::static_int_cast<char>(ch));
|
||
}
|
||
else if( isdigit(ch) ) {
|
||
do token << (char) ch;
|
||
while( isdigit(ch = strm->get()) );
|
||
strm->putback(sal::static_int_cast<char>(ch));
|
||
}
|
||
else
|
||
token << (char) ch;
|
||
|
||
return token.length();
|
||
}
|
||
|
||
static int read_white_space(MzString& outs, istream *strm)
|
||
{
|
||
int result;
|
||
|
||
if( stk->state(strm) ) {
|
||
outs << stk->white;
|
||
stk->white = 0;
|
||
result = stk->token[0];
|
||
}
|
||
else {
|
||
int ch;
|
||
while( IS_WS(ch = strm->get()) )
|
||
outs << (char )ch;
|
||
strm->putback(sal::static_int_cast<char>(ch));
|
||
result = ch;
|
||
}
|
||
return result;
|
||
}
|
||
|
||
/* Àμö°¡ ÇÊ¿äÇÏÁö ¾ÊÀº °æ¿ì °¢ Ç׸ñ°£ÀÇ ±¸ºÐÀº space¿Í brace
|
||
sqrt {ab}c = sqrt{ab} c
|
||
(, }´Â grouping
|
||
^, _ ´Â ¾ÕµÚ·Î °áÇÕÇÑ´Ù.
|
||
|
||
sqrt µî°ú °°ÀÌ Àμö°¡ ÀÖ´Â Çü½Ä Á¤¸®
|
||
sqrt a -> sqrt{a}
|
||
sqrt {a} -> sqrt{a}
|
||
1 ÀÌ»óÀÇ Àμö°¡ ÀÖ´Â °æ¿ì Àμöµé°£ÀÇ ¿ª¹éÀº ¾ø¾Ø´Ù.
|
||
\frac a b -> frac{a}{b}
|
||
overÀÇ Çü½Ä Á¤¸®
|
||
a over b -> {a}over{b}
|
||
*/
|
||
|
||
static int eq_word(MzString& outs, istream *strm, int status)
|
||
{
|
||
MzString token, white, state;
|
||
int result;
|
||
char keyword[256];
|
||
hwpeq *eq;
|
||
|
||
next_token(white, token, strm);
|
||
if (token.length() <= 0)
|
||
return 0;
|
||
result = token[0];
|
||
|
||
if( token.compare("{") == 0 ) {
|
||
state << white << token;
|
||
eq_sentence(state, strm, "}");
|
||
}
|
||
else if( token.compare("left") == 0 ) {
|
||
state << white << token;
|
||
next_token(white, token, strm);
|
||
state << white << token;
|
||
|
||
eq_sentence(state, strm, "right");
|
||
|
||
next_token(white, token, strm);
|
||
state << white << token;
|
||
}
|
||
else {
|
||
/* Á¤»óÀûÀÎ token */
|
||
int script_status = SCRIPT_NONE;
|
||
while( 1 ) {
|
||
state << white << token;
|
||
make_keyword(keyword, token);
|
||
if( token[0] == '^' )
|
||
script_status |= SCRIPT_SUP;
|
||
else if( token[0] == '_' )
|
||
script_status |= SCRIPT_SUB;
|
||
else
|
||
script_status = SCRIPT_NONE;
|
||
|
||
if( 0 != (eq = lookup_eqn(keyword)) ) {
|
||
int nargs = eq->nargs;
|
||
int ch;
|
||
while( nargs-- ) {
|
||
ch = read_white_space(state, strm);
|
||
if( ch != '{' ) state << '{';
|
||
eq_word(state, strm, script_status);
|
||
if( ch != '{' ) state << '}';
|
||
}
|
||
}
|
||
|
||
if( !next_token(white, token, strm) )
|
||
break;
|
||
// end loop and restart with this
|
||
if( (token[0] == '^' && status && !(status & SCRIPT_SUP)) ||
|
||
(token[0] == '_' && status && !(status & SCRIPT_SUB)) ||
|
||
strcmp("over", token) == 0 || strcmp("atop", token) == 0 ||
|
||
strchr("{}#&`", token[0]) ||
|
||
(!strchr("^_", token[0]) && white.length()) ) {
|
||
push_token(white, token, strm);
|
||
break;
|
||
}
|
||
}
|
||
}
|
||
outs << state;
|
||
|
||
return result;
|
||
}
|
||
|
||
static bool eq_sentence(MzString& outs, istream *strm, const char *end)
|
||
{
|
||
MzString state;
|
||
MzString white, token;
|
||
bool multiline = false;
|
||
|
||
read_white_space(outs, strm);
|
||
while( eq_word(state, strm) ) {
|
||
if( !next_token(white, token, strm) ||
|
||
(end && strcmp(token.c_str(), end) == 0) )
|
||
{
|
||
state << white << token;
|
||
break;
|
||
}
|
||
push_token(white, token, strm);
|
||
if( !token.compare("atop") || !token.compare("over") )
|
||
outs << '{' << state << '}';
|
||
else {
|
||
if( !token.compare("#") )
|
||
multiline = true;
|
||
outs << state;
|
||
}
|
||
state = 0;
|
||
read_white_space(outs, strm);
|
||
}
|
||
outs << state;
|
||
return multiline;
|
||
}
|
||
|
||
static char eq2ltxconv(MzString& sstr, istream *strm, const char *sentinel)
|
||
{
|
||
MzString white, token;
|
||
char key[256];
|
||
int ch, result;
|
||
hwpeq *eq = 0;
|
||
|
||
while( 0 != (result = next_token(white, token, strm)) ) {
|
||
if( sentinel && (result == 1) && strchr(sentinel, token[0]) )
|
||
break;
|
||
make_keyword(key, token);
|
||
if( (eq = lookup_eqn(key)) != 0 ) {
|
||
if( eq->latex )
|
||
strcpy(key, eq->latex);
|
||
else {
|
||
key[0] = '\\';
|
||
strcpy(key + 1, eq->key);
|
||
}
|
||
if( (eq->flag & EQ_CASE) && isupper(token[0]) )
|
||
key[1] = sal::static_int_cast<char>(toupper(key[1]));
|
||
token = key;
|
||
}
|
||
|
||
if( token[0] == '{' ) { // grouping
|
||
sstr << white << token;
|
||
eq2ltxconv(sstr, strm, "}");
|
||
sstr << '}';
|
||
}
|
||
else if( eq && (eq->flag & EQ_ENV) ) {
|
||
next_token(white, token, strm);
|
||
if( token[0] != '{' ) return 0;
|
||
sstr << "\\begin" << "{" << eq->key << "}" << ENDL ;
|
||
eq2ltxconv(sstr, strm, "}");
|
||
if( sstr[sstr.length() - 1] != '\n' )
|
||
sstr << ENDL ;
|
||
sstr << "\\end" << "{" << eq->key << "}" << ENDL ;
|
||
}
|
||
else if( eq && (eq->flag & EQ_ATOP) ) {
|
||
if( sstr.length() == 0 )
|
||
sstr << '{';
|
||
else {
|
||
int pos = sstr.rfind('}');
|
||
if( 0 < pos)
|
||
sstr.replace(pos, ' ');
|
||
}
|
||
sstr << token;
|
||
while( (ch = strm->get()) != EOF && IS_WS(ch) )
|
||
sstr << (char)ch;
|
||
if( ch != '{' )
|
||
sstr << "{}";
|
||
else {
|
||
eq2ltxconv(sstr, strm, "}");
|
||
sstr << '}';
|
||
}
|
||
}
|
||
else
|
||
sstr << white << token;
|
||
}
|
||
return token[0];
|
||
}
|
||
|
||
void eq2latex(MzString& outs, char *s)
|
||
{
|
||
assert(s);
|
||
if( stk == 0 )
|
||
stk = new eq_stack;
|
||
|
||
MzString tstr;
|
||
|
||
istringstream tstrm(s);
|
||
bool eqnarray = eq_sentence(tstr, &tstrm);
|
||
istringstream strm(tstr.c_str());
|
||
|
||
if( eqnarray )
|
||
outs << "\\begin{array}{rllll}" << ENDL;
|
||
eq2ltxconv(outs, &strm, 0);
|
||
outs << ENDL;
|
||
if( eqnarray )
|
||
outs << "\\end{array}" << ENDL;
|
||
delete stk;
|
||
stk = 0;
|
||
}
|
||
|
||
/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
|