with open('example.tex') as f:
    data = f.read()

"""
Explanation: Converting $\LaTeX$ to <span style="font-variant:small-caps;">Html</span>
The purpose of the following exercise is to implement a translator from $\LaTeX$ to 
MathML.  $\LaTeX$ is a document markup language
that is especially well suited to present text that contains mathematical formulas.  MathML is the part of <span style="font-variant:small-caps;">Html</span> that deals with the representation of mathematical formulas.  As $\LaTeX$ provides a very rich
document markup language and we can only afford to spend a few hours on this exercise, we confine
ourselves to a small subset of $\LaTeX$.  The file example.tex contains some $\LaTeX$.  The goal of this exercise is to implement a translator that is able to transform this file into MathML.
We start with reading the file.
End of explanation
"""


print(data)

"""
Explanation: Now the variable data contains the text that is stored in this file.
End of explanation
"""


!start example.pdf

"""
Explanation: $$ c = \sqrt{a^{2}+b^{2}} $$
Let us look at the output file example.pdf that is produced if we run $\LaTeX$ on this file. 
Depending on your operating system, you might have to exchange the command start for another command
that is able to open the file example.pdf.
End of explanation
"""


outfile = open('example.html', 'w')

"""
Explanation: Next, we open the file example.html.  The scanner we are going to implement has to write its output into this file.
End of explanation
"""


def start_html():
    outfile.write('<!doctype html>\n')
    outfile.write('<html>\n')
    outfile.write('<head>\n')
    outfile.write('<script type="text/javascript" ')
    outfile.write('src="https://cdnjs.cloudflare.com/ajax/libs/mathjax/2.7.1/MathJax.js?config=TeX-AMS-MML_HTMLorMML">\n')
    outfile.write('</script>\n')
    outfile.write('</head>\n\n')
    outfile.write('<body>\n\n')

"""
Explanation: <hr style="height:4px;background-color:blue">
Below are some predefined functions that you can use to create the <span style="font-variant:small-caps;">Html</span> file.
<hr style="height:4px;background-color:blue">

The function start_html writes the header of the <span style="font-variant:small-caps;">Html</span> file
and the opening &lt;body&gt; tag to the file opened above.
End of explanation
"""


def end_html():
    outfile.write('</body>\n')
    outfile.write('</html>\n')

"""
Explanation: The function end_html writes the closing &lt;/body&gt; and &lt;/html&gt; tags.
End of explanation
"""


def start_math_block():
    outfile.write('<math xmlns="http://www.w3.org/1998/Math/MathML" display="block">\n')

"""
Explanation: The function start_math_block starts a math block.  This is useful for formulas enclosed in $$.  This type of formulas is displayed in a line by itself.
End of explanation
"""


def start_math_inline():
    outfile.write('<math xmlns="http://www.w3.org/1998/Math/MathML" display="inline">\n')

"""
Explanation: The function start_math_inline starts an <em style="color:blue">inline formula</em>, i.e. a formula enclosed in $.  Formulas of this type are part of the surrounding text.
End of explanation
"""


def end_math():
    outfile.write('</math>\n')

"""
Explanation: The function end_math ends a math block.
End of explanation
"""


def start_sum():
    outfile.write('<munderover>\n')
    outfile.write('<mo>&sum;</mo>\n')

def end_sum():
    outfile.write('</munderover>\n')

"""
Explanation: The functions start_sum and end_sum write code to display formulas involving sums.  For example, to display  the expression
$$ \sum\limits_{i=1}^n i^2 $$
we can use the following MathML:
&lt;munderover&gt;
&lt;mo&gt;&amp;sum;&lt;/mo&gt;
&lt;mrow&gt;
&lt;mi&gt;i&lt;/mi&gt;
&lt;mo&gt;=&lt;/mo&gt;
&lt;mn&gt;1&lt;/mn&gt;
&lt;/mrow&gt;
&lt;mrow&gt;
&lt;mi&gt;n&lt;/mi&gt;
&lt;/mrow&gt;
&lt;/munderover&gt;
&lt;msup&gt;
&lt;mi&gt;i&lt;/mi&gt;
&lt;mrow&gt;
&lt;mn&gt;2&lt;/mn&gt;
&lt;/mrow&gt;
&lt;/msup&gt;
End of explanation
"""


def start_sqrt():
    outfile.write('<msqrt>\n')

def end_sqrt():
    outfile.write('</msqrt>\n')

"""
Explanation: The functions start_sqrt and end_sqrt write code to display formulas involving square roots.  For example, to display  the expression
$$ \sqrt{a^2 + b^2} $$
we can use the following MathML:
&lt;msqrt&gt;
&lt;mrow&gt;
&lt;msup&gt;
&lt;mi&gt;a&lt;/mi&gt;
&lt;mrow&gt;
&lt;mn&gt;2&lt;/mn&gt;
&lt;/mrow&gt;
&lt;/msup&gt;
&lt;mo&gt;+&lt;/mo&gt;
&lt;msup&gt;
&lt;mi&gt;b&lt;/mi&gt;
&lt;mrow&gt;
&lt;mn&gt;2&lt;/mn&gt;
&lt;/mrow&gt;
&lt;/msup&gt;
&lt;/mrow&gt;
&lt;/msqrt&gt;
End of explanation
"""


def start_super():
    outfile.write('<msup>\n')

def end_super():
    outfile.write('</msup>\n')

"""
Explanation: In order to write exponents we have to use the tag &lt;msup&gt;.  For example, the expression $a^2$ 
is equivalent to the following markup:
&lt;msup&gt;
&lt;mi&gt;a&lt;/mi&gt;
&lt;mrow&gt;
&lt;mn&gt;2&lt;/mn&gt;
&lt;/mrow&gt;
&lt;/msup&gt;
Note that the exponent is enclosed in &lt;mrow&gt; &lt;/mrow&gt; tags.
<b>Note</b> that everything, i.e. both the variable and the exponent is enclosed in &lt;msup&gt; &lt;/msup&gt; tags.
End of explanation
"""


def start_fraction():
    outfile.write('<mfrac>\n')

def end_fraction():
    outfile.write('</mfrac>\n')

"""
Explanation: In order to write fractions we have to use the tag &lt;mfrac&gt;.  For example, the expression $\frac{1}{6}$ 
is equivalent to the following markup:
&lt;mfrac&gt;
&lt;mrow&gt;
&lt;mn&gt;1&lt;/mn&gt;
&lt;/mrow&gt;
&lt;mrow&gt;
&lt;mn&gt;6&lt;/mn&gt;
&lt;/mrow&gt;
&lt;/mfrac&gt;
Note that both nominator and denominator are enclosed in &lt;mrow&gt; &lt;/mrow&gt; tags.
End of explanation
"""


def start_row():
    outfile.write('<mrow>\n')

def end_row():
    outfile.write('</mrow>\n')

"""
Explanation: Arguments of functions like the square root or exponents have to be enclosed in pairs of &lt;mrow&gt; and &lt;/mrow&gt; tags.
End of explanation
"""


def write_var(v):
    outfile.write('<mi>' + v + '</mi>\n')

"""
Explanation: Variable names should be enclosed in pairs of &lt;mi&gt; and &lt;/mi&gt; tags.  For example, the variable $x$ is displayed by the following MathML:
&lt;mi&gt;x&lt;/mi&gt;
The tag name mi is short for math italics.
End of explanation
"""


def write_number(n):
    outfile.write('<mn>' + n + '</mn>\n')

"""
Explanation: Numbers should be enclosed in pairs of &lt;mn&gt; and &lt;/mn&gt; tags.  For example, the number $6$ is displayed by the following MathML:
&lt;mn&gt;6&lt;/mn&gt;
End of explanation
"""


def write_times():
    outfile.write('<mo>&sdot;</mo>\n')

"""
Explanation: The symbol $\cdot$ is created by the following MathML:
&lt;mo&gt;&amp;sdot;&lt;/mo&gt;
End of explanation
"""


def write_operator(op):
    outfile.write('<mo>' + op + '</mo>\n')

"""
Explanation: Mathematical operators should be enclosed in pairs of &lt;mo&gt; and &lt;/mo&gt; tags.  For example, the operator $+$ is displayed by the following MathML:
&lt;mo&gt;+&lt;/mo&gt;
End of explanation
"""


def write_pi():
    outfile.write('<mn>&pi;</mn>\n')

"""
Explanation: The symbol $\pi$ is created by the following MathML:
&lt;mn&gt;&amp;pi;&lt;/mn&gt;
End of explanation
"""


def write_leq():
    outfile.write('<mo>&le;</mo>\n')

"""
Explanation: The symbol $\leq$ is created by the following MathML:
&lt;mn&gt;&amp;le;&lt;/mn&gt;
End of explanation
"""


def write_geq():
    outfile.write('<mo>&ge;</mo>\n')

"""
Explanation: The symbol $\geq$ is created by the following MathML:
&lt;mn&gt;&amp;ge;&lt;/mn&gt;
End of explanation
"""


def write_any(char):
    outfile.write(char)

"""
Explanation: The function write_any writes a single character unadorned to the output file.
End of explanation
"""


import ply.lex as lex

"""
Explanation: We will be use the library ply to translate $\LaTeX$ into 
<span style="font-variant:small-caps;">MathML</span>.
We only use the scanner that is provided by the module ply.lex. 
Hence we import the module ply.lex that contains the scanner generator from ply.
End of explanation
"""


tokens = [ 'HEAD',            # r'\\documentclass\{article\}'
           'BEGIN_DOCUMENT',  # r'\\begin\{document\}'
           'END_DOCUMENT',    # r'\\end\{document\}'
           'DOLLAR_DOLLAR',   # r'\$\$'
           'DOLLAR',          # r'\$'
           '...' # many more token declarations here
           'ANY',             # r'.|\n'
           'WS'               # r'[ \t]'
         ]

"""
Explanation: We have to declare all tokens below.  We will need tokens for the following parts of the $\LaTeX$ file:
 - The $\LaTeX$ file starts with the string \documentclass{article}.
 - Next, there is the string \begin{document} that starts the content.
 - The string &#92;end{document} ends the content.
 - The string $$ starts and ends a formula that is displayed on a line by itself.
 - The string $ starts and ends a formula that is displayed as part of the text.
 - The string \sum\limits_{ starts the definition of a sum.
 - The string \sqrt{ starts the definition of a square root.
 - The string \frac{ starts the definition of a fraction.
 - A variable taken to a power starts something like a^{.
 - $\vdots$
End of explanation
"""


states = [ ('formula', 'exclusive') ]

def t_HEAD(t):
    r'\\documentclass\{article\}'
    pass

def t_BEGIN_DOCUMENT(t):
    r'\\begin\{document\}'
    start_html()

def t_END_DOCUMENT(t):
    r'\\end\{document\}'
    end_html()

def t_DOLLAR_DOLLAR(t):
    r'\$\$'
    t.lexer.begin('formula')
    t.lexer.stack = []
    t.lexer.stack.append('INITIAL')
    start_math_block()

def t_DOLLAR(t):
    r'\$'
    t.lexer.begin('formula')
    t.lexer.stack = []
    t.lexer.stack.append('INITIAL')
    start_math_inline()

def t_ANY(t):
    r'.|\n'
    write_any(t.value)

def t_formula_DOLLAR_DOLLAR(t):
    r'\$\$'
    t.lexer.begin('INITIAL')
    end_math()

def t_formula_DOLLAR(t):
    r'\$'
    t.lexer.begin('INITIAL')
    end_math()

"""
Explanation: When we see a closing brace } things get difficult.  The reason is that we need to know what type of formula is being closed.
Is it a square root, the subscript of a sum, the superscript of a sum, or some part of a fraction.  My idea is to use a stack that is attached to the lexer, i.e. we have a variable lexer.stack that stores this information.
Furthermore, the scanner has two different states.  Either we are inside a formula, i.e. inside something that is enclosed in dollar symbols, or we are inside text that needs to be echoed unchanged to the output file.
End of explanation
"""


def formula_LEQ(t):
    r'\\leq'
    write_leq()

def t_formula_GEQ(t):
    r'\\geq'
    write_geq()    

def t_formula_PI(t):
    r'\\pi'
    write_pi()

def t_formula_OPERATOR(t):
    r'[.,()+<>=-]'
    write_operator(t.value)

def t_formula_WS(t):
    r'[ \t]'
    pass

def t_formula_error(t):
    print(f"Illegal character in state 'formula': '{t.value[0]}'")
    t.lexer.skip(1)

"""
Explanation: $\cdots$ lots of token definitions $\cdots$
End of explanation
"""


__file__ = 'main'

"""
Explanation: The line below is necessary to trick ply.lex into assuming this program is written in an ordinary python file instead of a Jupyter notebook.
End of explanation
"""


lexer = lex.lex(debug=True)

"""
Explanation: The line below generates the scanner.
End of explanation
"""


lexer.input(data)

"""
Explanation: Next, we feed our input string into the generated scanner.
End of explanation
"""


def scan(lexer):
    for t in lexer:
        pass

scan(lexer)

outfile.close()

"""
Explanation: In order to scan the data that we provided in the last line, we iterate over all tokens generated by our scanner.
End of explanation
"""


!start 'example.html'

"""
Explanation: Now you should be able to see a file with the name example.html in your current durectory.
End of explanation
"""


