📄 lexert.cc
字号:
// -*- c-basic-offset: 4 -*-/* * lexert.{cc,hh} -- configuration file parser for tools * Eddie Kohler * * Copyright (c) 1999-2000 Massachusetts Institute of Technology * Copyright (c) 2000 Mazu Networks, Inc. * Copyright (c) 2001-2003 International Computer Science Institute * Copyright (c) 2004-2007 Regents of the University of California * Copyright (c) 2008 Meraki, Inc. * * Permission is hereby granted, free of charge, to any person obtaining a * copy of this software and associated documentation files (the "Software"), * to deal in the Software without restriction, subject to the conditions * listed in the Click LICENSE file. These conditions include: you must * preserve this copyright notice, and you cannot mention the copyright * holders in advertising related to the Software without their permission. * The Software is provided WITHOUT ANY WARRANTY, EXPRESS OR IMPLIED. This * notice is a summary of the Click LICENSE file; the license in that file is * legally binding. */#include <click/config.h>#include "lexert.hh"#include "lexertinfo.hh"#include "routert.hh"#include <click/confparse.hh>#include <ctype.h>#include <stdlib.h>#include <string.h>static LexerTInfo *stub_lexinfo = 0;LexerT::LexerT(ErrorHandler *errh, bool ignore_line_directives) : _data(0), _end(0), _pos(0), _lineno(1), _lset(0), _ignore_line_directives(ignore_line_directives), _tpos(0), _tfull(0), _router(0), _base_type_map(0), _errh(errh){ if (!_errh) _errh = ErrorHandler::default_handler(); if (!stub_lexinfo) stub_lexinfo = new LexerTInfo; _lexinfo = stub_lexinfo; clear();}LexerT::~LexerT(){ clear(); _router->unuse(); _lset->unref();}voidLexerT::reset(const String &data, const Vector<ArchiveElement> &archive, const String &filename){ clear(); _big_string = data; _data = _pos = _big_string.begin(); _end = _big_string.end(); _original_filename = _filename = filename; _lineno = 1; _lset->new_line(0, _filename, _lineno); // provide archive elements for (int i = 0; i < archive.size(); i++) if (archive[i].live() && archive[i].name != "config") _router->add_archive(archive[i]);}voidLexerT::clear(){ if (_router) _router->unuse(); if (_lset) _lset->unref(); _router = new RouterT(); _router->use(); // hold a reference to the router _lset = new LandmarkSetT(); _big_string = ""; // _data was freed by _big_string _data = 0; _end = 0; _pos = 0; _filename = ""; _lineno = 0; _tpos = 0; _tfull = 0; _base_type_map.clear(); _anonymous_offset = 0; _anonymous_class_count = 0;}voidLexerT::set_lexinfo(LexerTInfo *li){ _lexinfo = (li ? li : stub_lexinfo);}// LEXING: LOWEST LEVELStringLexerT::remaining_text() const{ return _big_string.substring(_pos, _end);}voidLexerT::set_remaining_text(const String &s){ _big_string = s; _data = _pos = s.begin(); _end = s.end();}const char *LexerT::skip_line(const char *s){ _lineno++; for (; s < _end; s++) if (*s == '\n') return s + 1; else if (*s == '\r') { if (s + 1 < _end && s[1] == '\n') return s + 2; else return s + 1; } _lineno--; return s;}const char *LexerT::skip_slash_star(const char *s){ for (; s < _end; s++) if (*s == '\n') _lineno++; else if (*s == '\r') { if (s + 1 < _end && s[1] == '\n') s++; _lineno++; } else if (*s == '*' && s + 1 < _end && s[1] == '/') return s + 2; return _end;}const char *LexerT::skip_backslash_angle(const char *s){ for (; s < _end; s++) if (*s == '\n') _lineno++; else if (*s == '\r') { if (s + 1 < _end && s[1] == '\n') s++; _lineno++; } else if (*s == '/' && s + 1 < _end) { if (s[1] == '/') s = skip_line(s + 2) - 1; else if (s[1] == '*') s = skip_slash_star(s + 2) - 1; } else if (*s == '>') return s + 1; return _end;}const char *LexerT::skip_quote(const char *s, char endc){ for (; s < _end; s++) if (*s == '\n') _lineno++; else if (*s == '\r') { if (s + 1 < _end && s[1] == '\n') s++; _lineno++; } else if (*s == '\\' && endc == '\"' && s + 1 < _end) { if (s[1] == '<') s = skip_backslash_angle(s + 2) - 1; else if (s[1] == '\"') s++; } else if (*s == endc) return s + 1; return _end;}const char *LexerT::process_line_directive(const char *s){ const char *first_pos = s; for (s++; s < _end && (*s == ' ' || *s == '\t'); s++) /* nada */; if (s + 4 < _end && *s == 'l' && s[1] == 'i' && s[2] == 'n' && s[3] == 'e' && (s[4] == ' ' || s[4] == '\t')) { for (s += 5; s < _end && (*s == ' ' || *s == '\t'); s++) /* nada */; } if (s >= _end || !isdigit((unsigned char) *s)) { // complain about bad directive lerror(first_pos, s, "unknown preprocessor directive"); return skip_line(s); } else if (_ignore_line_directives) return skip_line(s); // parse line number for (_lineno = 0; s < _end && isdigit((unsigned char) *s); s++) _lineno = _lineno * 10 + *s - '0'; _lineno--; // account for extra line for (; s < _end && (*s == ' ' || *s == '\t'); s++) /* nada */; if (s < _end && *s == '\"') { // parse filename const char *first_in_filename = s; for (s++; s < _end && *s != '\"' && *s != '\n' && *s != '\r'; s++) if (*s == '\\' && s + 1 < _end && s[1] != '\n' && s[1] != '\r') s++; _filename = cp_unquote(_big_string.substring(first_in_filename, s) + "\""); // an empty filename means return to the input file's name if (_filename == "") _filename = _original_filename; } // reach end of line for (; s < _end && *s != '\n' && *s != '\r'; s++) /* nada */; if (s + 1 < _end && *s == '\r' && s[1] == '\n') s++; return s;}LexemeLexerT::next_lexeme(){ const char *s = _pos; while (true) { while (s < _end && isspace((unsigned char) *s)) { if (*s == '\n') { _lineno++; _lset->new_line(s + 1 - _big_string.begin(), _filename, _lineno); } else if (*s == '\r') { if (s + 1 < _end && s[1] == '\n') s++; _lineno++; _lset->new_line(s + 1 - _big_string.begin(), _filename, _lineno); } s++; } const char *opos = s; if (s >= _end) { _pos = _end; return Lexeme(lexEOF, String(), _pos); } else if (*s == '/' && s + 1 < _end) { if (s[1] == '/') s = skip_line(s + 2); else if (s[1] == '*') s = skip_slash_star(s + 2); else break; _lexinfo->notify_comment(opos, s); } else if (*s == '#' && (s == _data || s[-1] == '\n' || s[-1] == '\r')) { s = process_line_directive(s); _lexinfo->notify_line_directive(opos, s); } else break; } const char *word_pos = s; // find length of current word if (isalnum((unsigned char) *s) || *s == '_' || *s == '@') { more_word_characters: s++; while (s < _end && (isalnum((unsigned char) *s) || *s == '_' || *s == '@')) s++; if (s + 1 < _end && *s == '/' && (isalnum((unsigned char) s[1]) || s[1] == '_' || s[1] == '@')) goto more_word_characters; _pos = s; String word = _big_string.substring(word_pos, s); if (word.equals("elementclass", 12)) { _lexinfo->notify_keyword(word, word_pos, s); return Lexeme(lexElementclass, word, word_pos); } else if (word.equals("require", 7)) { _lexinfo->notify_keyword(word, word_pos, s); return Lexeme(lexRequire, word, word_pos); } else if (word.equals("define", 6)) { _lexinfo->notify_keyword(word, word_pos, s); return Lexeme(lexDefine, word, word_pos); } else return Lexeme(lexIdent, word, word_pos); } // check for variable if (*s == '$') { s++; while (s < _end && (isalnum((unsigned char) *s) || *s == '_')) s++; if (s > word_pos + 1) { _pos = s; return Lexeme(lexVariable, _big_string.substring(word_pos + 1, s), word_pos); } else s--; } if (s + 1 < _end) { if (*s == '-' && s[1] == '>') { _pos = s + 2; return Lexeme(lexArrow, _big_string.substring(s, s + 2), word_pos); } else if (*s == ':' && s[1] == ':') { _pos = s + 2; return Lexeme(lex2Colon, _big_string.substring(s, s + 2), word_pos); } else if (*s == '|' && s[1] == '|') { _pos = s + 2; return Lexeme(lex2Bar, _big_string.substring(s, s + 2), word_pos); } } if (s + 2 < _end && *s == '.' && s[1] == '.' && s[2] == '.') { _pos = s + 3; return Lexeme(lex3Dot, _big_string.substring(s, s + 3), word_pos); } _pos = s + 1; return Lexeme(*s, _big_string.substring(s, s + 1), word_pos);}LexemeLexerT::lex_config(){ const char *config_pos = _pos; const char *s = _pos; unsigned paren_depth = 1; for (; s < _end; s++) if (*s == '(') paren_depth++; else if (*s == ')') { paren_depth--; if (!paren_depth) break; } else if (*s == '\n') { _lineno++; _lset->new_line(s + 1 - _big_string.begin(), _filename, _lineno); } else if (*s == '\r') { if (s + 1 < _end && s[1] == '\n') s++; _lineno++; _lset->new_line(s + 1 - _big_string.begin(), _filename, _lineno); } else if (*s == '/' && s + 1 < _end) { if (s[1] == '/') s = skip_line(s + 2) - 1; else if (s[1] == '*') s = skip_slash_star(s + 2) - 1; } else if (*s == '\'' || *s == '\"') s = skip_quote(s + 1, *s) - 1; else if (*s == '\\' && s + 1 < _end && s[1] == '<') s = skip_backslash_angle(s + 2) - 1; _pos = s; _lexinfo->notify_config_string(config_pos, s); return Lexeme(lexConfig, _big_string.substring(config_pos, s), config_pos);}StringLexerT::lexeme_string(int kind){ char buf[14]; if (kind == lexIdent) return String::make_stable("identifier", 10); else if (kind == lexVariable) return String::make_stable("variable", 8); else if (kind == lexArrow) return String::make_stable("'->'", 4); else if (kind == lex2Colon) return String::make_stable("'::'", 4); else if (kind == lex2Bar) return String::make_stable("'||'", 4); else if (kind == lex3Dot) return String::make_stable("'...'", 5); else if (kind == lexElementclass) return String::make_stable("'elementclass'", 14); else if (kind == lexRequire) return String::make_stable("'require'", 9); else if (kind == lexDefine) return String::make_stable("'define'", 8); else if (kind >= 32 && kind < 127) { sprintf(buf, "'%c'", kind); return buf; } else { sprintf(buf, "'\\%03d'", kind); return buf; }}// LEXING: MIDDLE LEVEL (WITH PUSHBACK)const Lexeme &LexerT::lex(){ int p = _tpos; if (_tpos == _tfull) { _tcircle[p] = next_lexeme(); _tfull = (_tfull + 1) % TCIRCLE_SIZE; } _tpos = (_tpos + 1) % TCIRCLE_SIZE; return _tcircle[p];}voidLexerT::unlex(const Lexeme &t){ _tpos = (_tpos + TCIRCLE_SIZE - 1) % TCIRCLE_SIZE; _tcircle[_tpos] = t; assert(_tfull != _tpos);}boolLexerT::expect(int kind, bool report_error){ // Never adds anything to '_tcircle'. This requires a nonobvious // implementation. if (_tpos != _tfull) { if (_tcircle[_tpos].is(kind)) { _tpos = (_tpos + 1) % TCIRCLE_SIZE; return true; } if (report_error) lerror(_tcircle[_tpos], "expected %s", lexeme_string(kind).c_str()); } else { String old_filename = _filename; unsigned old_lineno = _lineno; const char *old_pos = _pos; if (next_lexeme().is(kind)) return true; _filename = old_filename; _lineno = old_lineno; if (report_error) lerror(old_pos, _pos, "expected %s", lexeme_string(kind).c_str()); _pos = old_pos; } return false;}const char *LexerT::next_pos() const{ if (_tpos != _tfull) return _tcircle[_tpos].pos1(); else return _pos;}// ERRORSStringLexerT::landmark() const{ if (_filename && _filename.back() != ':' && !isspace((unsigned char) _filename.back())) return _filename + ":" + String(_lineno); else return _filename + String(_lineno);}voidLexerT::vlerror(const char *pos1, const char *pos2, const String &lm, const char *fmt, va_list val){ String text = _errh->vformat(fmt, val); _lexinfo->notify_error(text, pos1, pos2); _errh->xmessage(lm, ErrorHandler::e_error, text);}intLexerT::lerror(const char *pos1, const char *pos2, const char *format, ...){ va_list val; va_start(val, format); vlerror(pos1, pos2, landmark(), format, val); va_end(val); return -1;}intLexerT::lerror(const Lexeme &t, const char *format, ...){ va_list val; va_start(val, format); vlerror(t.pos1(), t.pos2(), landmark(), format, val); va_end(val); return -1;}// ELEMENT TYPESElementClassT *LexerT::element_type(const Lexeme &t) const{ assert(t.is(lexIdent)); String name = t.string(); ElementClassT *type = _router->declared_type(name); if (!type) type = _base_type_map[name]; if (type) _lexinfo->notify_class_reference(type, t.pos1(), t.pos2()); return type;}ElementClassT *LexerT::force_element_type(const Lexeme &t){ assert(t.is(lexIdent)); String name = t.string(); ElementClassT *type = _router->declared_type(name); if (!type) type = _base_type_map.get(name); if (!type) { if (_router->eindex(name) >= 0) lerror(t, "%<%s%> was previously used as an element name", name.c_str()); type = ElementClassT::base_type(name); _base_type_map.set(name, type); } _lexinfo->notify_class_reference(type, t.pos1(), t.pos2()); return type;}// ELEMENTSStringLexerT::anon_element_name(const String &class_name) const{ int anonymizer = _router->nelements() - _anonymous_offset + 1; return ";" + class_name + "@" + String(anonymizer);}intLexerT::make_element(String name, const Lexeme &location, const char *decl_pos2, ElementClassT *type, const String &conf){ // check 'name' for validity for (int i = 0; i < name.length(); i++) { bool ok = false; for (; i < name.length() && name[i] != '/'; i++) if (!isdigit((unsigned char) name[i])) ok = true; if (!ok) {
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -