📄 input.cc
字号:
; if (cc == '\n') type = TOKEN_NEWLINE; else type = TOKEN_EOF; return; case '#': // Like \" but newline is ignored. while ((cc = input_stack::get(NULL)) != '\n') if (cc == EOF) { type = TOKEN_EOF; return; } break; case '$': { symbol nm = read_escape_name(); if (!nm.is_null()) interpolate_arg(nm); break; } case '*': { symbol nm = read_escape_name(); if (!nm.is_null()) interpolate_string(nm); break; } case 'a': nd = new non_interpreted_char_node('\001'); type = TOKEN_NODE; return; case 'A': c = '0' + do_name_test(); type = TOKEN_CHAR; return; case 'b': nd = do_bracket(); type = TOKEN_NODE; return; case 'c': goto ESCAPE_c; case 'C': nm = get_delim_name(); if (nm.is_null()) break; type = TOKEN_SPECIAL; return; case 'd': type = TOKEN_NODE; nd = new vmotion_node(curenv->get_size()/2); return; case 'D': nd = read_draw_node(); if (!nd) break; type = TOKEN_NODE; return; case 'e': goto ESCAPE_e; case 'E': goto handle_escape_char; case 'f': { symbol s = read_escape_name(); if (s.is_null()) break; for (const char *p = s.contents(); *p != '\0'; p++) if (!csdigit(*p)) break; if (*p) curenv->set_font(s); else curenv->set_font(atoi(s.contents())); break; } case 'g': { symbol s = read_escape_name(); if (!s.is_null()) interpolate_number_format(s); break; } case 'h': if (!get_delim_number(&x, 'm')) break; type = TOKEN_NODE; nd = new hmotion_node(x); return; case 'H': if (get_delim_number(&x, 'z', curenv->get_requested_point_size())) curenv->set_char_height(x); break; case 'k': nm = read_escape_name(); if (nm.is_null()) break; type = TOKEN_MARK_INPUT; return; case 'l': case 'L': { charinfo *s = 0; if (!get_line_arg(&x, (cc == 'l' ? 'm': 'v'), &s)) break; if (s == 0) s = get_charinfo(cc == 'l' ? "ru" : "br"); type = TOKEN_NODE; node *n = curenv->make_char_node(s); if (cc == 'l') nd = new hline_node(x, n); else nd = new vline_node(x, n); return; } case 'n': { int inc; symbol nm = read_increment_and_escape_name(&inc); if (!nm.is_null()) interpolate_number_reg(nm, inc); break; } case 'N': if (!get_delim_number(&val, 0)) break; type = TOKEN_NUMBERED_CHAR; return; case 'o': nd = do_overstrike(); type = TOKEN_NODE; return; case 'p': type = TOKEN_SPREAD; return; case 'r': type = TOKEN_NODE; nd = new vmotion_node(-curenv->get_size()); return; case 'R': do_register(); break; case 's': if (read_size(&x)) curenv->set_size(x); break; case 'S': if (get_delim_number(&x, 0)) curenv->set_char_slant(x); break; case 't': type = TOKEN_NODE; nd = new non_interpreted_char_node('\t'); return; case 'u': type = TOKEN_NODE; nd = new vmotion_node(-curenv->get_size()/2); return; case 'v': if (!get_delim_number(&x, 'v')) break; type = TOKEN_NODE; nd = new vmotion_node(x); return; case 'V': { symbol nm = read_escape_name(); if (!nm.is_null()) interpolate_environment_variable(nm); break; } case 'w': do_width(); break; case 'x': if (!get_delim_number(&x, 'v')) break; type = TOKEN_NODE; nd = new extra_size_node(x); return; case 'X': nd = do_special(); if (!nd) break; type = TOKEN_NODE; return; case 'Y': { symbol s = read_escape_name(); if (s.is_null()) break; request_or_macro *p = lookup_request(s); macro *m = p->to_macro(); if (!m) { error("can't transparently throughput a request"); break; } nd = new special_node(*m); type = TOKEN_NODE; return; } case 'z': { next(); if (type == TOKEN_NODE) nd = new zero_width_node(nd); else { charinfo *ci = get_char(1); if (ci == 0) break; node *gn = curenv->make_char_node(ci); if (gn == 0) break; nd = new zero_width_node(gn); type = TOKEN_NODE; } return; } case 'Z': nd = do_zero_width(); if (nd == 0) break; type = TOKEN_NODE; return; case '{': goto ESCAPE_LEFT_BRACE; case '}': goto ESCAPE_RIGHT_BRACE; case '\n': break; case '[': if (!compatible_flag) { nm = read_long_escape_name(); if (nm.is_null()) break; type = TOKEN_SPECIAL; return; } goto handle_normal_char; default: if (cc != escape_char && cc != '.') warning(WARN_ESCAPE, "escape character ignored before %1", input_char_description(cc)); goto handle_normal_char; } } }}int token::operator==(const token &t){ if (type != t.type) return 0; switch(type) { case TOKEN_CHAR: return c == t.c; case TOKEN_SPECIAL: return nm == t.nm; case TOKEN_NUMBERED_CHAR: return val == t.val; default: return 1; }}int token::operator!=(const token &t){ return !(*this == t);}// is token a suitable delimiter (like ')?int token::delimiter(int err){ switch(type) { case TOKEN_CHAR: switch(c) { case '0': case '1': case '2': case '3': case '4': case '5': case '6': case '7': case '8': case '9': case '+': case '-': case '/': case '*': case '%': case '<': case '>': case '=': case '&': case ':': case '(': case ')': case '.': if (err) error("cannot use character `%1' as a starting delimiter", char(c)); return 0; default: return 1; } case TOKEN_NODE: case TOKEN_SPACE: case TOKEN_TAB: case TOKEN_NEWLINE: if (err) error("cannot use %1 as a starting delimiter", description()); return 0; default: return 1; }}const char *token::description(){ static char buf[4]; switch (type) { case TOKEN_BACKSPACE: return "a backspace character"; case TOKEN_CHAR: buf[0] = '`'; buf[1] = c; buf[2] = '\''; buf[3] = '\0'; return buf; case TOKEN_DUMMY: return "`\\&'"; case TOKEN_ESCAPE: return "`\\e'"; case TOKEN_HYPHEN_INDICATOR: return "`\\%'"; case TOKEN_INTERRUPT: return "`\\c'"; case TOKEN_ITALIC_CORRECTION: return "`\\/'"; case TOKEN_LEADER: return "a leader character"; case TOKEN_LEFT_BRACE: return "`\\{'"; case TOKEN_MARK_INPUT: return "`\\k'"; case TOKEN_NEWLINE: return "newline"; case TOKEN_NODE: return "a node"; case TOKEN_NUMBERED_CHAR: return "`\\N'"; case TOKEN_RIGHT_BRACE: return "`\\}'"; case TOKEN_SPACE: return "a space"; case TOKEN_SPECIAL: return "a special character"; case TOKEN_SPREAD: return "`\\p'"; case TOKEN_TAB: return "a tab character"; case TOKEN_TRANSPARENT: return "`\\!'"; case TOKEN_EOF: return "end of input"; default: break; } return "a magic token";}void skip_line(){ while (!tok.newline()) if (tok.eof()) return; else tok.next(); tok.next();}void compatible(){ int n; if (has_arg() && get_integer(&n)) compatible_flag = n != 0; else compatible_flag = 1; skip_line();}static void empty_name_warning(int required){ if (tok.newline() || tok.eof()) { if (required) warning(WARN_MISSING, "missing name"); } else if (tok.right_brace() || tok.tab()) { const char *start = tok.description(); do { tok.next(); } while (tok.space() || tok.right_brace() || tok.tab()); if (!tok.newline() && !tok.eof()) error("%1 is not allowed before an argument", start); else if (required) warning(WARN_MISSING, "missing name"); } else if (required) error("name expected (got %1)", tok.description()); else error("name expected (got %1): treated as missing", tok.description());}static void non_empty_name_warning(){ if (!tok.newline() && !tok.eof() && !tok.space() && !tok.tab() && !tok.right_brace() // We don't want to give a warning for .el\{ && !tok.left_brace()) error("%1 is not allowed in a name", tok.description());}symbol get_name(int required){ if (compatible_flag) { char buf[3]; tok.skip(); if ((buf[0] = tok.ch()) != 0) { tok.next(); if ((buf[1] = tok.ch()) != 0) { buf[2] = 0; tok.make_space(); } else non_empty_name_warning(); return symbol(buf); } else { empty_name_warning(required); return NULL_SYMBOL; } } else return get_long_name(required);}symbol get_long_name(int required){ while (tok.space()) tok.next(); char abuf[ABUF_SIZE]; char *buf = abuf; int buf_size = ABUF_SIZE; int i = 0; for (;;) { if (i + 1 > buf_size) { if (buf == abuf) { buf = new char [ABUF_SIZE*2]; memcpy(buf, abuf, buf_size); buf_size = ABUF_SIZE*2; } else { char *old_buf = buf; buf = new char[buf_size*2]; memcpy(buf, old_buf, buf_size); buf_size *= 2; a_delete old_buf; } } if ((buf[i] = tok.ch()) == 0) break; i++; tok.next(); } if (i == 0) { empty_name_warning(required); return NULL_SYMBOL; } non_empty_name_warning(); if (buf == abuf) return symbol(buf); else { symbol s(buf); a_delete buf; return s; }}NO_RETURN void exit_troff(){ exit_started = 1; topdiv->set_last_page(); if (!end_macro_name.is_null()) { spring_trap(end_macro_name); tok.next(); process_input_stack(); } curenv->final_break(); tok.next(); process_input_stack(); end_diversions(); done_end_macro = 1; topdiv->set_ejecting(); static unsigned char buf[2] = { LAST_PAGE_EJECTOR, '\0' }; input_stack::push(make_temp_iterator((char *)buf)); topdiv->space(topdiv->get_page_length(), 1); tok.next(); process_input_stack(); seen_last_page_ejector = 1; // should be set already topdiv->set_ejecting(); push_page_ejector(); topdiv->space(topdiv->get_page_length(), 1); tok.next(); process_input_stack(); // This will only happen if a trap-invoked macro starts a diversion, // or if vertical position traps have been disabled. cleanup_and_exit(0);}// This implements .ex. The input stack must be cleared before calling// exit_troff().void exit_request(){ input_stack::clear(); if (exit_started) tok.next(); else exit_troff();}void end_macro(){ end_macro_name = get_name(); skip_line();}void do_request(){ int saved_compatible_flag = compatible_flag; compatible_flag = 0; symbol nm = get_name(); if (nm.is_null()) skip_line(); else interpolate_macro(nm); compatible_flag = saved_compatible_flag;}inline int possibly_handle_first_page_transition(){ if (topdiv->before_first_page && curdiv == topdiv && !curenv->is_dummy()) { handle_first_page_transition(); return 1; } else return 0;}static int transparent_translate(int cc){ if (!illegal_input_char(cc)) { charinfo *ci = charset_table[cc]; switch (ci->get_special_translation(1)) { case charinfo::TRANSLATE_SPACE: return ' '; case charinfo::TRANSLATE_DUMMY: return ESCAPE_AMPERSAND; case charinfo::TRANSLATE_HYPHEN_INDICATOR: return ESCAPE_PERCENT; } // This is realy ugly. ci = ci->get_translation(1); if (ci) { int c = ci->get_ascii_code(); if (c != '\0') return c; error("can't translate %1 to special character `%2'" " in transparent throughput", input_char_description(cc), ci->nm.contents()); } } return cc;}class int_stack { struct int_stack_element { int n; int_stack_element *next; } *top;public: int_stack(); ~int_stack(); void push(int); int is_empty(); int pop();};int_stack::int_stack(){ top = 0;}int_stack::~int_stack(){ while (top != 0) { int_stack_element *temp = top; top = top->next; delete temp; } }int int_stack::is_empty(){ return top == 0;}void int_stack::push(int n){ int_stack_element *p = new int_stack_element; p->next = top; p->n = n; top = p;}int int_stack::pop(){ assert(top != 0); int_stack_element *p = top; top = top->next; int n = p->n; delete p; return n;}int node::reread(int *){ return 0;}int diverted_space_node::reread(int *bolp){ if (curenv->get_fill()) blank_line(); else curdiv->space(n); *bolp = 1; return 1;}int diverted_copy_file_node::reread(int *bolp){ curdiv->copy_file(filename.contents()); *bolp = 1; return 1;}static void process_input_stack(){ int_stack trap_bol_stack; int bol = 1; for (;;) { int suppress_next = 0; switch (tok.type) { case token::TOKEN_CHAR:
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -