├── AST └── AST.png ├── demo.css ├── Makefile ├── t2CSSAST.h ├── README.md ├── main.cpp ├── Flex-8-CSS2.l ├── t2CSSNode.h └── Bison-5-CSS2.y /AST/AST.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/BentleyBlanks/t2CSSPareser/HEAD/AST/AST.png -------------------------------------------------------------------------------- /demo.css: -------------------------------------------------------------------------------- 1 | /* 存在可能为class = "font-face a" */ 2 | head.font-face.a .b:hover, #ahs{ 3 | background: #00FF00; 4 | src: 222; 5 | } 6 | 7 | .body { 8 | font-family: 'Raleway', Arial, sans-serif; 9 | /*text-rendering: optimizeLegibility;*/ 10 | margin: 1, 2, 3, 4; 11 | } 12 | 13 | 14 | /*.demo-4 a:hover, 15 | .demo-4 a:focus { 16 | color: #7b8d92; 17 | } 18 | 19 | .media .screen{ 20 | display: none; 21 | font-size: 80; 22 | } 23 | 24 | .foo.bar, .baz { 25 | left: 10; 26 | width: 100; 27 | background-color: red; 28 | } */ -------------------------------------------------------------------------------- /Makefile: -------------------------------------------------------------------------------- 1 | # -o指定生成的输出文件 2 | # $@代表当前Makefile taget的名称 这里直接作为可执行文件名 3 | # FlexBison-3: Flex-3.l Bison-3.y 4 | # bison -d Bison-3.y 5 | # flex Flex-3.l 6 | # cc -o $@ Bison-3.tab.c lex.yy.c 7 | 8 | # t2CSS: 9 | # Flex-6-CSS2.l Bison-3.y 10 | # bison -d Bison-4-CSS2.y 11 | # flex -o t2CSSLex.c Flex-6-CSS2.l 12 | # cc -o $@ t2CSSLex.c 13 | 14 | cssParser: main.cpp t2CSSLex.o t2CSSBison.cpp 15 | g++ -o $@ $^ 16 | 17 | t2CSSBison.cpp t2CSSBison.hpp: Bison-5-CSS2.y 18 | bison -d -o $@ $< 19 | 20 | t2CSSLex.o: t2CSSLex.cpp t2CSSBison.hpp 21 | g++ -c -o $@ $< 22 | 23 | t2CSSLex.cpp: Flex-8-CSS2.l 24 | flex -o $@ $< 25 | 26 | clean: 27 | rm -f t2CSSBison.hpp t2CSSBison.cpp 28 | rm -f t2CSSLex.h t2CSSLex.cpp t2CSSLex.o 29 | rm -f cssParser 30 | 31 | # t2CSSParser.cpp: Bison-4-CSS2.y 32 | # bison -d -o $@ $^ 33 | 34 | # t2CSSLex.cpp: Flex-6-CSS2.l t2CSSParser.hpp 35 | # flex -o t2CSSLex.cpp 36 | 37 | # cssParser: 38 | # g++ -o $@ t2CSSParser.cpp t2CSSLex.cpp main.cpp 39 | 40 | -------------------------------------------------------------------------------- /t2CSSAST.h: -------------------------------------------------------------------------------- 1 | #ifndef T2_CSSAST_H 2 | #define T2_CSSAST_H 3 | 4 | #include 5 | #include 6 | #include "t2CSSBison.hpp" 7 | #include "t2CSSLex.h" 8 | 9 | #include "t2CSSNode.h" 10 | 11 | class t2CSSAST 12 | { 13 | public: 14 | t2CSSAST() :root(NULL) {} 15 | 16 | yyscan_t scaninfo; 17 | 18 | t2CSSNode* root; 19 | 20 | void printAsDot() { printAsDot(root); } 21 | 22 | void traversal() { traversal(root); } 23 | 24 | void traversalAsDot() { traversalAsDot(root); } 25 | 26 | protected: 27 | void printAsDot(t2CSSNode* root) 28 | { 29 | traversal(root); 30 | 31 | printf("\n--------------------Graphviz--------------------\n"); 32 | 33 | printf("digraph G {\n"); 34 | printf("node[shape=rect]\n"); 35 | 36 | traversalAsDot(root); 37 | 38 | printf("}\n"); 39 | 40 | printf("------------------------------------------------\n"); 41 | } 42 | 43 | void traversal(t2CSSNode* root) 44 | { 45 | if(!root) return; 46 | 47 | t2CSSNode *l = root->leftChild(); 48 | t2CSSNode *r = root->rightChild(); 49 | 50 | traversal(l); 51 | root->node(); 52 | traversal(r); 53 | } 54 | 55 | void traversalAsDot(t2CSSNode* root) 56 | { 57 | if(!root) return; 58 | 59 | printf("_%p[label=%s]\n", root, root->nodeName.c_str()); 60 | 61 | t2CSSNode *l = root->leftChild(); 62 | t2CSSNode *r = root->rightChild(); 63 | 64 | if(l != NULL) printf("_%p -> _%p\n", root, l); 65 | if(r != NULL) printf("_%p -> _%p\n", root, r); 66 | 67 | traversalAsDot(l); 68 | traversalAsDot(r); 69 | } 70 | }; 71 | 72 | #endif 73 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # t2CSSPareser 2 | 3 | 使用Flex+Bison完成CSS词法分析与语法分析工作,具体BNF是参考[W3C](http://www.w3.org/TR/CSS21/grammar.html)中CSS2.0标准实现(实现了部分CSS3.0)。 4 | 5 | 感谢[tang3w](http://tang3w.com/2015/02/01/%E4%BD%BF%E7%94%A8-lemon-%E5%AE%9E%E7%8E%B0-css-%E8%AF%AD%E6%B3%95%E5%88%86%E6%9E%90%E5%99%A8.html)给出了使用Flex+Lemon的简易CSS解析器实现,以及其推荐的[可视化AST](http://tang3w.com/2015/02/01/%E6%8A%BD%E8%B1%A1%E8%AF%AD%E6%B3%95%E6%A0%91%E7%9A%84%E5%8F%AF%E8%A7%86%E5%8C%96.html)的实现方法。 6 | 7 | ## 依赖项说明 8 | 1.[Flex](http://flex.sourceforge.net/) 2.5.35 9 | 10 | 2.[Bison](https://www.gnu.org/software/bison/) 2.4.1 11 | 12 | (Windows版本可以使用[MinGW](http://www.mingw.org/),OSX为自带) 13 | 14 | 3.[Graphviz](http://www.graphviz.org/)(可选),用于可视化生成AST树 15 | 16 | ## 构建说明 17 | 1.自带Makefile,自带demo.css无需其他平台依赖项 18 | 19 | 2.不使用g++ 而使用Visual Studio编译时可能会遇到```unistd.h```无法找到的问题,目前的解决方案可以是直接在VS的include目录下添加 20 | 21 | 具体操作可以参见[在VC下如何使用头文件unistd.h](http://weilihero.blog.163.com/blog/static/13411039520109218831848/) 22 | 23 | ## 使用说明 24 | 1.目前支持CSS2.0大部分特性,正如demo.css中显示的 25 | 26 | 2.所有数值不带单位,例如 27 | ```css 28 | /* 已知错误 */ 29 | font-size: 80; 30 | /* font-size: 80px; */ 31 | 32 | ``` 33 | 此处一旦数值带有单位将会发生```不可预测错误```。 34 | 35 | 3.AST基本数据类型已经在```t2CSSNode.hpp```中显示,其中可视化AST可以调用```printAsDot()```方法。 36 | 37 | 4.目前语法错误无法检测具体错误类型,只能显示```Error: syntax error.```。 38 | 39 | 5.目前规则不能为空,例如 40 | ```css 41 | /* Syntax error */ 42 | hello.a{} 43 | ``` 44 | 6.目前最后一个选择器后建议不加空格 45 | ```css 46 | /* Unsupported */ 47 | .haha {} 48 | 49 | /* supported */ 50 | .haha{} 51 | ``` 52 | 原因是生成的AST会认为```.haha```之后还有一个selector(紧跟的空格引起),因此外部需要额外的解析工作来消除这一影响,但不影响正常解析。 53 | 54 | 在t2CSSParser中会被认为有语法错误,目前的解决办法是手工直接删除空规则,等待版本。 55 | 56 | 7.不支持类```function```的写法,如```color: rgba(...);```等 57 | 58 | 59 | ## 可视化AST 60 | 此为给出的demo.css生成的AST具体样式 61 | ![AST](https://raw.githubusercontent.com/BentleyBlanks/t2CSSPareser/master/AST/AST.png) 62 | 63 | 64 | ## 关于作者 65 | ```cpp 66 | int 官某某 = "Bingo"; 67 | 68 | char[] 个人博客 = "http://bentleyblanks.github.io"; 69 | ``` 70 | -------------------------------------------------------------------------------- /main.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include "t2CSSBison.hpp" 6 | #include "t2CSSLex.h" 7 | #include "t2CSSAST.h" 8 | 9 | extern int yyparse(t2CSSAST* parser); 10 | 11 | void printAsDot(t2CSSNode* root); 12 | 13 | void traversal(t2CSSNode* root); 14 | 15 | void traversalAsDot(t2CSSNode* root); 16 | 17 | void yyerror(const char *s) 18 | { 19 | // va_list ap; 20 | // va_start(ap, s); 21 | 22 | // fprintf(stderr, "%d: error: ", yyget_lineno(parser->scaninfo)); 23 | // vfprintf(stderr, s, ap); 24 | // fprintf(stderr, "\n"); 25 | printf("Error: %s", s); 26 | } 27 | 28 | int main(int argc, char **argv) 29 | { 30 | t2CSSAST* parser = new t2CSSAST(); 31 | 32 | if(yylex_init_extra(parser, &parser->scaninfo)){ 33 | perror("Inti alloc failed"); 34 | return 1; 35 | } 36 | 37 | FILE *f = fopen("./demo.css", "r"); 38 | 39 | /* 文件打开失败 */ 40 | if(!f){ 41 | printf("打开文件失败\n"); 42 | return 0; 43 | } 44 | 45 | printf("------------------------------\n"); 46 | 47 | //YY_BUFFER_STATE bs = yy_create_buffer(f, YY_BUF_SIZE); 48 | //yy_switch_to_buffer(bs); 49 | 50 | yyset_in(f, parser->scaninfo); 51 | 52 | //while(yylex()); 53 | 54 | //yylex(parser->scaninfo); 55 | 56 | yyparse(parser); 57 | 58 | printAsDot(parser->root); 59 | 60 | fclose(f); 61 | 62 | return 0; 63 | } 64 | 65 | void printAsDot(t2CSSNode* root) 66 | { 67 | traversal(root); 68 | 69 | printf("\n--------------------Graphviz--------------------\n"); 70 | 71 | printf("digraph G {\n"); 72 | printf("node[shape=rect]\n"); 73 | 74 | traversalAsDot(root); 75 | 76 | printf("}\n"); 77 | 78 | printf("------------------------------------------------\n"); 79 | } 80 | 81 | void traversal(t2CSSNode* root) 82 | { 83 | if(!root) return; 84 | 85 | t2CSSNode *l = root->leftChild(); 86 | t2CSSNode *r = root->rightChild(); 87 | 88 | traversal(l); 89 | root->node(); 90 | traversal(r); 91 | } 92 | 93 | void traversalAsDot(t2CSSNode* root) 94 | { 95 | if(!root) return; 96 | 97 | printf("_%p[label=%s]\n", root, root->nodeName.c_str()); 98 | 99 | t2CSSNode *l = root->leftChild(); 100 | t2CSSNode *r = root->rightChild(); 101 | 102 | if (l != NULL) printf("_%p -> _%p\n", root, l); 103 | if (r != NULL) printf("_%p -> _%p\n", root, r); 104 | 105 | traversalAsDot(l); 106 | traversalAsDot(r); 107 | } -------------------------------------------------------------------------------- /Flex-8-CSS2.l: -------------------------------------------------------------------------------- 1 | %{ 2 | /* http://www.w3.org/TR/2003/WD-css3-syntax-20030813/#detailed-grammar */ 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include "t2CSSBison.hpp" 9 | /* #include "t2CSSAST.h" */ 10 | 11 | #define t2Token yylval->token 12 | /* 额外传入的parser带有Flex需要的yyscan_t信息 */ 13 | /* yytext->yyget_text(yyscan_t) yyleng->yyget_leng(yyscan_t) */ 14 | #define t2SaveTokenString yylval->string = new std::string(yytext, yyleng) 15 | #define t2SaveTokenNumber yylval->number = atof(std::string(yytext, yyleng).c_str()) 16 | 17 | /* void t2Log(const char* string, ...){ 18 | va_list args; 19 | va_start(args, string); 20 | vprintf(string, args); 21 | va_end(args); 22 | } */ 23 | 24 | /* int yylex(YYSTYPE * yylval_param, yyscan_t* scan_t); */ 25 | %} 26 | 27 | /* 前缀可同时使用自定义前缀以及yy */ 28 | /* Flex额外参数的具体类型 在yylex_init_extra时可使用到 */ 29 | %option noyywrap 30 | %option case-insensitive 31 | %option header-file="t2CSSLex.h" 32 | %option reentrant 33 | %option bison-bridge 34 | %option extra-type = "class t2CSSAST*" 35 | 36 | %s mediaquery 37 | %s forkeyword 38 | 39 | h [0-9a-fA-F] 40 | 41 | nonascii [\200-\377] 42 | 43 | unicode \\{h}{1,6}[ \t\r\n\f]? 44 | 45 | escape {unicode}|\\[ -~\200-\377] 46 | 47 | nmstart [_a-zA-Z]|{nonascii}|{escape} 48 | 49 | nmchar [_a-zA-Z0-9-]|{nonascii}|{escape} 50 | 51 | string1 \"([\t !#$%&(-~]|\\{nl}|\'|{nonascii}|{escape})*\" 52 | 53 | string2 \'([\t !#$%&(-~]|\\{nl}|\"|{nonascii}|{escape})*\' 54 | 55 | 56 | ident -?{nmstart}{nmchar}* 57 | 58 | num [0-9]+|[0-9]*"."[0-9]+ 59 | 60 | intnum [0-9]+ 61 | 62 | string {string1}|{string2} 63 | 64 | url ([!#$%&*-~]|{nonascii}|{escape})* 65 | 66 | w [ \t\r\n\f]* 67 | 68 | nl \n|\r\n|\r|\f 69 | 70 | range \?{1,6}|{h}(\?{0,5}|{h}(\?{0,4}|{h}(\?{0,3}|{h}(\?{0,2}|{h}(\??|{h}))))) 71 | 72 | nth [\+-]?{intnum}*n([\t\r\n ]*[\+-][\t\r\n ]*{intnum})? 73 | 74 | %% 75 | 76 | %{ 77 | class t2CSSAST* parser = yyextra; 78 | %} 79 | 80 | \/\*[^*]*\*+([^/*][^*]*\*+)*\/ {/* ignore comments */ } 81 | 82 | [ \t\r\n\f]+ { t2Token = WHITESPACE; return t2Token; } 83 | 84 | "" { t2Token = SGML_CD; return t2Token; } 87 | 88 | "~=" { t2Token = INCLUDES; return t2Token; } 89 | 90 | "|=" { t2Token = DASHMATCH; return t2Token; } 91 | 92 | "^=" { t2Token = BEGINSWITH; return t2Token; } 93 | 94 | "$=" { t2Token = ENDSWITH; return t2Token; } 95 | 96 | "*=" { t2Token = CONTAINS; return t2Token; } 97 | 98 | "not" { t2Token = MEDIA_NOT; return t2Token; } 99 | 100 | "only" { t2Token = MEDIA_ONLY; return t2Token; } 101 | 102 | "and" { t2Token = MEDIA_AND; return t2Token; } 103 | 104 | 105 | {string} { t2SaveTokenString; return STRING; } 106 | 107 | {ident} { t2SaveTokenString; return IDENT; } 108 | 109 | {nth} { t2SaveTokenString; return NTH; } 110 | 111 | 112 | "#"{h}+ { t2SaveTokenString; return HEX; } 113 | 114 | "#"{ident} { t2SaveTokenString; return IDSEL; } 115 | 116 | "@import" {BEGIN(mediaquery); t2Token = IMPORT_SYM; return t2Token; } 117 | 118 | "@page" { t2Token = PAGE_SYM; return t2Token; } 119 | 120 | "@top-left-corner" { t2Token = TOPLEFTCORNER_SYM; return t2Token; } 121 | 122 | "@top-left" { t2Token = TOPLEFT_SYM; return t2Token; } 123 | 124 | "@top-center" { t2Token = TOPCENTER_SYM; return t2Token; } 125 | 126 | "@top-right" { t2Token = TOPRIGHT_SYM; return t2Token; } 127 | 128 | "@top-right-corner" { t2Token = TOPRIGHTCORNER_SYM; return t2Token; } 129 | 130 | "@bottom-left-corner" { t2Token = BOTTOMLEFTCORNER_SYM; return t2Token; } 131 | 132 | "@bottom-left" { t2Token = BOTTOMLEFT_SYM; return t2Token; } 133 | 134 | "@bottom-center" { t2Token = BOTTOMCENTER_SYM; return t2Token; } 135 | 136 | "@bottom-right" { t2Token = BOTTOMRIGHT_SYM; return t2Token; } 137 | 138 | "@bottom-right-corner" { t2Token = BOTTOMRIGHTCORNER_SYM; return t2Token; } 139 | 140 | "@left-top" { t2Token = LEFTTOP_SYM; return t2Token; } 141 | 142 | "@left-middle" { t2Token = LEFTMIDDLE_SYM; return t2Token; } 143 | 144 | "@left-bottom" { t2Token = LEFTBOTTOM_SYM; return t2Token; } 145 | 146 | "@right-top" { t2Token = RIGHTTOP_SYM; return t2Token; } 147 | 148 | "@right-middle" { t2Token = RIGHTMIDDLE_SYM; return t2Token; } 149 | 150 | "@right-bottom" { t2Token = RIGHTBOTTOM_SYM; return t2Token; } 151 | 152 | "@media" {BEGIN(mediaquery); t2Token = MEDIA_SYM; return t2Token; } 153 | 154 | "@font-face" { t2Token = FONT_FACE_SYM; return t2Token; } 155 | 156 | "@charset" { t2Token = CHARSET_SYM; return t2Token; } 157 | 158 | "@namespace" { t2Token = NAMESPACE_SYM; return t2Token; } 159 | 160 | "@-webkit-rule" { t2Token = WEBKIT_RULE_SYM; return t2Token; } 161 | 162 | "@-webkit-decls" { t2Token = WEBKIT_DECLS_SYM; return t2Token; } 163 | 164 | "@-webkit-value" { t2Token = WEBKIT_VALUE_SYM; return t2Token; } 165 | 166 | "@-webkit-mediaquery" {BEGIN(mediaquery); t2Token = WEBKIT_MEDIAQUERY_SYM; return t2Token; } 167 | 168 | "@-webkit-selector" { t2Token = WEBKIT_SELECTOR_SYM; return t2Token; } 169 | 170 | "@-webkit-keyframes" { t2Token = WEBKIT_KEYFRAMES_SYM; return t2Token; } 171 | 172 | "@-webkit-keyframe-rule" { t2Token = WEBKIT_KEYFRAME_RULE_SYM; return t2Token; } 173 | 174 | "@"{ident} { t2Token = ATKEYWORD; return t2Token; } 175 | 176 | "!"{w}"important" { t2Token = IMPORTANT_SYM; return t2Token; } 177 | 178 | {num}em { t2Token = EMS; return t2Token; } 179 | 180 | {num}rem { t2Token = REMS; return t2Token; } 181 | 182 | {num}__qem { t2Token = QEMS; return t2Token; } 183 | 184 | {num}ex { t2Token = EXS; return t2Token; } 185 | 186 | {num}px { t2Token = PXS; return t2Token; } 187 | 188 | {num}cm { t2Token = CMS; return t2Token; } 189 | 190 | {num}mm { t2Token = MMS; return t2Token; } 191 | 192 | {num}in { t2Token = INS; return t2Token; } 193 | 194 | {num}pt { t2Token = PTS; return t2Token; } 195 | 196 | {num}pc { t2Token = PCS; return t2Token; } 197 | 198 | {num}deg { t2Token = DEGS; return t2Token; } 199 | 200 | {num}rad { t2Token = RADS; return t2Token; } 201 | 202 | {num}grad { t2Token = GRADS; return t2Token; } 203 | 204 | {num}turn { t2Token = TURNS; return t2Token; } 205 | 206 | {num}ms { t2Token = MSECS; return t2Token; } 207 | 208 | {num}s { t2Token = SECS; return t2Token; } 209 | 210 | {num}Hz { t2Token = HERTZ; return t2Token; } 211 | 212 | {num}kHz { t2Token = KHERTZ; return t2Token; } 213 | 214 | {num}{ident} { t2Token = DIMEN; return t2Token; } 215 | 216 | {num}{ident}\+ { t2Token = INVALIDDIMEN; return t2Token; } 217 | 218 | {num}%+ { t2Token = PERCENTAGE; return t2Token; } 219 | 220 | 221 | {intnum} { t2SaveTokenNumber; return INTEGER; } 222 | 223 | {num} { t2SaveTokenNumber; return FLOATTOKEN; } 224 | 225 | 226 | "-webkit-any(" { t2Token = ANYFUNCTION; return t2Token; } 227 | 228 | "not(" { t2Token = NOTFUNCTION; return t2Token; } 229 | 230 | "url("{w}{string}{w}")" { t2Token = URI; return t2Token; } 231 | 232 | "url("{w}{url}{w}")" { t2Token = URI; return t2Token; } 233 | 234 | "-webkit-calc(" { t2Token = CALCFUNCTION; return t2Token; } 235 | 236 | "-webkit-min(" { t2Token = MINFUNCTION; return t2Token; } 237 | 238 | "-webkit-max(" { t2Token = MAXFUNCTION; return t2Token; } 239 | 240 | {ident}"(" { t2Token = FUNCTION; return t2Token; } 241 | 242 | 243 | U\+{range} { t2Token = UNICODERANGE; return t2Token; } 244 | 245 | U\+{h}{1,6}-{h}{1,6} { t2Token = UNICODERANGE; return t2Token; } 246 | 247 | 248 | "{" | 249 | 250 | ";" { BEGIN(INITIAL); t2Token = *yytext; return t2Token; } 251 | 252 | . { t2Token = *yytext; return t2Token; } 253 | 254 | %% -------------------------------------------------------------------------------- /t2CSSNode.h: -------------------------------------------------------------------------------- 1 | #ifndef T2_CSSNODE_H 2 | #define T2_CSSNODE_H 3 | 4 | #include 5 | #include 6 | 7 | #define ENABLE_PRINT_TEST 8 | 9 | enum t2CSSSpecifierType 10 | { 11 | // 元素选择器 12 | T2CSS_ELEMENT, 13 | // id选择器 14 | T2CSS_ID, 15 | // 类选择器 16 | T2CSS_CLASS, 17 | // 属性选择器 18 | T2CSS_ATTRIB, 19 | // 伪类选择器 20 | T2CSS_PSEUDO 21 | }; 22 | 23 | enum t2CSSTermType 24 | { 25 | T2CSS_INTERGER, 26 | T2CSS_FLOAT, 27 | T2CSS_PERCENTAGE, 28 | // 带一元运算符term 29 | T2CSS_UNARY_OPERATOR_INTERGER, 30 | T2CSS_UNARY_OPERATOR_FLOAT, 31 | T2CSS_STRING, 32 | T2CSS_IDENT, 33 | // 无符号dimen 34 | T2CSS_DIMEN, 35 | // 带一元运算符dimen 36 | T2CSS_UNARY_OPERATOR_UNARY_DIMEN, 37 | // url("")/url('') 38 | T2CSS_URI, 39 | T2CSS_UNICODERANGE, 40 | // 十六进制 41 | T2CSS_HEX, 42 | // #term 43 | T2CSS_POUND_TERM, 44 | // %term 45 | T2CSS_PERCENT_TERM 46 | }; 47 | 48 | class t2CSSNode 49 | { 50 | public: 51 | t2CSSNode():nodeName("Node"){} 52 | 53 | virtual t2CSSNode* leftChild(){ return NULL; } 54 | virtual t2CSSNode* rightChild(){ return NULL; } 55 | virtual void node(){ 56 | #ifdef ENABLE_PRINT_TEST 57 | std::cout << nodeName << std::endl; 58 | #endif 59 | } 60 | 61 | // --!Debug:结点名 62 | std::string nodeName; 63 | }; 64 | 65 | // 选择器 66 | class t2CSSNodeSpecifier : public t2CSSNode 67 | { 68 | public: 69 | t2CSSNodeSpecifier():type(T2CSS_ELEMENT){ nodeName = "Specifier"; } 70 | 71 | virtual t2CSSNode* leftChild(){ 72 | #ifdef ENABLE_PRINT_TEST 73 | //std::cout << selectorName << std::endl; 74 | #endif 75 | return NULL; 76 | } 77 | 78 | virtual t2CSSNode* rightChild(){ return NULL; } 79 | virtual void node(){ 80 | #ifdef ENABLE_PRINT_TEST 81 | std::cout << nodeName << std::endl; 82 | 83 | std::cout << "---->Type:"; 84 | switch(type) 85 | { 86 | // 元素选择器 87 | case T2CSS_ELEMENT: 88 | nodeName = "SpecifierElement"; 89 | std::cout << "Element" << std::endl; 90 | break; 91 | // id选择器 92 | case T2CSS_ID: 93 | nodeName = "SpecifierID"; 94 | std::cout << "ID" << std::endl; 95 | break; 96 | // 类选择器 97 | case T2CSS_CLASS: 98 | nodeName = "SpecifierClass"; 99 | std::cout << "Class" << std::endl; 100 | break; 101 | // 属性选择器 102 | case T2CSS_ATTRIB: 103 | nodeName = "SpecifierAttribute"; 104 | std::cout << "Attribute" << std::endl; 105 | break; 106 | // 伪类选择器 107 | case T2CSS_PSEUDO: 108 | nodeName = "SpecifierPseudo"; 109 | std::cout << "Pseudo" << std::endl; 110 | break; 111 | } 112 | #endif 113 | } 114 | 115 | // 选择器类型 116 | t2CSSSpecifierType type; 117 | 118 | // 具体选择器名 119 | std::string selectorName; 120 | }; 121 | 122 | class t2CSSNodeSpecifierList : public t2CSSNode 123 | { 124 | public: 125 | t2CSSNodeSpecifierList():specifier(NULL), specifierList(NULL){ nodeName = "SpecifierList"; } 126 | 127 | virtual t2CSSNode* leftChild(){ return specifier; } 128 | virtual t2CSSNode* rightChild(){ return specifierList; } 129 | 130 | // 这里默认specifierList = NULL TattyUI不支持.a.b{}此类写法 131 | t2CSSNodeSpecifier* specifier; 132 | t2CSSNodeSpecifierList* specifierList; 133 | }; 134 | 135 | class t2CSSSimpleSelector : public t2CSSNode 136 | { 137 | public: 138 | t2CSSSimpleSelector():specifierList(NULL){ nodeName = "SimpleSelector"; } 139 | 140 | virtual t2CSSNode* leftChild(){ 141 | #ifdef ENABLE_PRINT_TEST 142 | //std::cout << elementName << std::endl; 143 | #endif 144 | return NULL; 145 | } 146 | 147 | virtual t2CSSNode* rightChild(){ return specifierList; } 148 | 149 | // 元素名 大多数情况下为空 150 | std::string elementName; 151 | t2CSSNodeSpecifierList* specifierList; 152 | }; 153 | 154 | class t2CSSSelector : public t2CSSNode 155 | { 156 | public: 157 | t2CSSSelector():selector(NULL), simpleSelector(NULL){ nodeName = "Selector"; } 158 | 159 | virtual t2CSSNode* leftChild(){ return simpleSelector; } 160 | virtual t2CSSNode* rightChild(){ return selector; } 161 | 162 | // 为支持.a .b{}这种层序选择器 163 | t2CSSSelector* selector; 164 | t2CSSSimpleSelector* simpleSelector; 165 | }; 166 | 167 | class t2CSSSelectorList : public t2CSSNode 168 | { 169 | public: 170 | t2CSSSelectorList():selectorList(NULL), selector(NULL){ nodeName = "SelectorList"; } 171 | 172 | virtual t2CSSNode* leftChild(){ return selectorList; } 173 | virtual t2CSSNode* rightChild(){ return selector; } 174 | 175 | // 若当前规则只有一个选择器.a{} 那么selectorList为空 176 | t2CSSSelectorList* selectorList; 177 | t2CSSSelector* selector; 178 | }; 179 | 180 | // 声明 181 | class t2CSSTerm : public t2CSSNode 182 | { 183 | public: 184 | t2CSSTerm():termType(T2CSS_INTERGER){ nodeName = "Term"; } 185 | 186 | virtual t2CSSNode* leftChild(){ return NULL; } 187 | virtual t2CSSNode* rightChild(){ return NULL; } 188 | virtual void node(){ 189 | #ifdef ENABLE_PRINT_TEST 190 | std::cout << nodeName << std::endl; 191 | 192 | std::cout << "---->Type:"; 193 | switch(termType) 194 | { 195 | case T2CSS_INTERGER: 196 | nodeName = "TermInteger"; 197 | std::cout << "Integer" << std::endl; 198 | break; 199 | 200 | case T2CSS_FLOAT: 201 | nodeName = "TermFloat"; 202 | std::cout << "Float" << std::endl; 203 | break; 204 | 205 | case T2CSS_PERCENTAGE: 206 | nodeName = "TermPercentage"; 207 | std::cout << "Percentage" << std::endl; 208 | break; 209 | 210 | // 带一元运算符term 211 | case T2CSS_UNARY_OPERATOR_INTERGER: 212 | nodeName = "TermUnary Operator Interger"; 213 | std::cout << "Unary Operator Interger" << std::endl; 214 | break; 215 | 216 | case T2CSS_UNARY_OPERATOR_FLOAT: 217 | nodeName = "TermUnary Operator Float"; 218 | std::cout << "Unary Operator Float" << std::endl; 219 | break; 220 | 221 | case T2CSS_STRING: 222 | nodeName = "TermString"; 223 | std::cout << "String" << std::endl; 224 | break; 225 | 226 | case T2CSS_IDENT: 227 | nodeName = "TermIndent"; 228 | std::cout << "Indent" << std::endl; 229 | break; 230 | 231 | // 无符号dimen 232 | case T2CSS_DIMEN: 233 | nodeName = "TermDimen"; 234 | std::cout << "Dimen" << std::endl; 235 | break; 236 | 237 | // 带一元运算符dimen 238 | case T2CSS_UNARY_OPERATOR_UNARY_DIMEN: 239 | nodeName = "TermUnary Operator Unary Dimen"; 240 | std::cout << "Unary Operator Unary Dimen" << std::endl; 241 | break; 242 | 243 | // url("")/url('') 244 | case T2CSS_URI: 245 | nodeName = "TermUrl"; 246 | std::cout << "Url" << std::endl; 247 | break; 248 | 249 | case T2CSS_UNICODERANGE: 250 | nodeName = "TermUnicoderange"; 251 | std::cout << "Unicoderange" << std::endl; 252 | break; 253 | 254 | // 十六进制 255 | case T2CSS_HEX: 256 | nodeName = "TermHex"; 257 | std::cout << "Hex" << std::endl; 258 | break; 259 | 260 | // #term 261 | case T2CSS_POUND_TERM: 262 | nodeName = "TermPound Term"; 263 | std::cout << "Pound Term" << std::endl; 264 | break; 265 | 266 | // %term 267 | case T2CSS_PERCENT_TERM: 268 | nodeName = "TermPercent Term"; 269 | std::cout << "Percent Term" << std::endl; 270 | break; 271 | } 272 | #endif 273 | } 274 | 275 | // term类型 276 | t2CSSTermType termType; 277 | 278 | // term名 279 | std::string termName; 280 | // value 281 | float value; 282 | }; 283 | 284 | class t2CSSExpression : public t2CSSNode 285 | { 286 | public: 287 | t2CSSExpression():expression(NULL), term(NULL){ nodeName = "Expression"; } 288 | 289 | virtual t2CSSNode* leftChild(){ return expression; } 290 | virtual t2CSSNode* rightChild(){ return term; } 291 | 292 | // 只有为margin: 1, 2, 3, 4;这类表达式集 那么expr非空 293 | t2CSSExpression* expression; 294 | t2CSSTerm* term; 295 | }; 296 | 297 | class t2CSSDeclaration : public t2CSSNode 298 | { 299 | public: 300 | t2CSSDeclaration():expression(NULL){ nodeName = "Declaration"; } 301 | 302 | virtual t2CSSNode* leftChild(){ 303 | #ifdef ENABLE_PRINT_TEST 304 | //std::cout << property << std::endl; 305 | #endif 306 | return NULL; } 307 | virtual t2CSSNode* rightChild(){ return expression; } 308 | 309 | // 属性名 310 | std::string property; 311 | t2CSSExpression* expression; 312 | }; 313 | 314 | class t2CSSDeclarationList : public t2CSSNode 315 | { 316 | public: 317 | t2CSSDeclarationList():declarationList(NULL), declaration(NULL){ nodeName = "DeclarationList"; } 318 | 319 | virtual t2CSSNode* leftChild(){ return declarationList; } 320 | virtual t2CSSNode* rightChild(){ return declaration; } 321 | 322 | // 只有声明不止一个时 declarationList才不为空 323 | t2CSSDeclarationList* declarationList; 324 | t2CSSDeclaration* declaration; 325 | }; 326 | 327 | // 规则 328 | class t2CSSRuleset : public t2CSSNode 329 | { 330 | public: 331 | t2CSSRuleset():selectorList(NULL), declarationList(NULL){ nodeName = "Ruleset"; } 332 | 333 | virtual t2CSSNode* leftChild(){ return selectorList; } 334 | virtual t2CSSNode* rightChild(){ return declarationList; } 335 | 336 | t2CSSSelectorList* selectorList; 337 | t2CSSDeclarationList* declarationList; 338 | }; 339 | 340 | class t2CSSRuleList : public t2CSSNode 341 | { 342 | public: 343 | t2CSSRuleList():ruleList(NULL), ruleset(NULL){ nodeName = "RuleList"; } 344 | 345 | virtual t2CSSNode* leftChild(){ return ruleList; } 346 | virtual t2CSSNode* rightChild(){ return ruleset; } 347 | 348 | // 只有当规则不止一条时 ruleList才不为空 349 | t2CSSRuleList* ruleList; 350 | t2CSSRuleset* ruleset; 351 | }; 352 | 353 | #endif 354 | -------------------------------------------------------------------------------- /Bison-5-CSS2.y: -------------------------------------------------------------------------------- 1 | %pure-parser 2 | %parse-param { class t2CSSAST* parser } 3 | 4 | %{ 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | %} 11 | 12 | %union { 13 | int token; 14 | 15 | float number; 16 | std::string* string; 17 | 18 | class t2CSSNodeSpecifier* specifier; 19 | class t2CSSNodeSpecifierList* specifierList; 20 | 21 | class t2CSSDeclaration* decl; 22 | class t2CSSDeclarationList* declList; 23 | 24 | class t2CSSExpression* expr; 25 | class t2CSSTerm* term; 26 | 27 | class t2CSSRuleset* rule; 28 | class t2CSSRuleList* ruleList; 29 | 30 | class t2CSSSimpleSelector* simpleSelector; 31 | class t2CSSSelector* selector; 32 | class t2CSSSelectorList* selectorList; 33 | } 34 | 35 | 36 | %{ 37 | #include "t2CSSAST.h" 38 | 39 | #define YYLEX_PARAM parser->scaninfo 40 | 41 | /* t2CSSRuleList* root; 42 | 43 | int yyparse(t2CSSParser* parser); */ 44 | 45 | void yyerror(t2CSSAST* parser, const char *s) { 46 | printf("----------------------ERROR---------------------\n"); 47 | if(!parser->root) printf("Error: Ast's root is null.\n"); 48 | printf("Error content: %s.\n", s); 49 | printf("------------------------------------------------\n"); 50 | } 51 | 52 | %} 53 | 54 | /* 运算符优先级 */ 55 | /* token本身含义默认为宏 */ 56 | %nonassoc LOWEST_PREC 57 | 58 | %left UNIMPORTANT_TOK 59 | 60 | %token WHITESPACE SGML_CD 61 | %token TOKEN_EOF 0 62 | 63 | %token INCLUDES 64 | %token DASHMATCH 65 | %token BEGINSWITH 66 | %token ENDSWITH 67 | %token CONTAINS 68 | 69 | %token STRING 70 | %right IDENT 71 | %token NTH 72 | 73 | %nonassoc HEX 74 | %nonassoc IDSEL 75 | 76 | %nonassoc '-' 77 | %nonassoc '+' 78 | %nonassoc '#' 79 | %nonassoc '%' 80 | %nonassoc ':' 81 | %nonassoc '.' 82 | %nonassoc '[' 83 | %nonassoc '*' 84 | %nonassoc error 85 | %left '|' 86 | 87 | /* Flex可解析出的所有词法token */ 88 | %token IMPORT_SYM 89 | %token PAGE_SYM 90 | %token MEDIA_SYM 91 | %token FONT_FACE_SYM 92 | %token CHARSET_SYM 93 | %token NAMESPACE_SYM 94 | %token WEBKIT_RULE_SYM 95 | %token WEBKIT_DECLS_SYM 96 | %token WEBKIT_KEYFRAME_RULE_SYM 97 | %token WEBKIT_KEYFRAMES_SYM 98 | %token WEBKIT_VALUE_SYM 99 | %token WEBKIT_MEDIAQUERY_SYM 100 | %token WEBKIT_SELECTOR_SYM 101 | %token TOPLEFTCORNER_SYM 102 | %token TOPLEFT_SYM 103 | %token TOPCENTER_SYM 104 | %token TOPRIGHT_SYM 105 | %token TOPRIGHTCORNER_SYM 106 | %token BOTTOMLEFTCORNER_SYM 107 | %token BOTTOMLEFT_SYM 108 | %token BOTTOMCENTER_SYM 109 | %token BOTTOMRIGHT_SYM 110 | %token BOTTOMRIGHTCORNER_SYM 111 | %token LEFTTOP_SYM 112 | %token LEFTMIDDLE_SYM 113 | %token LEFTBOTTOM_SYM 114 | %token RIGHTTOP_SYM 115 | %token RIGHTMIDDLE_SYM 116 | %token RIGHTBOTTOM_SYM 117 | 118 | %token ATKEYWORD 119 | 120 | %token IMPORTANT_SYM 121 | %token MEDIA_ONLY 122 | %token MEDIA_NOT 123 | %token MEDIA_AND 124 | 125 | %token REMS 126 | %token QEMS 127 | %token EMS 128 | %token EXS 129 | %token PXS 130 | %token CMS 131 | %token MMS 132 | %token INS 133 | %token PTS 134 | %token PCS 135 | %token DEGS 136 | %token RADS 137 | %token GRADS 138 | %token TURNS 139 | %token MSECS 140 | %token SECS 141 | %token HERTZ 142 | %token KHERTZ 143 | %token DIMEN 144 | %token INVALIDDIMEN 145 | %token PERCENTAGE 146 | %token FLOATTOKEN 147 | %token INTEGER 148 | 149 | %token URI 150 | %token FUNCTION 151 | %token ANYFUNCTION 152 | %token NOTFUNCTION 153 | %token CALCFUNCTION 154 | %token MINFUNCTION 155 | %token MAXFUNCTION 156 | 157 | %token UNICODERANGE 158 | 159 | /* BNF范式类型 */ 160 | %type ruleset 161 | %type rule_list 162 | 163 | %type property 164 | 165 | %type specifier 166 | %type specifier_list 167 | 168 | %type simple_selector 169 | %type selector 170 | %type selector_list 171 | 172 | %type class 173 | %type attrib 174 | %type pseudo 175 | 176 | %type decl_list 177 | %type declaration 178 | 179 | %type unary_operator 180 | %type operator 181 | 182 | %type expr 183 | %type term 184 | 185 | %type element_name 186 | %type attr_name 187 | 188 | %% 189 | /* 可选的字符集选择 / @import / @namemaybe_space / 普通规则集合 / @media / @page / @font_face */ 190 | stylesheet 191 | : maybe_space rule_list { 192 | printf("stylesheet\n"); 193 | 194 | parser->root = $2; 195 | 196 | /* traversal(root); */ 197 | } 198 | ; 199 | 200 | /* 格式化符集 \t\r\n\f */ 201 | maybe_space 202 | : /* 空 */ %prec UNIMPORTANT_TOK 203 | | maybe_space WHITESPACE 204 | ; 205 | 206 | /* 单目运算符 */ 207 | unary_operator 208 | : '-' { $$ = new std::string("-"); } 209 | | '+' { $$ = new std::string("+"); } 210 | ; 211 | 212 | /* 属性名 */ 213 | property 214 | : IDENT maybe_space { 215 | printf("property\n"); 216 | $$ = $1; 217 | } 218 | ; 219 | 220 | /* ------------------------规则------------------------ */ 221 | /* 逗号做分隔符 规则由{开始 }结束 中间可插入一个或多个属性声明*/ 222 | /* 语句后需要有;结束 */ 223 | /* -- */ 224 | rule_list 225 | : /* 空 */ { 226 | printf("rule_list_empty\n"); 227 | 228 | $$ = NULL; 229 | } 230 | 231 | | rule_list ruleset maybe_space { 232 | printf("rule_list\n"); 233 | 234 | t2CSSRuleList* list = new t2CSSRuleList(); 235 | list->ruleList = $1; 236 | list->ruleset = $2; 237 | $$ = list; 238 | } 239 | ; 240 | 241 | before_ruleset 242 | : /* 空 */ 243 | ; 244 | 245 | before_rule_opening_brace 246 | : /* empty */ 247 | ; 248 | 249 | ruleset 250 | : before_ruleset selector_list before_rule_opening_brace '{' maybe_space decl_list '}' { 251 | printf("ruleset\n"); 252 | 253 | t2CSSRuleset* ruleset = new t2CSSRuleset(); 254 | ruleset->selectorList = $2; 255 | ruleset->declarationList = $6; 256 | $$ = ruleset; 257 | } 258 | ; 259 | 260 | /* ------------------------声明------------------------ */ 261 | decl_list 262 | : declaration ';' maybe_space { 263 | printf("decl_list\n\n"); 264 | 265 | t2CSSDeclarationList* declList = new t2CSSDeclarationList(); 266 | declList->declarationList = NULL; 267 | declList->declaration = $1; 268 | $$ = declList; 269 | } 270 | 271 | | decl_list declaration ';' maybe_space { 272 | printf("decl_list_declaration\n"); 273 | 274 | t2CSSDeclarationList* declList = new t2CSSDeclarationList(); 275 | declList->declarationList = $1; 276 | declList->declaration = $2; 277 | $$ = declList; 278 | } 279 | ; 280 | 281 | /* 属性声明 */ 282 | /* 属性名之后可接格式化符 必须以;结尾 */ 283 | declaration 284 | : property ':' maybe_space expr { 285 | printf("declaration\n"); 286 | 287 | t2CSSDeclaration* decl = new t2CSSDeclaration(); 288 | decl->property = *$1; 289 | decl->expression = $4; 290 | $$ = decl; 291 | } 292 | ; 293 | 294 | /* ------------------------选择器------------------------ */ 295 | selector_list 296 | : selector %prec UNIMPORTANT_TOK { 297 | printf("selector_list\n"); 298 | 299 | t2CSSSelectorList* selectorList = new t2CSSSelectorList(); 300 | selectorList->selectorList = NULL; 301 | selectorList->selector = $1; 302 | $$ = selectorList; 303 | } 304 | 305 | | selector_list ',' maybe_space selector { 306 | printf("selector_list ,\n"); 307 | 308 | t2CSSSelectorList* selectorList = new t2CSSSelectorList(); 309 | selectorList->selectorList = $1; 310 | selectorList->selector = $4; 311 | $$ = selectorList; 312 | } 313 | ; 314 | 315 | /* Hash代表id选择器 */ 316 | /*

HelloWorld

其中p也就是element_name都是可选的*/ 317 | /* Hash: p#intro */ 318 | /* class: p.intro */ 319 | /* attrib: p[href] */ 320 | /* pseudo: p:active */ 321 | selector 322 | : simple_selector { 323 | printf("selector_simple\n"); 324 | 325 | t2CSSSelector* selector = new t2CSSSelector(); 326 | selector->selector = NULL; 327 | selector->simpleSelector = $1; 328 | $$ = selector; 329 | } 330 | 331 | | selector WHITESPACE { 332 | printf("selector whitspace\n"); 333 | 334 | t2CSSSelector* selector = new t2CSSSelector(); 335 | selector->selector = $1; 336 | selector->simpleSelector = NULL; 337 | $$ = selector; 338 | } 339 | 340 | | selector WHITESPACE simple_selector { 341 | printf("selector\n"); 342 | 343 | t2CSSSelector* selector = new t2CSSSelector(); 344 | selector->selector = $1; 345 | selector->simpleSelector = $3; 346 | $$ = selector; 347 | } 348 | ; 349 | 350 | simple_selector 351 | : element_name { 352 | printf("simple_selector_element_name\n"); 353 | 354 | t2CSSSimpleSelector* simpleSelector = new t2CSSSimpleSelector(); 355 | simpleSelector->elementName = *$1; 356 | simpleSelector->specifierList = NULL; 357 | $$ = simpleSelector; 358 | } 359 | 360 | | element_name specifier_list { 361 | printf("simple_selector_element_name_specifier_list\n"); 362 | 363 | t2CSSSimpleSelector* simpleSelector = new t2CSSSimpleSelector(); 364 | simpleSelector->elementName = *$1; 365 | simpleSelector->specifierList = $2; 366 | $$ = simpleSelector; 367 | } 368 | 369 | | specifier_list { 370 | printf("simple_selector_specifier_list\n"); 371 | 372 | t2CSSSimpleSelector* simpleSelector = new t2CSSSimpleSelector(); 373 | simpleSelector->elementName = ""; 374 | simpleSelector->specifierList = $1; 375 | $$ = simpleSelector; 376 | } 377 | ; 378 | 379 | specifier_list 380 | : specifier { 381 | printf("specifier_list_this\n"); 382 | 383 | t2CSSNodeSpecifierList* specifierList = new t2CSSNodeSpecifierList(); 384 | specifierList->specifier = $1; 385 | specifierList->specifierList = NULL; 386 | $$ = specifierList; 387 | } 388 | 389 | | specifier_list specifier { 390 | printf("specifier_list_specifier\n"); 391 | 392 | t2CSSNodeSpecifierList* specifierList = new t2CSSNodeSpecifierList(); 393 | specifierList->specifier = $2; 394 | specifierList->specifierList = $1; 395 | $$ = specifierList; 396 | } 397 | ; 398 | 399 | /* 元素选择器 id选择器 + 其他选择器*/ 400 | specifier: 401 | IDSEL { 402 | printf("idsel\n"); 403 | 404 | t2CSSNodeSpecifier* specifier = new t2CSSNodeSpecifier(); 405 | specifier->type = T2CSS_ELEMENT; 406 | specifier->selectorName = *$1; 407 | 408 | $$ = specifier; 409 | } 410 | 411 | | HEX { 412 | printf("hex\n"); 413 | 414 | t2CSSNodeSpecifier* specifier = new t2CSSNodeSpecifier(); 415 | specifier->type = T2CSS_ID; 416 | specifier->selectorName = *$1; 417 | 418 | $$ = specifier; 419 | } 420 | 421 | | class { 422 | printf("specifier\n"); 423 | 424 | t2CSSNodeSpecifier* specifier = new t2CSSNodeSpecifier(); 425 | specifier->type = T2CSS_CLASS; 426 | specifier->selectorName = *$1; 427 | 428 | $$ = specifier; 429 | } 430 | 431 | | attrib { 432 | printf("specifier\n"); 433 | 434 | t2CSSNodeSpecifier* specifier = new t2CSSNodeSpecifier(); 435 | specifier->type = T2CSS_ATTRIB; 436 | specifier->selectorName = *$1; 437 | 438 | $$ = specifier; 439 | } 440 | 441 | | pseudo { 442 | printf("specifier\n"); 443 | 444 | t2CSSNodeSpecifier* specifier = new t2CSSNodeSpecifier(); 445 | specifier->type = T2CSS_PSEUDO; 446 | specifier->selectorName = *$1; 447 | 448 | $$ = specifier; 449 | } 450 | ; 451 | 452 | /* 类选择器 */ 453 | class 454 | : '.' IDENT { 455 | printf("class\n"); 456 | $$ = $2; 457 | } 458 | ; 459 | 460 | /* 元素名可以为* 代表所有文档中元素 */ 461 | element_name 462 | : IDENT { 463 | printf("element_name\n"); 464 | $$ = $1; 465 | } 466 | 467 | | '*'{ 468 | $$ = new std::string("*"); 469 | } 470 | ; 471 | 472 | /* 属性名 */ 473 | attr_name 474 | : IDENT maybe_space { 475 | printf("attr_name\n"); 476 | 477 | $$ = $1; 478 | } 479 | ; 480 | 481 | /* 属性选择器 */ 482 | attrib 483 | : '[' maybe_space attr_name ']' { 484 | printf("attrib\n"); 485 | $$ = $3; 486 | } 487 | ; 488 | 489 | /* 伪类选择器 */ 490 | /* Deprecated: Function用于处理 q:lang(no){}类的情况 */ 491 | pseudo 492 | : ':' IDENT { 493 | printf("pseudo\n"); 494 | 495 | $$ = $2; 496 | } 497 | ; 498 | 499 | /* ------------------------元类型------------------------ */ 500 | /* 表达式 可选的单独term出现 */ 501 | expr 502 | : term { 503 | printf("expr term\n"); 504 | 505 | t2CSSExpression* expr = new t2CSSExpression(); 506 | expr->expression = NULL; 507 | expr->term = $1; 508 | $$ = expr; 509 | } 510 | 511 | | expr operator term { 512 | printf("expr operator term\n"); 513 | 514 | t2CSSExpression* expr = new t2CSSExpression(); 515 | expr->expression = $1; 516 | expr->term = $3; 517 | $$ = expr; 518 | } 519 | ; 520 | 521 | /* 分隔操作符 / 空格 */ 522 | operator 523 | : '/' maybe_space 524 | | ',' maybe_space 525 | | /* 空 */ 526 | ; 527 | 528 | /* 实则为表达式右值 可以为带单位的数值 或 类函数 / 字符串 / 关键字标示符 / url / 一段Unicode范围 / 十六进制色*/ 529 | /* 不支持num+单位的表达方式 全局为像素单位 */ 530 | term: 531 | INTEGER maybe_space{ 532 | t2CSSTerm* term = new t2CSSTerm(); 533 | term->termType = T2CSS_INTERGER; 534 | term->value = $1; 535 | $$ = term; 536 | } 537 | 538 | | FLOATTOKEN maybe_space{ 539 | t2CSSTerm* term = new t2CSSTerm(); 540 | term->termType = T2CSS_FLOAT; 541 | term->value = $1; 542 | $$ = term; 543 | } 544 | 545 | | unary_operator INTEGER maybe_space { 546 | printf("unary_operator INTEGER\n"); 547 | 548 | t2CSSTerm* term = new t2CSSTerm(); 549 | term->termType = T2CSS_UNARY_OPERATOR_INTERGER; 550 | 551 | if(*$1 == "+") 552 | term->termName = $2; 553 | else 554 | term->termName = -$2; 555 | 556 | $$ = term; 557 | } 558 | 559 | | unary_operator FLOATTOKEN maybe_space { 560 | printf("unary_operator FLOATTOKEN\n"); 561 | 562 | t2CSSTerm* term = new t2CSSTerm(); 563 | term->termType = T2CSS_UNARY_OPERATOR_FLOAT; 564 | 565 | if(*$1 == "+") 566 | term->termName = $2; 567 | else 568 | term->termName = -$2; 569 | 570 | $$ = term; 571 | } 572 | 573 | | STRING maybe_space { 574 | printf("STRING\n"); 575 | 576 | t2CSSTerm* term = new t2CSSTerm(); 577 | term->termType = T2CSS_STRING; 578 | term->termName = *$1; 579 | $$ = term; 580 | } 581 | 582 | | IDENT maybe_space { 583 | printf("IDENT\n"); 584 | 585 | t2CSSTerm* term = new t2CSSTerm(); 586 | term->termType = T2CSS_IDENT; 587 | term->termName = *$1; 588 | $$ = term; 589 | } 590 | 591 | | HEX maybe_space { 592 | printf("HEX\n"); 593 | 594 | t2CSSTerm* term = new t2CSSTerm(); 595 | term->termType = T2CSS_HEX; 596 | term->termName = *$1; 597 | $$ = term; 598 | } 599 | 600 | | '#' maybe_space { 601 | printf("#term\n"); 602 | 603 | t2CSSTerm* term = new t2CSSTerm(); 604 | term->termType = T2CSS_POUND_TERM; 605 | term->termName = *$1; 606 | $$ = term; 607 | } 608 | 609 | | '%' maybe_space { 610 | printf("%term\n"); 611 | 612 | t2CSSTerm* term = new t2CSSTerm(); 613 | term->termType = T2CSS_PERCENT_TERM; 614 | term->termName = *$1; 615 | $$ = term; 616 | } 617 | ; 618 | 619 | %% 620 | --------------------------------------------------------------------------------