123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297 |
- %{
- #ifdef HAVE_CONFIG_H
- # include <config.h>
- #endif
- #include <stdio.h>
- #include <stdlib.h>
- #include <string.h>
- #define MAXLINE 1000
- #define INDENT_STRING " "
- #define PAPER_WIDTH 74
- int indent=0;
- int line=1;
- char *last_label=NULL;
- extern int yylex(void);
- extern char *yytext;
- extern void yyerror(const char *x);
- extern char *get_label(const char *label);
- extern void set_label(const char *label, const char *target);
- char *new_counter(const char *key);
- %}
- %union {
- int def;
- char *string;
- }
- %token NEW_COUNTER LABEL HASH CHAR NEWLINE NO_INDENT RIGHT
- %type <string> stuff text
- %start doc
- %%
- doc:
- | doc NEWLINE {
- printf("\n");
- ++line;
- }
- | doc stuff NEWLINE {
- if (strlen($2) > (PAPER_WIDTH-(indent ? strlen(INDENT_STRING):0))) {
- yyerror("line too long");
- }
- printf("%s%s\n", indent ? INDENT_STRING:"", $2);
- free($2);
- indent = 1;
- ++line;
- }
- | doc stuff RIGHT stuff NEWLINE {
- char fixed[PAPER_WIDTH+1];
- int len;
- len = PAPER_WIDTH-(strlen($2)+strlen($4));
- if (len >= 0) {
- memset(fixed, ' ', len);
- fixed[len] = '\0';
- } else {
- yyerror("line too wide");
- fixed[0] = '\0';
- }
- printf("%s%s%s\n", $2, fixed, $4);
- free($2);
- free($4);
- indent = 1;
- ++line;
- }
- | doc stuff RIGHT stuff RIGHT stuff NEWLINE {
- char fixed[PAPER_WIDTH+1];
- int len, l;
- len = PAPER_WIDTH-(strlen($2)+strlen($4));
- if (len < 0) {
- len = 0;
- yyerror("line too wide");
- }
- l = len/2;
- memset(fixed, ' ', l);
- fixed[l] = '\0';
- printf("%s%s%s", $2, fixed, $4);
- free($2);
- free($4);
- l = (len+1)/2;
- memset(fixed, ' ', l);
- fixed[l] = '\0';
- printf("%s%s\n", fixed, $6);
- free($6);
- indent = 1;
- ++line;
- }
- | doc stuff RIGHT stuff RIGHT stuff NEWLINE {
- char fixed[PAPER_WIDTH+1];
- int len, l;
- len = PAPER_WIDTH-(strlen($2)+strlen($4));
- if (len < 0) {
- len = 0;
- yyerror("line too wide");
- }
- l = len/2;
- memset(fixed, ' ', l);
- fixed[l] = '\0';
- printf("%s%s%s", $2, fixed, $4);
- free($2);
- free($4);
- l = (len+1)/2;
- memset(fixed, ' ', l);
- fixed[l] = '\0';
- printf("%s%s\n", fixed, $6);
- free($6);
- indent = 1;
- ++line;
- }
- ;
- stuff: {
- $$ = strdup("");
- }
- | stuff text {
- $$ = malloc(strlen($1)+strlen($2)+1);
- sprintf($$,"%s%s", $1, $2);
- free($1);
- free($2);
- }
- ;
- text: CHAR {
- $$ = strdup(yytext);
- }
- | text CHAR {
- $$ = malloc(strlen($1)+2);
- sprintf($$,"%s%s", $1, yytext);
- free($1);
- }
- | NO_INDENT {
- $$ = strdup("");
- indent = 0;
- }
- | HASH {
- $$ = strdup("#");
- }
- | LABEL {
- if (($$ = get_label(yytext)) == NULL) {
- set_label(yytext, last_label);
- $$ = strdup("");
- }
- }
- | NEW_COUNTER {
- $$ = new_counter(yytext);
- }
- ;
- %%
- typedef struct node_s {
- struct node_s *left, *right;
- const char *key;
- char *value;
- } *node_t;
- node_t label_root = NULL;
- node_t counter_root = NULL;
- static const char *find_key(node_t root, const char *key)
- {
- while (root) {
- int cmp = strcmp(key, root->key);
- if (cmp > 0) {
- root = root->right;
- } else if (cmp) {
- root = root->left;
- } else {
- return root->value;
- }
- }
- return NULL;
- }
- static node_t set_key(node_t root, const char *key, const char *value)
- {
- if (root) {
- int cmp = strcmp(key, root->key);
- if (cmp > 0) {
- root->right = set_key(root->right, key, value);
- } else if (cmp) {
- root->left = set_key(root->left, key, value);
- } else {
- free(root->value);
- root->value = strdup(value);
- }
- } else {
- root = malloc(sizeof(struct node_s));
- root->right = root->left = NULL;
- root->key = strdup(key);
- root->value = strdup(value);
- }
- return root;
- }
- void yyerror(const char *x)
- {
- fprintf(stderr, "line %d: %s\n", line, x);
- }
- char *get_label(const char *label)
- {
- const char *found = find_key(label_root, label);
- if (found) {
- return strdup(found);
- }
- return NULL;
- }
- void set_label(const char *label, const char *target)
- {
- if (target == NULL) {
- yyerror("no hanging value for label");
- target = "<??" ">"; /* avoid trigraph warning */
- }
- label_root = set_key(label_root, label, target);
- }
- char *new_counter(const char *key)
- {
- int i=0, j, ndollars = 0;
- const char *old;
- char *new;
- if (key[i++] != '#') {
- yyerror("bad index");
- return strdup("<???" ">"); /* avoid trigraph warning */
- }
- while (key[i] == '$') {
- ++ndollars;
- ++i;
- }
- key += i;
- old = find_key(counter_root, key);
- new = malloc(20*ndollars);
- if (old) {
- for (j=0; ndollars > 1 && old[j]; ) {
- if (old[j++] == '.' && --ndollars <= 0) {
- break;
- }
- }
- if (j) {
- strncpy(new, old, j);
- }
- if (old[j]) {
- i = atoi(old+j);
- } else {
- new[j++] = '.';
- i = 0;
- }
- } else {
- j=0;
- while (--ndollars > 0) {
- new[j++] = '0';
- new[j++] = '.';
- }
- i = 0;
- }
- new[j] = '\0';
- sprintf(new+j, "%d", ++i);
- counter_root = set_key(counter_root, key, new);
- if (last_label) {
- free(last_label);
- }
- last_label = strdup(new);
- return new;
- }
- int
- main(void)
- {
- return yyparse();
- }
|