C で書かれていないことはわかっていますが、そのプレゼンテーションは、問題に効率的に取り組む方法についての情報を提供してくれるかもしれません。
https://web.archive.org/web/20120115060003/http://cuddle.googlecode.com/hg/talk/lex.html#landing-slide
また、最初の要件に基づいて、JavaScript で非常に単純なパーサーの例を作成しました (これも C ではありませんが、JS も知っていることを願っています)。これは、属性を解析せず、自己終了タグや他の多くのものを処理しないことを意味します。 HTML仕様に従って処理する必要があります。次の形式で解析ツリーが生成されます。
{
cn: [{
tag: 'html',
cn: [{
tag: 'body',
cn: [
{ tag: 'h1', cn: ['test'] },
' some text ',
...
]
}]
}]
}
コードとフィドルは次のとおりです。http://jsfiddle.net/LUpyZ/3/
空白は無視されず、テキスト ノードに取り込まれることに注意してください。
var html = '<html><body><h1>test</h1> some text <div> <p>text</p></div></body></html>';
var parseHTML = (function () {
var nodesStack = [],
i = 0,
len = html.length,
stateFn = parseText,
parseTree = { cn: [] },
alphaNumRx = /\w/,
currentNode = parseTree,
text = '',
tag = '',
newNode;
function parseTag(token) {
if (token === '/') {
return parseCloseTag;
}
i--; //backtrack to first tag character
return parseOpenTag;
}
function parseCloseTag(token) {
if (token === '>') {
if (currentNode.tag !== tag) {
throw 'Wrong closed tag at char ' + i;
}
tag = '';
nodesStack.pop();
currentNode = currentNode.parentNode;
return parseText;
}
assertValidTagNameChar(token);
tag += token;
return parseCloseTag;
}
function parseOpenTag(token) {
if (token === '>') {
currentNode.cn.push(newNode = { tag: tag, parentNode: currentNode, cn: []});
nodesStack.push(currentNode = newNode);
tag = '';
return parseText;
}
assertValidTagNameChar(token);
tag += token;
return parseOpenTag;
}
function parseText(token) {
if (token === '<') {
if (text) {
currentNode.cn.push(text);
text = '';
}
return parseTag;
}
text += token;
return parseText;
}
function assertValidTagNameChar(c) {
if (!alphaNumRx.test(c)) {
throw 'Invalid tag name char at ' + i;
}
}
return function (html) {
for (; i < len; i++) {
stateFn = stateFn(html[i]);
}
if (currentNode = nodesStack.pop()) {
throw 'Unbalanced tags: ' + currentNode.tag + ' is never closed.';
}
return parseTree;
};
})();
console.log(parseHTML(html));