add environment nodes and matrices
This commit is contained in:
parent
97b60443f8
commit
d54f17fab2
4
TODO.md
4
TODO.md
|
@ -28,7 +28,7 @@
|
|||
* Parametrize character-level and word-level spacing
|
||||
* Be more generic in what nodes have display mode by default
|
||||
* Reduce horizontal spacing by using a proportional font
|
||||
* Have a decent variable-height font system in gint
|
||||
* Have a decent variable-height font system in gint (argh)
|
||||
|
||||
* Add square roots, and honor TEX_SQRT_SLANTED and TEX_SQRT_BAR_LENGTH
|
||||
* Add matrices
|
||||
* Make more matrix tests
|
||||
|
|
|
@ -73,4 +73,8 @@
|
|||
/* Length of the top-right bar of square roots (0 to disable) */
|
||||
#define TEX_SQRT_BAR_LENGTH 0
|
||||
|
||||
/* Spacing between rows and columns in matrices */
|
||||
#define TEX_MATRIX_COL_SPACING 4
|
||||
#define TEX_MATRIX_ROW_SPACING 4
|
||||
|
||||
#endif /* TEX_CONFIG */
|
||||
|
|
|
@ -30,8 +30,8 @@ struct TeX_Env
|
|||
/* add_break(): Add a break ("\\") */
|
||||
void (*add_break)(TeX_Env *env);
|
||||
|
||||
/* size(): Compute environment size */
|
||||
void (*size)(TeX_Env *env);
|
||||
/* layout(): Compute environment layout */
|
||||
void (*layout)(TeX_Env *env);
|
||||
|
||||
/* render(): Render environment */
|
||||
void (*render)(TeX_Env *env, int x, int y, int color);
|
||||
|
@ -51,8 +51,15 @@ struct TeX_Env
|
|||
/* TeX_env_primary(): make a primary, single-flow environment
|
||||
This is the environment type of whole formulas. It consists of a single
|
||||
flow and ignores separators and breaks.
|
||||
Creates and returns a new environment [env] which must be freed by a call
|
||||
to [env->free(env)]. */
|
||||
Creates and returns a new environment which must be freed by TeX_free(). */
|
||||
struct TeX_Env *TeX_env_primary(void);
|
||||
|
||||
/* TeX_env_matrix(): make a variable-size matrix
|
||||
This environment builds matrices without surrounding delimiters. Separators
|
||||
are used to separate elements, and breaks mark the end of each line. Rows of
|
||||
uneven length are all padded with empty elements to the maximum row length
|
||||
of the whole matrix.
|
||||
Returns a new environment; free with TeX_free(). */
|
||||
struct TeX_Env *TeX_env_matrix(void);
|
||||
|
||||
#endif /* TEX_ENV */
|
||||
|
|
|
@ -10,11 +10,13 @@
|
|||
#include <stddef.h>
|
||||
#include <stdint.h>
|
||||
|
||||
/* A special class number for nodes that contain plain text. Class numbers from
|
||||
1 onwards are used by TeX_Class. See also the class array in nodes.c. */
|
||||
/* A special class number for nodes that contain plain text. */
|
||||
#define TEX_NODECLASS_TEXT 0
|
||||
/* Special class for environment nodes, also a special case */
|
||||
#define TEX_NODECLASS_ENV 1
|
||||
|
||||
struct TeX_Flow;
|
||||
struct TeX_Env;
|
||||
|
||||
/* TeX_Node
|
||||
This object represents a mathematical construct. It can be plain text, a
|
||||
|
@ -28,6 +30,8 @@ struct TeX_Node
|
|||
union {
|
||||
/* Plain text content encoded as UTF-8 */
|
||||
uint8_t *text;
|
||||
/* Environment pointer */
|
||||
struct TeX_Env *env;
|
||||
/* Functional arguments */
|
||||
struct TeX_Flow *args[TEX_NODE_MAX_CHILDREN];
|
||||
};
|
||||
|
@ -75,6 +79,11 @@ struct TeX_Node *TeX_node_add_arg(struct TeX_Node *node, struct TeX_Flow *arg);
|
|||
not freed. Always returns [node]. */
|
||||
struct TeX_Node *TeX_node_absorb(struct TeX_Node *node, char const *text);
|
||||
|
||||
/* TeX_node_env(): Make a environment node
|
||||
This function creates an node that wraps an environment and inserts it into
|
||||
a formula. */
|
||||
struct TeX_Node *TeX_node_env(struct TeX_Env *env);
|
||||
|
||||
/* TeX_node_free(): Free a TeX_Node and all its children */
|
||||
void TeX_node_free(struct TeX_Node *node);
|
||||
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
//---
|
||||
// vector: Simple vectors that only grow
|
||||
// Preprocessing is a bit ugly here, but it makes it really easy to use.
|
||||
//---
|
||||
|
||||
#ifndef TEX_VECTOR
|
||||
|
@ -8,29 +9,33 @@
|
|||
#include <stdint.h>
|
||||
#include <stddef.h>
|
||||
|
||||
typedef struct
|
||||
{
|
||||
int len;
|
||||
int size;
|
||||
int elsize;
|
||||
/* Declare three variables for every vector */
|
||||
#define vector_type(type, name) \
|
||||
type * name; \
|
||||
short name ## _len; \
|
||||
short name ## _size;
|
||||
|
||||
/* This pointer can be cast to the vector type and indexed */
|
||||
void *data;
|
||||
} vector_t;
|
||||
/* Trivial initialization */
|
||||
#define vector_init(name) { \
|
||||
name = NULL; \
|
||||
name ## _len = 0; \
|
||||
name ## _size = 0; \
|
||||
}
|
||||
|
||||
/* vector_make(): Make a new vector of a given type
|
||||
@vector Pointer to preallocated vector structure
|
||||
@type Data type */
|
||||
void vector_make(vector_t *vector, size_t elsize);
|
||||
/* Extension */
|
||||
#define vector_extend(name) { \
|
||||
if(name ## _len >= name ## _size) \
|
||||
name = realloc(name, sizeof *name * \
|
||||
(name ## _size += 8)); \
|
||||
}
|
||||
|
||||
#define vector_make(v, T) vector_make(v, sizeof(T))
|
||||
/* Append */
|
||||
#define vector_append(name, value) { \
|
||||
vector_extend(name); \
|
||||
(name)[name ## _len++] = (value); \
|
||||
}
|
||||
|
||||
/* vector_append(): Append a new element to a vector
|
||||
@vector Pointer to initialized vector
|
||||
@element Pointer to new element, which will be *copied* */
|
||||
void vector_append(vector_t *v, void *element);
|
||||
|
||||
/* vector_free(): Free a vector's contents */
|
||||
void vector_free(vector_t *v);
|
||||
/* Last elements */
|
||||
#define vector_last(name) ((name)[name ## _len - 1])
|
||||
|
||||
#endif /* TEX_VECTOR */
|
||||
|
|
|
@ -51,7 +51,7 @@ void TeX_intf_text(void (*draw_text)(char const *str, int x, int y,int color))
|
|||
/* TeX_free(): Free an allocated TeX formula */
|
||||
void TeX_free(struct TeX_Env *env)
|
||||
{
|
||||
env->free(env);
|
||||
if(env) env->free(env);
|
||||
}
|
||||
|
||||
//---
|
||||
|
@ -67,7 +67,7 @@ struct TeX_Env *TeX_parse(char const *formula)
|
|||
struct TeX_Env *env = parse(formula);
|
||||
if(!env) return NULL;
|
||||
|
||||
env->size(env);
|
||||
env->layout(env);
|
||||
return env;
|
||||
}
|
||||
|
||||
|
|
33
src/TeX.y
33
src/TeX.y
|
@ -30,9 +30,8 @@ void env_push(char const *type)
|
|||
|
||||
if(!strcmp(type, "primary"))
|
||||
new_env = TeX_env_primary();
|
||||
/* TODO: Matrix environment creation
|
||||
if(!strcmp(type, "matrix"))
|
||||
new_env = TeX_env_matrix(); */
|
||||
new_env = TeX_env_matrix();
|
||||
|
||||
/* If new_env is NULL... still insert it. This is more likely to cause
|
||||
an error, and avoids asymmetry with pops */
|
||||
|
@ -82,10 +81,6 @@ struct TeX_Node *mknode_t(char const *name, char const *text)
|
|||
%token ENV_BEGIN
|
||||
%token ENV_END
|
||||
|
||||
/* Separators ("&") and breaks ("\\") */
|
||||
%token SEPARATOR
|
||||
%token BREAK
|
||||
|
||||
%left '^' '_'
|
||||
|
||||
%type <struct TeX_Flow *> flow
|
||||
|
@ -99,8 +94,8 @@ struct TeX_Node *mknode_t(char const *name, char const *text)
|
|||
env:
|
||||
%empty { }
|
||||
| env node { env->add_node(env, $2); }
|
||||
| env SEPARATOR { env->add_separator(env); }
|
||||
| env BREAK { env->add_break(env); }
|
||||
| env '&' { env->add_separator(env); }
|
||||
| env '\\' { env->add_break(env); }
|
||||
|
||||
flow:
|
||||
%empty { $$ = NULL; }
|
||||
|
@ -124,7 +119,7 @@ node_abs:
|
|||
|
||||
env_node:
|
||||
/* TODO: Add TeX_mknode_env() */
|
||||
env_begin env env_end { $$ = NULL; } //TeX_mknode_env($3); }
|
||||
env_begin env env_end { $$ = TeX_node_env($3); }
|
||||
|
||||
env_begin:
|
||||
ENV_BEGIN '{' TEXT '}' { env_push($3); }
|
||||
|
@ -191,6 +186,8 @@ static enum {
|
|||
subscript = '_',
|
||||
lbrace = '{',
|
||||
rbrace = '}',
|
||||
break_symbol = '\\',
|
||||
separator = '&',
|
||||
} state = text;
|
||||
|
||||
/* Single-character mode. When a command name, '^' or '_' is not followed by a
|
||||
|
@ -318,9 +315,17 @@ static int lexer_text(void)
|
|||
return release(TEXT);
|
||||
}
|
||||
|
||||
/* Breaks */
|
||||
if(la == '\\')
|
||||
{
|
||||
la = *lex++;
|
||||
state = '\\';
|
||||
return release(TEXT);
|
||||
}
|
||||
|
||||
/* Escaped character: accumulate lookahead and feed lexer.
|
||||
Feeding is safe because current lookahead is not EOF */
|
||||
if(strchr("\\{}^_", la))
|
||||
if(strchr("{}^_&", la))
|
||||
{
|
||||
c = la;
|
||||
la = *lex++;
|
||||
|
@ -333,7 +338,7 @@ static int lexer_text(void)
|
|||
}
|
||||
|
||||
/* Opening and closing braces are always syntactic elements */
|
||||
else if(c == '{' || c == '}')
|
||||
else if(c == '{' || c == '}' || c == '&')
|
||||
{
|
||||
state = c;
|
||||
return release(TEXT);
|
||||
|
@ -399,6 +404,12 @@ static int lexer_command(void)
|
|||
return release(COMMAND_ABS);
|
||||
}
|
||||
|
||||
/* Special environment commands */
|
||||
if(!acccmp("begin"))
|
||||
return release(ENV_BEGIN);
|
||||
if(!acccmp("end"))
|
||||
return release(ENV_END);
|
||||
|
||||
return release(COMMAND);
|
||||
}
|
||||
|
||||
|
|
|
@ -5,6 +5,7 @@
|
|||
#include <TeX/config.h>
|
||||
#include <TeX/node.h>
|
||||
#include <TeX/flow.h>
|
||||
#include <TeX/env.h>
|
||||
#include <TeX/classes.h>
|
||||
|
||||
#include <TeX/interface.h>
|
||||
|
@ -40,6 +41,24 @@ void text_render(struct TeX_Node const * node, int x, int y, int color)
|
|||
TeX_text((void *)node->text, x, y, color);
|
||||
}
|
||||
|
||||
//---
|
||||
// Environment nodes.
|
||||
//---
|
||||
|
||||
void env_layout(struct TeX_Node *node)
|
||||
{
|
||||
node->env->layout(node->env);
|
||||
|
||||
node->width = node->env->width;
|
||||
node->height = node->env->height;
|
||||
node->line = node->env->line;
|
||||
}
|
||||
|
||||
void env_render(struct TeX_Node *node, int x, int y, int color)
|
||||
{
|
||||
node->env->render(node->env, x, y, color);
|
||||
}
|
||||
|
||||
//---
|
||||
// Fractions.
|
||||
// * args: 2 (<2 invalidate, >2 ignore)
|
||||
|
@ -416,8 +435,9 @@ void lim_render(__attribute__((unused)) struct TeX_Node const * node, int x,
|
|||
//---
|
||||
|
||||
static struct TeX_Class const class_table[] = {
|
||||
/* Text has ID 0 */
|
||||
/* Text and environments */
|
||||
{ "\\text", text_layout, text_render },
|
||||
{ "\\end", env_layout, env_render },
|
||||
|
||||
/* Fractions */
|
||||
{ "frac", frac_layout, frac_render },
|
||||
|
|
246
src/env.c
246
src/env.c
|
@ -2,9 +2,20 @@
|
|||
#include <TeX/flow.h>
|
||||
#include <TeX/env.h>
|
||||
|
||||
#include <TeX/vector.h>
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
#define fill_prototype(env, prefix) { \
|
||||
env->free = prefix ## _free; \
|
||||
env->add_node = prefix ## _add_node; \
|
||||
env->add_separator = prefix ## _add_separator; \
|
||||
env->add_break = prefix ## _add_break; \
|
||||
env->layout = prefix ## _layout; \
|
||||
env->render = prefix ## _render; \
|
||||
}
|
||||
|
||||
//---
|
||||
// Primary environment: a simple flow
|
||||
//
|
||||
|
@ -24,6 +35,7 @@ static void primary_free(struct TeX_Env *env)
|
|||
{
|
||||
struct TeX_Env_Primary *p = (void *)env;
|
||||
TeX_flow_free(p->flow);
|
||||
free(env);
|
||||
}
|
||||
|
||||
static void primary_add_node(struct TeX_Env *env, struct TeX_Node *node)
|
||||
|
@ -32,14 +44,22 @@ static void primary_add_node(struct TeX_Env *env, struct TeX_Node *node)
|
|||
p->flow = TeX_flow_add_node(p->flow, node);
|
||||
}
|
||||
|
||||
static void primary_size(struct TeX_Env *env)
|
||||
static void primary_add_separator(__attribute__((unused)) struct TeX_Env *env)
|
||||
{
|
||||
}
|
||||
|
||||
static void primary_add_break(__attribute__((unused)) struct TeX_Env *env)
|
||||
{
|
||||
}
|
||||
|
||||
static void primary_layout(struct TeX_Env *env)
|
||||
{
|
||||
struct TeX_Env_Primary *p = (void *)env;
|
||||
TeX_flow_layout(p->flow);
|
||||
|
||||
p->env.width = p->flow->width;
|
||||
p->env.height = p->flow->height;
|
||||
p->env.line = p->flow->line;
|
||||
env->width = p->flow->width;
|
||||
env->height = p->flow->height;
|
||||
env->line = p->flow->line;
|
||||
}
|
||||
|
||||
static void primary_render(struct TeX_Env *env, int x, int y, int color)
|
||||
|
@ -54,12 +74,7 @@ struct TeX_Env *TeX_env_primary(void)
|
|||
struct TeX_Env *env = (void *)p;
|
||||
|
||||
env->name = "primary";
|
||||
env->free = primary_free;
|
||||
env->add_node = primary_add_node;
|
||||
env->add_separator = NULL;
|
||||
env->add_break = NULL;
|
||||
env->size = primary_size;
|
||||
env->render = primary_render;
|
||||
fill_prototype(env, primary);
|
||||
|
||||
p->flow = NULL;
|
||||
|
||||
|
@ -70,7 +85,175 @@ struct TeX_Env *TeX_env_primary(void)
|
|||
// Matrix environment.
|
||||
//---
|
||||
|
||||
/* TODO */
|
||||
struct TeX_Env_Matrix
|
||||
{
|
||||
struct TeX_Env env;
|
||||
|
||||
vector_type(struct TeX_Flow *, elements);
|
||||
vector_type(int, rowstart);
|
||||
|
||||
int *rowdepth;
|
||||
int *rowline;
|
||||
int *colwidth;
|
||||
|
||||
int rows;
|
||||
int cols;
|
||||
};
|
||||
|
||||
static void matrix_free(struct TeX_Env *env)
|
||||
{
|
||||
struct TeX_Env_Matrix *m = (void *)env;
|
||||
|
||||
free(m->elements);
|
||||
free(m->rowstart);
|
||||
free(m->rowdepth);
|
||||
free(m->rowline);
|
||||
free(m->colwidth);
|
||||
|
||||
free(env);
|
||||
}
|
||||
|
||||
static void matrix_add_node(struct TeX_Env *env, struct TeX_Node *node)
|
||||
{
|
||||
struct TeX_Env_Matrix *m = (void *)env;
|
||||
|
||||
int last = m->elements_len - 1;
|
||||
m->elements[last] = TeX_flow_add_node(m->elements[last], node);
|
||||
}
|
||||
|
||||
static void matrix_add_separator(struct TeX_Env *env)
|
||||
{
|
||||
struct TeX_Env_Matrix *m = (void *)env;
|
||||
|
||||
/* Create a new flow at the end of the element array */
|
||||
vector_append(m->elements, NULL);
|
||||
|
||||
/* Current row length is automatically increased. Set column count */
|
||||
int row_length = m->elements_len - m->rowstart[m->rows - 1];
|
||||
m->cols = max(m->cols, row_length);
|
||||
}
|
||||
|
||||
static void matrix_add_break(struct TeX_Env *env)
|
||||
{
|
||||
struct TeX_Env_Matrix *m = (void *)env;
|
||||
|
||||
/* First add a new flow */
|
||||
vector_append(m->elements, NULL);
|
||||
|
||||
/* Then add a row and its start index */
|
||||
vector_append(m->rowstart, m->elements_len - 1);
|
||||
m->rows++;
|
||||
}
|
||||
|
||||
static void matrix_layout(struct TeX_Env *env)
|
||||
{
|
||||
struct TeX_Env_Matrix *m = (void *)env;
|
||||
|
||||
int row = 0;
|
||||
int col = 0;
|
||||
|
||||
env->width = 0;
|
||||
env->height = 0;
|
||||
env->line = 0;
|
||||
|
||||
m->rowdepth = calloc(m->rows, sizeof *m->rowdepth);
|
||||
m->rowline = calloc(m->rows, sizeof *m->rowline);
|
||||
m->colwidth = calloc(m->cols, sizeof *m->colwidth);
|
||||
if(!m->rowdepth || !m->rowline || !m->colwidth) return;
|
||||
|
||||
/* Compute the layout of the grid */
|
||||
for(int i = 0; i < m->elements_len; i++)
|
||||
{
|
||||
if(row + 1 < m->rows && i == m->rowstart[row + 1])
|
||||
{
|
||||
col = 0;
|
||||
row++;
|
||||
}
|
||||
|
||||
struct TeX_Flow *f = m->elements[i];
|
||||
TeX_flow_layout(f);
|
||||
|
||||
/* Update the current row and column */
|
||||
m->rowline[row] = max(m->rowline[row], f->line);
|
||||
m->rowdepth[row] = max(m->rowdepth[row], f->height - f->line);
|
||||
m->colwidth[col] = max(m->colwidth[col], f->width);
|
||||
|
||||
col++;
|
||||
}
|
||||
|
||||
/* TODO: Add width spacing and height spacing */
|
||||
|
||||
for(int i = 0; i < m->rows; i++)
|
||||
{
|
||||
env->height += m->rowline[i] + m->rowdepth[i];
|
||||
}
|
||||
for(int j = 0; j < m->cols; j++)
|
||||
{
|
||||
env->width += m->colwidth[j];
|
||||
}
|
||||
|
||||
env->width += TEX_MATRIX_COL_SPACING * (m->cols - 1);
|
||||
env->height += TEX_MATRIX_ROW_SPACING * (m->rows - 1);
|
||||
env->line = env->height >> 1;
|
||||
}
|
||||
|
||||
static void matrix_render(struct TeX_Env *env, int x, int y, int color)
|
||||
{
|
||||
struct TeX_Env_Matrix *m = (void *)env;
|
||||
|
||||
int n = 0, dy = 0;
|
||||
|
||||
for(int row = 0; row < m->rows; row++)
|
||||
{
|
||||
int col = 0, dx = 0;
|
||||
|
||||
while((row + 1 < m->rows && n < m->rowstart[row + 1]) ||
|
||||
(row + 1 >= m->rows && n < m->elements_len))
|
||||
{
|
||||
struct TeX_Flow *flow = m->elements[n++];
|
||||
int cw = m->colwidth[col];
|
||||
int rh = m->rowline[row] + m->rowdepth[row];
|
||||
|
||||
TeX_flow_render(flow,
|
||||
x + dx + ((cw - flow->width) >> 1),
|
||||
y + dy + ((rh - flow->height) >> 1),
|
||||
color);
|
||||
|
||||
dx += cw + TEX_MATRIX_COL_SPACING;
|
||||
col++;
|
||||
}
|
||||
|
||||
dy += m->rowline[row]+m->rowdepth[row]+TEX_MATRIX_ROW_SPACING;
|
||||
}
|
||||
}
|
||||
|
||||
struct TeX_Env *TeX_env_matrix(void)
|
||||
{
|
||||
struct TeX_Env_Matrix *m = malloc(sizeof *m);
|
||||
struct TeX_Env *env = (void *)m;
|
||||
|
||||
env->name = "matrix";
|
||||
fill_prototype(env, matrix);
|
||||
|
||||
vector_init(m->elements);
|
||||
vector_init(m->rowstart);
|
||||
m->rowdepth = NULL;
|
||||
m->rowline = NULL;
|
||||
m->colwidth = NULL;
|
||||
|
||||
vector_extend(m->elements);
|
||||
m->elements[0] = NULL;
|
||||
m->elements_len = 1;
|
||||
|
||||
vector_extend(m->rowstart);
|
||||
m->rowstart[0] = 0;
|
||||
m->rowstart_len = 1;
|
||||
|
||||
m->rows = 1;
|
||||
m->cols = 0;
|
||||
|
||||
return env;
|
||||
}
|
||||
|
||||
//---
|
||||
// Environment printers
|
||||
|
@ -86,10 +269,39 @@ void TeX_print_env_primary(struct TeX_Env *env, int indent)
|
|||
{
|
||||
struct TeX_Env_Primary *p = (void *)env;
|
||||
|
||||
printf("%*s", indent, "");
|
||||
printf("{primary}\n");
|
||||
printf("%*senv:primary", indent, "");
|
||||
printf(GRAY " %dx%d,%d" END "\n", env->width, env->height, env->line);
|
||||
|
||||
TeX_print_flow(p->flow, indent + 2);
|
||||
TeX_print_flow(p->flow, indent + 4);
|
||||
}
|
||||
|
||||
/* TeX_print_env_matrix(): Print a matrix environment to stdout */
|
||||
void TeX_print_env_matrix(struct TeX_Env *env, int indent)
|
||||
{
|
||||
struct TeX_Env_Matrix *m = (void *)env;
|
||||
|
||||
printf("%*senv:matrix %dx%d", indent, "", m->rows, m->cols);
|
||||
printf(GRAY " %dx%d,%d", env->width, env->height, env->line);
|
||||
|
||||
for(int i = 0; i < m->cols; i++)
|
||||
{
|
||||
printf("%c%d", (i ? ';' : ' '), m->colwidth[i]);
|
||||
}
|
||||
printf(END "\n");
|
||||
|
||||
int row = 0;
|
||||
for(int i = 0; i < m->elements_len; i++)
|
||||
{
|
||||
if(row < m->rows && i == m->rowstart[row])
|
||||
{
|
||||
printf("%*s%d: " GRAY "%d,%d" END "\n", indent + 4, "",
|
||||
row, m->rowline[row] + m->rowdepth[row],
|
||||
m->rowline[row]);
|
||||
row++;
|
||||
}
|
||||
|
||||
TeX_print_flow(m->elements[i], indent + 8);
|
||||
}
|
||||
}
|
||||
|
||||
/* TeX_print_env(): Recursively print an environment */
|
||||
|
@ -99,9 +311,13 @@ void TeX_print_env(struct TeX_Env *env, int indent)
|
|||
{
|
||||
TeX_print_env_primary(env, indent);
|
||||
}
|
||||
else if(!strcmp(env->name, "matrix"))
|
||||
{
|
||||
TeX_print_env_matrix(env, indent);
|
||||
}
|
||||
else
|
||||
{
|
||||
printf("%*s{%s} (?)\n", indent, "", env->name);
|
||||
printf("%*senv:%s (?)\n", indent, "", env->name);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
33
src/node.c
33
src/node.c
|
@ -1,6 +1,7 @@
|
|||
#include <TeX/config.h>
|
||||
#include <TeX/node.h>
|
||||
#include <TeX/flow.h>
|
||||
#include <TeX/env.h>
|
||||
#include <TeX/classes.h>
|
||||
|
||||
#include <stdlib.h>
|
||||
|
@ -10,6 +11,10 @@
|
|||
// Node creation and destruction functions
|
||||
//---
|
||||
|
||||
#define special(node) \
|
||||
((node)->type == TEX_NODECLASS_TEXT || \
|
||||
(node)->type == TEX_NODECLASS_ENV)
|
||||
|
||||
/* TeX_node_text(): Make a text node */
|
||||
struct TeX_Node *TeX_node_text(char const *utf8)
|
||||
{
|
||||
|
@ -45,8 +50,8 @@ struct TeX_Node *TeX_node_add_arg(struct TeX_Node *node, struct TeX_Flow *arg)
|
|||
{
|
||||
if(!node || !arg) return node;
|
||||
|
||||
/* Drop the argument if it's for a plain text node */
|
||||
if(node->type == TEX_NODECLASS_TEXT)
|
||||
/* Drop the argument if it's for a plain text or environment node */
|
||||
if(special(node))
|
||||
{
|
||||
TeX_flow_free(arg);
|
||||
return node;
|
||||
|
@ -77,12 +82,27 @@ struct TeX_Node *TeX_node_absorb(struct TeX_Node *node, char const *text)
|
|||
TeX_node_text(text)));
|
||||
}
|
||||
|
||||
/* TeX_node_env(): Make a environment node */
|
||||
struct TeX_Node *TeX_node_env(struct TeX_Env *env)
|
||||
{
|
||||
struct TeX_Node *node = calloc(1, sizeof *node);
|
||||
if(!node) return NULL;
|
||||
|
||||
node->env = env;
|
||||
node->type = TEX_NODECLASS_ENV;
|
||||
|
||||
return node;
|
||||
}
|
||||
|
||||
/* TeX_node_free(): Free a TeX_Node and all its children */
|
||||
void TeX_node_free(struct TeX_Node *node)
|
||||
{
|
||||
/* Text nodes: free the allocated string */
|
||||
if(node->type == TEX_NODECLASS_TEXT) free(node->text);
|
||||
|
||||
/* Environment nodes: free the environment */
|
||||
else if(node->type == TEX_NODECLASS_ENV) node->env->free(node->env);
|
||||
|
||||
/* Class nodes: recursively free children */
|
||||
else for(int i = 0; i < TEX_NODE_MAX_CHILDREN; i++)
|
||||
{
|
||||
|
@ -102,7 +122,7 @@ void TeX_node_free(struct TeX_Node *node)
|
|||
void TeX_node_layout(struct TeX_Node *node)
|
||||
{
|
||||
/* First compute the layout of the children */
|
||||
if(node->type != TEX_NODECLASS_TEXT)
|
||||
if(!special(node))
|
||||
for(int i = 0; i < TEX_NODE_MAX_CHILDREN && node->args[i]; i++)
|
||||
TeX_flow_layout(node->args[i]);
|
||||
|
||||
|
@ -141,6 +161,13 @@ void TeX_print_node(struct TeX_Node *node, int indent)
|
|||
printf(GRAY " %dx%d,%d %+d%+d" END "\n", node->width,
|
||||
node->height, node->line, node->x, node->l);
|
||||
}
|
||||
else if(node->type == TEX_NODECLASS_ENV)
|
||||
{
|
||||
printf("\\env" GRAY " %dx%d,%d %+d%+d" END "\n", node->width,
|
||||
node->height, node->line, node->x, node->l);
|
||||
|
||||
TeX_print_env(node->env, indent + 4);
|
||||
}
|
||||
else
|
||||
{
|
||||
printf("<%s>", TeX_class_of(node)->name);
|
||||
|
|
|
@ -169,7 +169,11 @@ int main(void)
|
|||
char const * formula =
|
||||
"\\frac{x^7\\left[X,Y\\right]+3\\left|\\frac{A}{B}\\right>}"
|
||||
"{\\left\\{\\frac{a_k+b_k}{k!}\\right\\}^5}"
|
||||
" + \\int_a^b\\frac{\\left(b-t\\right)^{n+1}}{n!}dt";
|
||||
" + \\int_a^b\\frac{\\left(b-t\\right)^{n+1}}{n!}dt"
|
||||
" + \\left(\\begin{matrix}"
|
||||
"\\frac{1}{2}&5\\\\"
|
||||
"-1&a+b"
|
||||
"\\end{matrix}\\right)";
|
||||
|
||||
struct TeX_Env *env = TeX_parse(formula);
|
||||
if(!env) { puts("parsing error!"); return 1; }
|
||||
|
|
34
src/vector.c
34
src/vector.c
|
@ -1,34 +0,0 @@
|
|||
#include <TeX/vector.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
#undef vector_make
|
||||
|
||||
/* vector_make(): Make a new vector of a given type */
|
||||
void vector_make(vector_t *v, size_t elsize)
|
||||
{
|
||||
v->len = 0;
|
||||
v->size = 0;
|
||||
v->elsize = elsize;
|
||||
v->data = NULL;
|
||||
}
|
||||
|
||||
/* vector_append(): Append a new element to a vector */
|
||||
void vector_append(vector_t *v, void *element)
|
||||
{
|
||||
/* Realloc whenever the vector runs out of space */
|
||||
if(v->len >= v->size)
|
||||
{
|
||||
v->data = realloc(v->data, (v->size + 8) * v->elsize);
|
||||
v->size += 8;
|
||||
}
|
||||
|
||||
memcpy(v->data + v->len * v->elsize, element, v->elsize);
|
||||
v->len++;
|
||||
}
|
||||
|
||||
/* vector_free(): Free a vector's contents */
|
||||
void vector_free(vector_t *v)
|
||||
{
|
||||
free(v->data);
|
||||
}
|
Loading…
Reference in New Issue