解析 CSS 样式表

Parsing a CSS stylesheet

本文关键字:样式 CSS 解析      更新时间:2023-10-16

我目前正在为一个学习项目编写一个简单的HTML渲染器,但目前被困在解析部分 - 我知道有点早。我采用了"不要重新发明轮子"的方法,并使用TinyXML来解析HTML文件。虽然绘画有点遥远,但我计划使用OpenGL。但是,我遇到了CSS解析器部分缺少轮子的问题。是否有任何小型且相当快速的 CSS 解析器库可用?如果是,有人可以指出我吗?如果不是这种情况 - 任何人都可以给我一个简短的解释,说明自己使用 C++ 解析 CSS 文件的方法是什么?例如,我是否使用正则表达式?

所以,总结一下:

  • 是否有任何用 C/C++ 编写的小型/快速 CSS 解析器库可用?
  • 如何使用正则表达式解析一个非常简单的 CSS 文件(例如)?

我绝不想包含整个CSS标准,现在只需要标准的"by-id","by-class"和"by-tag"CSS选择器就足够了。我期待着一些可能对我的追求有所帮助的东西:D

我会使用LibCSS,只要不重新发明轮子。这是一件好事。LibCSS包含一个解析和选择API,这使得将其与HTML解析器相结合变得简单。

但是,如果在哪里谈论学习项目,编写解析器也是一件好事。我建议深入研究递归体面的解析器。这些实现起来相当简单。

如果我用伪C++代码编写一个简单的解析器,它看起来像:

enum Type {
  ID, // #
  CLASS, // .
  IDENTIFIER, // [a-zA-Z][a-zA-Z0-9-_]
  LWING, // {
  RWING, // }
  COLON, // :    
  SEMI, // ;
}
struct Token {
  std::string value;
  Type type;
}
bool has_next_token();
bool has_next_token(Type type);
Token next_token();

Token expect_token(Type type) {
  Token token = next_token();
  if (token.type != type) {
    std::runtime_error("Error: expected another type");
  }
}
void parse() {
  while (has_next_token()) {
    parse_rule();
  }
}
void parse_rule() {
  parse_selector();
  expect_token(Type.LWING);
  while (!has_next_token(Type.RWING)) {
     parse_assignment();
  }
  expect_token(Type.RWING);
}
void parse_selector() {
  if (has_next_token(Type.CLASS)) {
    parse_class();  
  } else if (has_next_token(Type.ID)) {
    parse_id();
  } else {
    parse_tag();
  }
}
void parse_class() {
  expect_token(Type.CLASS);
  Token token = expect_token(Type.IDENTIFIER);
  std::string class_name = token.value; 
  // Do something with class_name
}
void parse_id(); // Almost the same as parse_class
void parse_tag(); // You know the drill
void parse_assignment() {
  expect(Type.IDENTIFIER);
  expect(Type.COLON);
  parse_value();
  expect(Type.SEMI);
}
void parse_value(); // I'll leave this one to you