From 66d8fc5c287aa67e13148c3b27ce966155e48975 Mon Sep 17 00:00:00 2001 From: "Emil J. Tywoniak" Date: Wed, 5 Nov 2025 11:00:25 +0100 Subject: [PATCH] libparse: quirk-compatibility for unquoted boolean expression strings --- passes/techmap/libparse.cc | 81 +++++++++++++++++++++++++++----------- passes/techmap/libparse.h | 2 + 2 files changed, 61 insertions(+), 22 deletions(-) diff --git a/passes/techmap/libparse.cc b/passes/techmap/libparse.cc index 7d4fd77ad..cf1854c87 100644 --- a/passes/techmap/libparse.cc +++ b/passes/techmap/libparse.cc @@ -364,7 +364,7 @@ std::string LibertyExpression::str(int indent) #endif -int LibertyParser::lexer(std::string &str) +int LibertyParser::lexer_inner(std::string &str) { int c; @@ -390,11 +390,9 @@ int LibertyParser::lexer(std::string &str) if (str == "+" || str == "-") { /* Single operator is not an identifier */ - // fprintf(stderr, "LEX: char >>%s<<\n", str.c_str()); return str[0]; } else { - // fprintf(stderr, "LEX: identifier >>%s<<\n", str.c_str()); return 'v'; } } @@ -402,24 +400,25 @@ int LibertyParser::lexer(std::string &str) // if it wasn't an identifer, number of array range, // maybe it's a string? if (c == '"') { + f.consume(1); size_t i = 0; while (true) { c = f.peek(i); line += (c == '\n'); - if (c != '"') + if (c != '"' && c != EOF) i += 1; else break; } str.clear(); -#ifdef FILTERLIB f.unget(); - str.append(f.buffered_data(), f.buffered_data() + i + 2); - f.consume(i + 2); -#else - str.append(f.buffered_data(), f.buffered_data() + i); - f.consume(i + 1); + str.append(f.buffered_data(), f.buffered_data() + i + 1); + // Usage in filterlib is expected to retain quotes + // but yosys expects to get unquoted +#ifdef FILTERLIB + str = "\"" + str + "\""; #endif + f.consume(i + 2); return 'v'; } @@ -442,13 +441,12 @@ int LibertyParser::lexer(std::string &str) return lexer(str); } f.unget(); - // fprintf(stderr, "LEX: char >>/<<\n"); return '/'; // a single '/' charater. } // check for a backslash if (c == '\\') { - c = f.get(); + c = f.get(); if (c == '\r') c = f.get(); if (c == '\n') { @@ -467,14 +465,22 @@ int LibertyParser::lexer(std::string &str) // anything else, such as ';' will get passed // through as literal items. - - // if (c >= 32 && c < 255) - // fprintf(stderr, "LEX: char >>%c<<\n", c); - // else - // fprintf(stderr, "LEX: char %d\n", c); return c; } +int LibertyParser::lexer(std::string &str) +{ + int ret = lexer_inner(str); + // if (ret >= 32 && ret < 255) { + // fprintf(stdout, "LEX: ret >>%c<<\n", ret); + // } else if (ret == 'v') { + // fprintf(stdout, "LEX: ret v str %s\n", str.c_str()); + // } else { + // fprintf(stdout, "LEX: ret %d\n", ret); + // } + return ret; +} + void LibertyParser::report_unexpected_token(int tok) { std::string eReport; @@ -545,6 +551,25 @@ void LibertyParser::parse_vector_range(int tok) } } +// Consume into out_str any string-ish tokens, seperated with spaces +// to cope with abuse of the underdefined spec by real world PDKs +// enabled by proprietary implementations. +// Sorry. +int LibertyParser::consume_wrecked_str(int tok, std::string& out_str) { + std::string str = ""; + while (tok != ';' && tok != EOF && tok != 'n') { + out_str += " "; + if (tok == 'v') + out_str += str; + else + out_str += tok; + tok = lexer(str); + } + if (tok == EOF) + error("wrecked string EOF"); + return tok; +} + LibertyAst *LibertyParser::parse(bool top_level) { std::string str; @@ -591,17 +616,29 @@ LibertyAst *LibertyParser::parse(bool top_level) if (tok == '[') { parse_vector_range(tok); tok = lexer(str); + } else { + // Hack for when an expression string is unquoted + // std::cout << "consume_wrecked_str from :\n"; + // std::cout << " weh " << str << "\n"; + tok = consume_wrecked_str(tok, ast->value); } + } else if (tok == '(') { + // Hack for when an expression string is unquoted and starts with + // parentheses + // tok = ''; + // ast->value = "("; + // std::cout << "consume_wrecked_str from (\n"; + tok = consume_wrecked_str(tok, ast->value); } while (tok == '+' || tok == '-' || tok == '*' || tok == '/' || tok == '!') { ast->value += tok; tok = lexer(str); if (tok != 'v') - error(); + error("one"); ast->value += str; tok = lexer(str); } - + // In a liberty file, all key : value pairs should end in ';' // However, there are some liberty files in the wild that // just have a newline. We'll be kind and accept a newline @@ -609,7 +646,7 @@ LibertyAst *LibertyParser::parse(bool top_level) if ((tok == ';') || (tok == 'n')) break; else - error(); + error("two"); continue; } @@ -621,11 +658,11 @@ LibertyAst *LibertyParser::parse(bool top_level) continue; if (tok == ')') break; - + if (tok == '[') { parse_vector_range(tok); - continue; + continue; } if (tok == 'n') continue; diff --git a/passes/techmap/libparse.h b/passes/techmap/libparse.h index 44b5d3d47..91f06a46c 100644 --- a/passes/techmap/libparse.h +++ b/passes/techmap/libparse.h @@ -170,10 +170,12 @@ namespace Yosys 'n': newline anything else is a single character. */ + int lexer_inner(std::string &str); int lexer(std::string &str); void report_unexpected_token(int tok); void parse_vector_range(int tok); + int consume_wrecked_str(int tok, std::string& out_str); LibertyAst *parse(bool top_level); void error() const; void error(const std::string &str) const;