1 /*
2 * Syntax highlighting DFA interpreter
3 * Copyright
4 * (C) 2004 Joseph H. Allen
5 *
6 * This file is part of JOE (Joe's Own Editor)
7 */
8
9 #include "types.h"
10
11 /* Parse one line. Returns new state.
12 'syntax' is the loaded syntax definition for this buffer.
13 'line' is advanced to start of next line.
14 Global array 'attr_buf' end up with coloring for each character of line.
15 'state' is initial parser state for the line (0 is initial state).
16 */
17
18 int *attr_buf = 0;
19 int attr_size = 0;
20
21 int stack_count = 0;
22 static int state_count = 0; /* Max transitions possible without cycling */
23
24 struct high_syntax *ansi_syntax;
25 struct high_syntax *syntax_list;
26
27 /* ANSI highlighter */
28
29 #define IDLE 0
30 #define AFTER_ESC 1
31 #define AFTER_BRACK 2
32 #define IN_NUMBER 3
33
ansi_parse(P * line,HIGHLIGHT_STATE h_state)34 static HIGHLIGHT_STATE ansi_parse(P *line, HIGHLIGHT_STATE h_state)
35 {
36 int *attr = attr_buf;
37 int *attr_end = attr_buf + attr_size;
38 int c;
39 int bold = 0; /* Save bold state for extended scheme colors */
40
41 int state = IDLE; /* h_state.saved_s[0]; */
42 int accu = 0; /* h_state.saved_s[1]; */
43 int current_attr = 0; /* (int)h_state.state; */ /* Do not let attributes cross lines - simplifies vt.c */
44 // int new_attr = *(int *)(h_state.saved_s + 8);
45
46 int ansi_mode = line->b->o.ansi;
47
48 line->b->o.ansi = 0;
49
50 while ((c = pgetc(line)) != NO_MORE_DATA) {
51 if (attr == attr_end) {
52 if (!attr_buf) {
53 attr_size = 1024;
54 attr_buf = (int *)joe_malloc(SIZEOF(int) * attr_size);
55 attr = attr_buf;
56 } else {
57 attr_buf = (int *)joe_realloc(attr_buf, SIZEOF(int) * (attr_size * 2));
58 attr = attr_buf + attr_size;
59 attr_size *= 2;
60 }
61 attr_end = attr_buf + attr_size;
62 }
63 *attr++ = current_attr;
64 switch (state) {
65 case IDLE: {
66 if (c == 27) {
67 state = AFTER_ESC;
68 }
69 break;
70 } case AFTER_ESC: {
71 if (c == '[') {
72 state = AFTER_BRACK;
73 // new_attr = (current_attr & (FG_MASK | BG_MASK));
74 } else {
75 state = IDLE;
76 }
77 break;
78 } case AFTER_BRACK: {
79 if (c == ';') {
80 /* RESET */
81 current_attr = 0;
82 /* but stay in this state */
83 } else if (c >= '0' && c <= '9') {
84 accu = (char)(c - '0');
85 state = IN_NUMBER;
86 } else if (c == 'm') {
87 /* APPLY NEW ATTRIBUTES */
88 current_attr = 0;
89 state = IDLE;
90 } else {
91 state = IDLE;
92 }
93 break;
94 } case IN_NUMBER: {
95 if (c == ';' || c == 'm') {
96 if (accu == 0) {
97 current_attr = 0;
98 bold = 0;
99 } else if (accu == 1) {
100 current_attr |= BOLD;
101 bold = 1;
102 } else if (accu == 4) {
103 current_attr |= UNDERLINE;
104 } else if (accu == 5) {
105 current_attr |= BLINK;
106 } else if (accu == 7) {
107 current_attr |= INVERSE;
108 } else if (accu == 9) {
109 current_attr |= CROSSED_OUT;
110 } else if (accu == 21) {
111 current_attr |= DOUBLE_UNDERLINE;
112 } else if (accu >= 30 && accu <= 37) {
113 if (bold && curschemeset && curschemeset->termcolors[accu - 22].type != COLORSPEC_TYPE_NONE) {
114 /* Remapped extended color */
115 current_attr = (current_attr & ~FG_MASK) | (curschemeset->termcolors[accu - 22].atr & FG_MASK & ~BOLD);
116 } else if (curschemeset && curschemeset->termcolors[accu - 30].type != COLORSPEC_TYPE_NONE) {
117 /* Remapped by scheme */
118 current_attr = (current_attr & ~FG_MASK) | (curschemeset->termcolors[accu - 30].atr & FG_MASK);
119 } else {
120 current_attr = (current_attr & ~FG_MASK) | FG_NOT_DEFAULT | ((accu - 30) << FG_SHIFT) | (-bold & BOLD);
121 }
122 } else if (accu >= 40 && accu <= 47) {
123 if (curschemeset && curschemeset->termcolors[accu - 40].type != COLORSPEC_TYPE_NONE) {
124 /* Remapped by scheme */
125 current_attr = (current_attr & ~BG_MASK) | (((curschemeset->termcolors[accu - 40].atr & FG_MASK) >> FG_SHIFT) << BG_SHIFT);
126 } else {
127 current_attr = (current_attr & ~BG_MASK) | BG_NOT_DEFAULT | ((accu - 40) << BG_SHIFT);
128 }
129 }
130 if (c == ';') {
131 accu = 0;
132 state = IN_NUMBER;
133 } else if (c == 'm') {
134 state = IDLE;
135 }
136 } else if (c >= '0' && c <= '9') {
137 accu = (char)(accu * 10 + c - '0');
138 } else {
139 state = IDLE;
140 }
141 }
142 }
143 if (c == '\n')
144 break;
145 }
146 line->b->o.ansi = ansi_mode;
147 /* h_state.saved_s[0] = state;
148 h_state.saved_s[1] = accu;
149 h_state.saved_s[2] = 0; */ /* Because we Zcmp(saved_s) */
150 h_state.state = current_attr;
151 return h_state;
152 }
153
parse(struct high_syntax * syntax,P * line,HIGHLIGHT_STATE h_state,struct charmap * charmap)154 HIGHLIGHT_STATE parse(struct high_syntax *syntax,P *line,HIGHLIGHT_STATE h_state,struct charmap *charmap)
155 {
156 struct high_frame *stack;
157 struct high_state *h;
158 /* Current state */
159 int buf[SAVED_SIZE]; /* Name buffer (trunc after 23 characters) */
160 int lbuf[3*SAVED_SIZE]; /* Lower case version of name buffer */
161 int lsaved_s[3*SAVED_SIZE]; /* Lower case version of delimiter match buffer */
162 int buf_idx; /* Index into buffer */
163 int c; /* Current character */
164 int *attr;
165 int *attr_end;
166 int buf_en; /* Set for name buffering */
167 int ofst; /* record offset after we've stopped buffering */
168 int mark1; /* offset to mark start from current pos */
169 int mark2; /* offset to mark end from current pos */
170 int mark_en; /* set if marking */
171 int recolor_delimiter_or_keyword;
172
173 /* Nothing should reference 'h' above here. */
174 if (h_state.state < 0) {
175 /* Indicates a previous error -- highlighting disabled */
176 return h_state;
177 }
178
179 if (syntax == ansi_syntax)
180 return ansi_parse(line, h_state);
181
182 stack = h_state.stack;
183 h = (stack ? stack->syntax : syntax)->states[h_state.state];
184 buf_idx = 0;
185 attr = attr_buf;
186 attr_end = attr_buf + attr_size;
187 buf_en = 0;
188 ofst = 0;
189 mark1 = 0;
190 mark2 = 0;
191 mark_en = 0;
192
193 buf[0]=0; /* Forgot this originally... took 5 months to fix! */
194
195 /* Get next character */
196 while((c=pgetc(line))!=NO_MORE_DATA) {
197 struct high_cmd *cmd, *kw_cmd;
198 int iters = -8; /* +8 extra iterations before cycle detect. */
199 ptrdiff_t x;
200
201 /* If it isn't already, convert character to unicode */
202 if (!charmap->type)
203 c = to_uni(charmap, c);
204
205 /* Create or expand attribute array if necessary */
206 if(attr==attr_end) {
207 if(!attr_buf) {
208 attr_size = 1024;
209 attr_buf = (int *)joe_malloc(SIZEOF(int)*attr_size);
210 attr = attr_buf;
211 } else {
212 attr_buf = (int *)joe_realloc(attr_buf,SIZEOF(int)*(attr_size*2));
213 attr = attr_buf + attr_size;
214 attr_size *= 2;
215 }
216 attr_end = attr_buf + attr_size;
217 }
218
219 /* Advance to next attribute position (note attr[-1] below) */
220 attr++;
221
222 /* Loop while noeat */
223 do {
224 /* Guard against infinite loops from buggy syntaxes */
225 if (iters++ > state_count) {
226 invalidate_state(&h_state);
227 return h_state;
228 }
229
230 /* Color with current state */
231 attr[-1] = h->color;
232
233 /* Get command for this character */
234 if (h->delim && h_state.saved_s && c == h_state.saved_s[0] && h_state.saved_s[1] && h_state.saved_s[2] == 0)
235 cmd = h->delim;
236 else if (h->same_delim && h_state.saved_s && h_state.saved_s[0] && c == h_state.saved_s[1] && h_state.saved_s[2] == 0)
237 cmd = h->same_delim;
238 else {
239 cmd = (struct high_cmd *)rtree_lookup(&h->rtree, c);
240 if (!cmd)
241 cmd = h->dflt;
242 }
243
244 /* Lowerize strings for case-insensitive matching */
245 if (cmd->ignore) {
246 lowerize(lbuf, SIZEOF(lbuf)/SIZEOF(lbuf[0]), buf);
247 if (cmd->delim) {
248 if (h_state.saved_s)
249 lowerize(lsaved_s, SIZEOF(lsaved_s)/SIZEOF(lsaved_s[0]), h_state.saved_s);
250 else
251 lsaved_s[0] = 0;
252 }
253 }
254
255 /* Check for delimiter or keyword matches */
256 recolor_delimiter_or_keyword = 0;
257 if (cmd->delim && (cmd->ignore ? !Zcmp(lsaved_s,lbuf) : (h_state.saved_s && !Zcmp(h_state.saved_s,buf)))) {
258 cmd = cmd->delim;
259 recolor_delimiter_or_keyword = 1;
260 } else if (cmd->keywords && (cmd->ignore ? (kw_cmd=(struct high_cmd *)Zhtfind(cmd->keywords,lbuf)) : (kw_cmd=(struct high_cmd *)Zhtfind(cmd->keywords,buf)))) {
261 cmd = kw_cmd;
262 recolor_delimiter_or_keyword = 1;
263 }
264
265 /* Determine new state */
266 if (cmd->call) {
267 /* Call */
268 struct high_frame **frame_ptr = stack ? &stack->child : &syntax->stack_base;
269 /* Search for an existing stack frame for this call */
270 while (*frame_ptr && !((*frame_ptr)->syntax == cmd->call && (*frame_ptr)->return_state == cmd->new_state))
271 frame_ptr = &(*frame_ptr)->sibling;
272 if (*frame_ptr)
273 stack = *frame_ptr;
274 else {
275 struct high_frame *frame = (struct high_frame *)joe_malloc(SIZEOF(struct high_frame));
276 frame->parent = stack;
277 frame->child = 0;
278 frame->sibling = 0;
279 frame->syntax = cmd->call;
280 frame->return_state = cmd->new_state;
281 *frame_ptr = frame;
282 stack = frame;
283 ++stack_count;
284 }
285 h = stack->syntax->states[0];
286 } else if (cmd->rtn) {
287 /* Return */
288 if (stack) {
289 h = stack->return_state;
290 stack = stack->parent;
291 } else
292 /* Not in a subroutine, so ignore the return */
293 h = cmd->new_state;
294 } else if (cmd->reset) {
295 h = syntax->states[0];
296 } else {
297 /* Normal edge */
298 h = cmd->new_state;
299 }
300
301 /* Recolor if necessary */
302 if (recolor_delimiter_or_keyword)
303 for(x= -(buf_idx+1);x<-1;++x)
304 attr[x-ofst] = h->color;
305 for(x=cmd->recolor;x<0;++x)
306 if (attr + x >= attr_buf)
307 attr[x] = h->color;
308
309 /* Mark recoloring */
310 if (cmd->recolor_mark)
311 for(x= -mark1;x<-mark2;++x)
312 attr[x] = h->color;
313
314 /* Save string? */
315 if (cmd->save_s) {
316 h_state.saved_s = Zatom_add(buf);
317 }
318
319 /* Save character? */
320 if (cmd->save_c) {
321 int bf[3];
322 bf[1] = c;
323 bf[2] = 0;
324 if (c=='<')
325 bf[0] = '>';
326 else if (c=='(')
327 bf[0] = ')';
328 else if (c=='[')
329 bf[0] = ']';
330 else if (c=='{')
331 bf[0] = '}';
332 else if (c=='`')
333 bf[0] = '\'';
334 else
335 bf[0] = c;
336 h_state.saved_s = Zatom_add(bf);
337 }
338
339 /* Start buffering? */
340 if (cmd->start_buffering) {
341 buf_idx = 0;
342 buf_en = 1;
343 ofst = 0;
344 }
345
346 /* Stop buffering? */
347 if (cmd->stop_buffering)
348 buf_en = 0;
349
350 /* Set mark begin? */
351 if (cmd->start_mark)
352 {
353 mark2 = 1;
354 mark1 = 1;
355 mark_en = 1;
356 }
357
358 /* Set mark end? */
359 if(cmd->stop_mark)
360 {
361 mark_en = 0;
362 mark2 = 1;
363 }
364 } while(cmd->noeat);
365
366 /* Save character in buffer */
367 if (buf_idx < (SAVED_SIZE - 1) && buf_en)
368 buf[buf_idx++] = c;
369 if (!buf_en)
370 ++ofst;
371 buf[buf_idx] = 0;
372
373 /* Update mark pointers */
374 ++mark1;
375 if(!mark_en)
376 ++mark2;
377
378 if(c=='\n')
379 break;
380 }
381 /* Return new state */
382 h_state.stack = stack;
383 h_state.state = h->no;
384 return h_state;
385 }
386
387 /* Subroutines for load_dfa() */
388
find_state(struct high_syntax * syntax,char * name)389 static struct high_state *find_state(struct high_syntax *syntax,char *name)
390 {
391 struct high_state *state;
392
393 /* Find state */
394 state = (struct high_state *)htfind(syntax->ht_states, name);
395
396 /* It doesn't exist, so create it */
397 if(!state) {
398 state=(struct high_state *)joe_malloc(SIZEOF(struct high_state));
399 state->name = zdup(name);
400 state->no = syntax->nstates;
401 state->color = 0;
402 state->colorp = NULL;
403 /* Expand the state table if necessary */
404 if (syntax->nstates==syntax->szstates)
405 syntax->states=(struct high_state **)joe_realloc(syntax->states,SIZEOF(struct high_state *)*(syntax->szstates*=2));
406 syntax->states[syntax->nstates++]=state;
407 rtree_init(&state->rtree);
408 state->dflt = &syntax->default_cmd;
409 state->delim = 0;
410 state->same_delim = 0;
411 htadd(syntax->ht_states, state->name, state);
412 ++state_count;
413 }
414 return state;
415 }
416
417 /* Build cmaps */
418
build_cmaps(struct high_syntax * syntax)419 static void build_cmaps(struct high_syntax *syntax)
420 {
421 int x;
422 for (x = 0; x != syntax->ht_states->len; ++x) {
423 HENTRY *p;
424 for (p = syntax->ht_states->tab[x]; p; p = p->next) {
425 struct high_state *st = (struct high_state *)p->val;
426 rtree_opt(&st->rtree);
427 }
428 }
429 }
430
431 /* Create empty command */
432
iz_cmd(struct high_cmd * cmd)433 static void iz_cmd(struct high_cmd *cmd)
434 {
435 cmd->noeat = 0;
436 cmd->recolor = 0;
437 cmd->start_buffering = 0;
438 cmd->stop_buffering = 0;
439 cmd->save_c = 0;
440 cmd->save_s = 0;
441 cmd->new_state = 0;
442 cmd->keywords = 0;
443 cmd->delim = 0;
444 cmd->ignore = 0;
445 cmd->start_mark = 0;
446 cmd->stop_mark = 0;
447 cmd->recolor_mark = 0;
448 cmd->rtn = 0;
449 cmd->reset = 0;
450 cmd->call = 0;
451 }
452
mkcmd()453 static struct high_cmd *mkcmd()
454 {
455 struct high_cmd *cmd = (struct high_cmd *)joe_malloc(SIZEOF(struct high_cmd));
456 iz_cmd(cmd);
457 return cmd;
458 }
459
find_color(struct color_def * colors,char * name,char * syn)460 static struct color_def *find_color(struct color_def *colors,char *name,char *syn)
461 {
462 char bf[256];
463 struct color_def *color;
464 joe_snprintf_2(bf, SIZEOF(bf), "%s.%s", syn, name);
465 for (color = colors; color; color = color->next)
466 if (!zcmp(color->name,bf)) break;
467 if (color)
468 return color;
469 for (color = colors; color; color = color->next)
470 if (!zcmp(color->name,name)) break;
471 return color;
472 }
473
parse_syntax_color_def(struct color_def ** color_list,const char * p,char * name,int line)474 void parse_syntax_color_def(struct color_def **color_list,const char *p,char *name,int line)
475 {
476 char bf[256];
477 if(!parse_tows(&p, bf)) {
478 struct color_def *color;
479
480 /* Find color */
481 color=find_color(*color_list,bf,name);
482
483 /* If it doesn't exist, create it */
484 if(!color) {
485 color = (struct color_def *)joe_malloc(SIZEOF(struct color_def));
486 color->name = atom_add(bf);
487 color->next = *color_list;
488 *color_list = color;
489 } else {
490 logerror_2(joe_gettext(_("%s %d: Class already defined\n")),name,line);
491 }
492
493 parse_color_def(&p, color);
494
495 /* Older syntaxes had colors specified with color classes. For backwards
496 compatibility, we'll try to map those into the scheme via the term_colors.
497 We preserve the parsed color_spec here because the scheme/syntax color
498 resolution procedure will overwrite color->spec. */
499 memcpy(&color->orig, &color->spec, SIZEOF(struct color_spec));
500 } else {
501 logerror_2(joe_gettext(_("%s %d: Missing class name\n")),name,line);
502 }
503 }
504
505
506 /* Dump sytnax file */
507
dump_syntax(BW * bw)508 void dump_syntax(BW *bw)
509 {
510 struct high_syntax *syntax;
511 struct high_param *params;
512 char buf[1024];
513 joe_snprintf_1(buf, SIZEOF(buf), "Allocated %d stack frames\n", stack_count);
514 binss(bw->cursor, buf);
515 pnextl(bw->cursor);
516 for (syntax = syntax_list; syntax; syntax = syntax->next) {
517 int x;
518 joe_snprintf_3(buf, SIZEOF(buf), "Syntax name=%s, subr=%s, nstates=%d\n",syntax->name,syntax->subr,(int)syntax->nstates);
519 binss(bw->cursor, buf);
520 pnextl(bw->cursor);
521 zlcpy(buf, SIZEOF(buf), "params=(");
522 for(params = syntax->params; params; params = params->next) {
523 zlcat(buf, SIZEOF(buf), " ");
524 zlcat(buf, SIZEOF(buf), params->name);
525 }
526 zlcat(buf, SIZEOF(buf), " )\n");
527 binss(bw->cursor, buf);
528 pnextl(bw->cursor);
529 for(x=0;x!=syntax->nstates;++x) {
530 struct high_state *s = syntax->states[x];
531 joe_snprintf_2(buf, SIZEOF(buf), " state %s %x\n",s->name,s->color);
532 binss(bw->cursor, buf);
533 pnextl(bw->cursor);
534 // for (l = s->src; l; l = l->next) {
535 // struct high_cmd *h = (struct high_cmd *)l->map;
536 // joe_snprintf_4(buf, SIZEOF(buf), " [%d-%d] -> %s %d\n",l->interval.first,l->interval.last,(h->new_state ? h->new_state->name : "ERROR! Unknown state!"),(int)h->recolor);
537 // binss(bw->cursor, buf);
538 // pnextl(bw->cursor);
539 // }
540 joe_snprintf_2(buf, SIZEOF(buf), " default -> %s %d\n",(s->dflt->new_state ? s->dflt->new_state->name : "ERROR! Unknown state!"),(int)s->dflt->recolor);
541 binss(bw->cursor, buf);
542 pnextl(bw->cursor);
543 }
544 }
545 }
546
parse_params(struct high_param * current_params,const char ** ptr,char * name,int line)547 static struct high_param *parse_params(struct high_param *current_params,const char **ptr,char *name,int line)
548 {
549 const char *p = *ptr;
550 char bf[256];
551 struct high_param *params;
552 struct high_param **param_ptr;
553
554 /* Propagate currently defined parameters */
555 param_ptr = ¶ms;
556 while (current_params) {
557 *param_ptr = (struct high_param *)joe_malloc(SIZEOF(struct high_param));
558 (*param_ptr)->name = zdup(current_params->name);
559 param_ptr = &(*param_ptr)->next;
560 current_params = current_params->next;
561 }
562 *param_ptr = 0;
563
564 parse_ws(&p, '#');
565 if (!parse_char(&p, '(')) {
566 for (;;) {
567 parse_ws(&p, '#');
568 if (!parse_char(&p, ')'))
569 break;
570 else if (!parse_char(&p, '-')) {
571 if (!parse_ident(&p,bf,SIZEOF(bf))) {
572 int cmp = 0;
573 param_ptr = ¶ms;
574 /* Parameters are sorted */
575 while (*param_ptr && (cmp = zcmp(bf,(*param_ptr)->name)) > 0)
576 param_ptr = &(*param_ptr)->next;
577 if (*param_ptr && !cmp) {
578 /* Remove this parameter */
579 struct high_param *param = *param_ptr;
580 *param_ptr = param->next;
581 joe_free(param);
582 }
583 } else {
584 logerror_2(joe_gettext(_("%s %d: Missing parameter name\n")),name,line);
585 }
586 } else if (!parse_ident(&p,bf,SIZEOF(bf))) {
587 int cmp = 0;
588 param_ptr = ¶ms;
589 /* Keep parameters sorted */
590 while (*param_ptr && (cmp = zcmp(bf,(*param_ptr)->name)) > 0)
591 param_ptr = &(*param_ptr)->next;
592 /* Discard duplicates */
593 if (!*param_ptr || cmp) {
594 struct high_param *param = (struct high_param *)joe_malloc(SIZEOF(struct high_param));
595 param->name = zdup(bf);
596 param->next = *param_ptr;
597 *param_ptr = param;
598 }
599 } else {
600 logerror_2(joe_gettext(_("%s %d: Missing )\n")),name,line);
601 break;
602 }
603 }
604 }
605
606 *ptr = p;
607 return params;
608 }
609
610
611 struct high_syntax *load_syntax_subr(const char *name,char *subr,struct high_param *params);
612
613 /* Parse options */
614
parse_options(struct high_syntax * syntax,struct high_cmd * cmd,JFILE * f,const char * p,int parsing_strings,char * name,int line)615 static int parse_options(struct high_syntax *syntax,struct high_cmd *cmd,JFILE *f,const char *p,int parsing_strings,char *name,int line)
616 {
617 char buf[1024];
618 char bf[256];
619 char bf1[256];
620
621 while (parse_ws(&p,'#'), !parse_ident(&p,bf,SIZEOF(bf)))
622 if(!zcmp(bf,"buffer")) {
623 cmd->start_buffering = 1;
624 } else if(!zcmp(bf,"hold")) {
625 cmd->stop_buffering = 1;
626 } else if(!zcmp(bf,"save_c")) {
627 cmd->save_c = 1;
628 } else if(!zcmp(bf,"save_s")) {
629 cmd->save_s = 1;
630 } else if(!zcmp(bf,"recolor")) {
631 parse_ws(&p,'#');
632 if(!parse_char(&p,'=')) {
633 parse_ws(&p,'#');
634 if(parse_diff(&p,&cmd->recolor))
635 logerror_2(joe_gettext(_("%s %d: Missing value for option\n")),name,line);
636 } else
637 logerror_2(joe_gettext(_("%s %d: Missing value for option\n")),name,line);
638 } else if(!zcmp(bf,"call")) {
639 parse_ws(&p,'#');
640 if(!parse_char(&p,'=')) {
641 parse_ws(&p,'#');
642 if (!parse_char(&p,'.')) {
643 zlcpy(bf, SIZEOF(bf), syntax->name);
644 goto subr;
645 } else if (parse_ident(&p,bf,SIZEOF(bf)))
646 logerror_2(joe_gettext(_("%s %d: Missing value for option\n")),name,line);
647 else {
648 if (!parse_char(&p,'.')) {
649 subr:
650 if (parse_ident(&p,bf1,SIZEOF(bf1)))
651 logerror_2(joe_gettext(_("%s %d: Missing subroutine name\n")),name,line);
652 cmd->call = load_syntax_subr(bf,bf1,parse_params(syntax->params,&p,name,line));
653 } else
654 cmd->call = load_syntax_subr(bf,0,parse_params(syntax->params,&p,name,line));
655 }
656 } else
657 logerror_2(joe_gettext(_("%s %d: Missing value for option\n")),name,line);
658 } else if(!zcmp(bf,"return")) {
659 cmd->rtn = 1;
660 } else if(!zcmp(bf,"reset")) {
661 cmd->reset = 1;
662 } else if(!parsing_strings && (!zcmp(bf,"strings") || !zcmp(bf,"istrings"))) {
663 if (bf[0]=='i')
664 cmd->ignore = 1;
665 while(jfgets(buf,sizeof(buf),f)) {
666 ++line;
667 p = buf;
668 parse_ws(&p,'#');
669 if (*p) {
670 int kwbuf[256];
671 int lkwbuf[256 * 3];
672 if(!parse_field(&p,"done"))
673 break;
674 if(parse_Zstring(&p,kwbuf,SIZEOF(kwbuf)/SIZEOF(kwbuf[0])) >= 0) {
675 parse_ws(&p,'#');
676 if (cmd->ignore)
677 lowerize(lkwbuf, SIZEOF(lkwbuf)/SIZEOF(lkwbuf[0]), kwbuf);
678 if(!parse_ident(&p,bf1,SIZEOF(bf1))) {
679 struct high_cmd *kw_cmd=mkcmd();
680 kw_cmd->noeat=1;
681 kw_cmd->new_state = find_state(syntax,bf1);
682 if (kwbuf[0] == '&' && !kwbuf[1]) {
683 cmd->delim = kw_cmd;
684 } else {
685 if(!cmd->keywords)
686 cmd->keywords = Zhtmk(64);
687 Zhtadd(cmd->keywords, (cmd->ignore ? Zdup(lkwbuf) : Zdup(kwbuf)), kw_cmd);
688 }
689 line = parse_options(syntax,kw_cmd,f,p,1,name,line);
690 } else
691 logerror_2(joe_gettext(_("%s %d: Missing state name\n")),name,line);
692 } else
693 logerror_2(joe_gettext(_("%s %d: Missing string\n")),name,line);
694 }
695 }
696 } else if(!zcmp(bf,"noeat")) {
697 cmd->noeat = 1;
698 } else if(!zcmp(bf,"mark")) {
699 cmd->start_mark = 1;
700 } else if(!zcmp(bf,"markend")) {
701 cmd->stop_mark = 1;
702 } else if(!zcmp(bf,"recolormark")) {
703 cmd->recolor_mark = 1;
704 } else
705 logerror_2(joe_gettext(_("%s %d: Unknown option\n")),name,line);
706 return line;
707 }
708
709 struct ifstack {
710 struct ifstack *next;
711 int ignore; /* Ignore input lines if set */
712 int skip; /* Set to skip the else part */
713 int else_part; /* Set if we're in the else part */
714 int line;
715 };
716
717 /* Load dfa */
718
load_dfa(struct high_syntax * syntax)719 static struct high_state *load_dfa(struct high_syntax *syntax)
720 {
721 char name[1024];
722 char buf[1024];
723 char bf[256];
724 const char *p;
725 ptrdiff_t c;
726 JFILE *f = 0;
727 struct ifstack *stack=0;
728 struct high_state *state=0; /* Current state */
729 struct high_state *first=0; /* First state */
730 int line = 0;
731 int this_one = 0;
732 int inside_subr = 0;
733
734 /* Load it */
735 p = getenv("HOME");
736 if (p) {
737 joe_snprintf_2(name,SIZEOF(name),"%s/.joe/syntax/%s.jsf",p,syntax->name);
738 f = jfopen(name,"r");
739 }
740
741 if (!f) {
742 joe_snprintf_2(name,SIZEOF(name),"%ssyntax/%s.jsf",JOEDATA,syntax->name);
743 f = jfopen(name,"r");
744 }
745 if (!f) {
746 joe_snprintf_1(name,SIZEOF(name),"*%s.jsf",syntax->name);
747 f = jfopen(name,"r");
748 }
749 if (!f) {
750 return 0;
751 }
752
753 /* Parse file */
754 while(jfgets(buf,SIZEOF(buf),f)) {
755 ++line;
756 p = buf;
757 c = parse_ws(&p,'#');
758 if (!parse_char(&p, '.')) {
759 if (!parse_ident(&p, bf, SIZEOF(bf))) {
760 if (!zcmp(bf, "ifdef")) {
761 struct ifstack *st = (struct ifstack *)joe_malloc(SIZEOF(struct ifstack));
762 st->next = stack;
763 st->else_part = 0;
764 st->ignore = 1;
765 st->skip = 1;
766 st->line = line;
767 if (!stack || !stack->ignore) {
768 parse_ws(&p,'#');
769 if (!parse_ident(&p, bf, SIZEOF(bf))) {
770 struct high_param *param;
771 for (param = syntax->params; param; param = param->next)
772 if (!zcmp(param->name, bf)) {
773 st->ignore = 0;
774 break;
775 }
776 st->skip = 0;
777 } else {
778 logerror_2(joe_gettext(_("%s %d: missing parameter for ifdef\n")),name,line);
779 }
780 }
781 stack = st;
782 } else if (!zcmp(bf, "else")) {
783 if (stack && !stack->else_part) {
784 stack->else_part = 1;
785 if (!stack->skip)
786 stack->ignore = !stack->ignore;
787 } else
788 logerror_2(joe_gettext(_("%s %d: else with no matching if\n")),name,line);
789 } else if (!zcmp(bf, "endif")) {
790 if (stack) {
791 struct ifstack *st = stack;
792 stack = st->next;
793 joe_free(st);
794 } else
795 logerror_2(joe_gettext(_("%s %d: endif with no matching if\n")),name,line);
796 } else if (!zcmp(bf, "subr")) {
797 parse_ws(&p, '#');
798 if (parse_ident(&p, bf, SIZEOF(bf))) {
799 logerror_2(joe_gettext(_("%s %d: Missing subroutine name\n")),name,line);
800 } else {
801 if (!stack || !stack->ignore) {
802 inside_subr = 1;
803 this_one = 0;
804 if (syntax->subr && !zcmp(bf, syntax->subr))
805 this_one = 1;
806 }
807 }
808 } else if (!zcmp(bf, "end")) {
809 if (!stack || !stack->ignore) {
810 this_one = 0;
811 inside_subr = 0;
812 }
813 } else {
814 logerror_2(joe_gettext(_("%s %d: Unknown control statement\n")),name,line);
815 }
816 } else {
817 logerror_2(joe_gettext(_("%s %d: Missing control statement name\n")),name,line);
818 }
819 } else if (stack && stack->ignore) {
820 /* Ignore this line because of ifdef */
821 } else if(!parse_char(&p, '=')) {
822 /* Parse color */
823 parse_syntax_color_def(&syntax->color,p,name,line);
824 } else if ((syntax->subr && !this_one) || (!syntax->subr && inside_subr)) {
825 /* Ignore this line because it's not the code we want */
826 } else if(!parse_char(&p, ':')) {
827 if(!parse_ident(&p, bf, SIZEOF(bf))) {
828
829 state = find_state(syntax,bf);
830
831 if (!first)
832 first = state;
833
834 parse_ws(&p,'#');
835 if(!parse_tows(&p,bf)) {
836 struct color_def *color;
837 for(color=syntax->color;color;color=color->next)
838 if(!zcmp(color->name,bf))
839 break;
840 if(!color) {
841 logerror_2(joe_gettext(_("%s %d: Unknown class\n")),name,line);
842 }
843
844 state->color = 0;
845 state->colorp = color;
846 while(parse_ws(&p, '#'), !parse_ident(&p, bf, SIZEOF(bf))) {
847 if(!zcmp(bf, "comment")) {
848 state->color |= CONTEXT_COMMENT;
849 } else if(!zcmp(bf, "string")) {
850 state->color |= CONTEXT_STRING;
851 } else {
852 logerror_2(joe_gettext(_("%s %d: Unknown context\n")),name,line);
853 }
854 }
855 } else
856 logerror_2(joe_gettext(_("%s %d: Missing color for state definition\n")),name,line);
857 } else
858 logerror_2(joe_gettext(_("%s %d: Missing state name\n")),name,line);
859 } else if(!parse_char(&p, '-')) {
860 /* No. sync lines ignored */
861 } else {
862 c = parse_ws(&p,'#');
863
864 if (!c) {
865 } else if (c=='"' || c=='*' || c=='&' || c =='%') {
866 if (state) {
867 struct high_cmd *cmd = mkcmd();
868 if(!parse_field(&p, "*")) {
869 state->dflt = cmd;
870 } else if(!parse_field(&p, "&")) {
871 state->delim = cmd;
872 } else if(!parse_field(&p, "%")) {
873 state->same_delim = cmd;
874 } else {
875 struct interval *array;
876 ptrdiff_t size;
877 ++p;
878 while(*p != '"' && !parse_class(&p, &array, &size)) {
879 rtree_set(&state->rtree, array, size, cmd);
880 /* logmessage_3("Interval add: %x - %x to %p\n", array[0].first, array[0].last, cmd); */
881 }
882 if (*p != '"')
883 logerror_2(joe_gettext(_("%s %d: Bad string\n")),name,line);
884 else
885 ++p;
886 /* rtree_show(&state->rtree); */
887 }
888 /* Create command */
889 parse_ws(&p,'#');
890 if(!parse_ident(&p,bf,SIZEOF(bf))) {
891 cmd->new_state = find_state(syntax,bf);
892 line = parse_options(syntax,cmd,f,p,0,name,line);
893 } else
894 logerror_2(joe_gettext(_("%s %d: Missing jump\n")),name,line);
895 } else
896 logerror_2(joe_gettext(_("%s %d: No state\n")),name,line);
897 } else
898 logerror_2(joe_gettext(_("%s %d: Unknown character\n")),name,line);
899 }
900 }
901
902 while (stack) {
903 struct ifstack *st = stack;
904 stack = st->next;
905 logerror_2(joe_gettext(_("%s %d: ifdef with no matching endif\n")),name,st->line);
906 joe_free(st);
907 }
908
909 jfclose(f);
910
911 /* Compile cmaps */
912 build_cmaps(syntax);
913
914 return first;
915 }
916
syntax_match(struct high_syntax * syntax,const char * name,const char * subr,struct high_param * params)917 static int syntax_match(struct high_syntax *syntax,const char *name,const char *subr,struct high_param *params)
918 {
919 struct high_param *syntax_params;
920 if (zcmp(syntax->name,name))
921 return 0;
922 if (!syntax->subr ^ !subr)
923 return 0;
924 if (subr && zcmp(syntax->subr,subr))
925 return 0;
926 syntax_params = syntax->params;
927 while (syntax_params && params) {
928 if (zcmp(syntax_params->name,params->name))
929 return 0;
930 syntax_params = syntax_params->next;
931 params = params->next;
932 }
933 return syntax_params == params;
934 }
935
load_syntax_subr(const char * name,char * subr,struct high_param * params)936 struct high_syntax *load_syntax_subr(const char *name,char *subr,struct high_param *params)
937 {
938 struct high_syntax *syntax; /* New syntax table */
939
940 /* Find syntax table */
941
942 /* Already loaded? */
943 for(syntax=syntax_list;syntax;syntax=syntax->next)
944 if(syntax_match(syntax,name,subr,params))
945 return syntax;
946
947 /* Create new one */
948 syntax = (struct high_syntax *)joe_malloc(SIZEOF(struct high_syntax));
949 syntax->name = zdup(name);
950 syntax->subr = subr ? zdup(subr) : 0;
951 syntax->params = params;
952 syntax->next = syntax_list;
953 syntax->nstates = 0;
954 syntax->color = 0;
955 syntax->states = (struct high_state **)joe_malloc(SIZEOF(struct high_state *)*(syntax->szstates = 64));
956 syntax->ht_states = htmk(syntax->szstates);
957 iz_cmd(&syntax->default_cmd);
958 syntax->default_cmd.reset = 1;
959 syntax->stack_base = 0;
960 syntax_list = syntax;
961
962 if (load_dfa(syntax)) {
963 /* dump_syntax(syntax); */
964 resolve_syntax_colors(curschemeset, syntax);
965 return syntax;
966 } else {
967 if(syntax_list == syntax)
968 syntax_list = syntax_list->next;
969 else {
970 struct high_syntax *syn;
971 for(syn=syntax_list;syn->next!=syntax;syn=syn->next);
972 syn->next = syntax->next;
973 }
974 htrm(syntax->ht_states);
975 joe_free(syntax->name);
976 joe_free(syntax->states);
977 joe_free(syntax);
978 return 0;
979 }
980 }
981
load_syntax(const char * name)982 struct high_syntax *load_syntax(const char *name)
983 {
984 if (!ansi_syntax) {
985 ansi_syntax = (struct high_syntax *)joe_calloc(1, SIZEOF(struct high_syntax));
986 ansi_syntax->name = zdup("ansi");
987 }
988
989 if (!name)
990 return 0;
991
992 if (!zcmp(name, "ansi"))
993 return ansi_syntax;
994
995 return load_syntax_subr(name,0,0);
996 }
997