Я пытаюсь написать парсер C, для моего собственного образования. Я знаю, что для упрощения процесса я мог бы использовать такие инструменты, как YACC, но я хочу как можно больше узнать об опыте, поэтому я начинаю с нуля.
Мой вопрос заключается в том, как я должен обрабатывать строку следующим образом:
doSomethingWith((foo)(bar));
Может быть, что (foo)(bar)
является типом, как в:
typedef int foo;
void doSomethingWith(foo aFoo) { ... }
int main() {
float bar = 23.6;
doSomethingWith((foo)(bar));
return 0;
}
Или может быть, что (foo)(bar)
является вызовом функции, как в:
int foo(int bar) { return bar; }
void doSomethingWith(int anInt) { ... }
int main() {
int bar = 10;
doSomethingWith((foo)(bar));
return 0;
}
Мне кажется, что синтаксический анализатор не может определить, к какому из двух случаев он имеет дело только с просмотром строки doSomethingWith((foo)(bar));
Это меня раздражает, потому что я надеялся разделить этап синтаксиса с "интерпретацией" ", где вы фактически определяете, что строка typedef int foo;
означает, что foo
теперь является допустимым типом. В моем воображаемом сценарии Type a = b + c * d
будет разбираться просто отлично, даже если Type, a, b, c и d нигде не определены, и проблемы возникнут позже, когда фактически пытаются" разрешить" идентификаторы.
Итак, мой вопрос: как с этим справляются "реальные" C-парсеры? Является ли разделение между двумя этапами, что я надеялся на наивное желание, или я чего-то не хватает?