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 data contains the text that is stored in this file.
End of explanation
"""


!open example.pdf

"""
Explanation: Let us look at the output file example.pdf that is produced if we run $\LaTeX$ on this file. 
If you are nor running <span style="font-variant:small-caps;">MacOS</span> you have to replace the command
open with the name of an executable that can open a .pdf-file.
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="http://cdn.mathjax.org/mathjax/latest/MathJax.js?config=TeX-AMS-MML_HTMLorMML">\n')
    outfile.write('</script>\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 start_math_block 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:
```
<munderover>
<mo>&sum;</mo>
<mrow>
<mi>i</mi>
<mo>=</mo>
<mn>1</mn>
</mrow>
<mrow>
<mi>n</mi>
</mrow>
</munderover>
<msup>
<mi>i</mi>
<mrow>
<mn>2</mn>
</mrow>
</msup>
```
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.
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;
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\}'
           'your token definitions here, lots of them'
         ]

"""
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):
    "your code here"

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):
    "your code here"

"""
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, some part of a fraction, or an exponent.  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.  We need a stack since formulas might be nested.
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 t_formula_error(t):
    print(f"Illegal character in state 'formula': '{t.value[0]}'")
    t.lexer.skip(1)

"""
Explanation: ... lots of token definitions here ...
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()

!open 'example.html'

"""
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
"""


