Schalter --show-missing dazu gebaut
This commit is contained in:
@@ -92,6 +92,7 @@ bin\awl2scl_deep.bat --dir . --category A
|
|||||||
| `--force` | vorhandene **generierte** `.scl` überschreiben |
|
| `--force` | vorhandene **generierte** `.scl` überschreiben |
|
||||||
| `--tochange <pfad>` | toChange-Liste (Default `<Projekt>\data\globals2params_tochange.json`) |
|
| `--tochange <pfad>` | toChange-Liste (Default `<Projekt>\data\globals2params_tochange.json`) |
|
||||||
| `--log <pfad>` | Log-Datei |
|
| `--log <pfad>` | Log-Datei |
|
||||||
|
| `--show-missing` | am Ende alle nicht übersetzten Bausteine (manuelle Prüfung + Fehler) mit Grund auf der Konsole auflisten |
|
||||||
|
|
||||||
`--improve-gotos` und `--globals2params` implizieren `--force` (Regenerierung).
|
`--improve-gotos` und `--globals2params` implizieren `--force` (Regenerierung).
|
||||||
Der Zielpfad je Baustein ist `<target-dir>\<Station>\<Name>.scl`.
|
Der Zielpfad je Baustein ist `<target-dir>\<Station>\<Name>.scl`.
|
||||||
@@ -315,3 +316,21 @@ Jeder Lauf schreibt `log\awl2scl_<Zeitstempel>.log` mit:
|
|||||||
- **Fehler**.
|
- **Fehler**.
|
||||||
|
|
||||||
Bei `--globals2params` zusätzlich der Pfad der toChange-Liste.
|
Bei `--globals2params` zusätzlich der Pfad der toChange-Liste.
|
||||||
|
|
||||||
|
Mit `--show-missing` wird am Ende zusätzlich auf der **Konsole** (nicht nur im
|
||||||
|
Log) eine kompakte Liste aller nicht übersetzten Bausteine ausgegeben — sowohl
|
||||||
|
`manuelle Prüfung nötig` als auch echte `Fehler`, je mit Grund:
|
||||||
|
|
||||||
|
```text
|
||||||
|
======================================================================
|
||||||
|
Nicht uebersetzt (2)
|
||||||
|
======================================================================
|
||||||
|
MANUELL [B] =A01+UH06-KF00\Programmbausteine\Anlage\AMR_Bereich.awl
|
||||||
|
Grund: Timer-Mnemonik SE nicht unterstuetzt
|
||||||
|
MANUELL [C] =A01+UH06-KF00\Programmbausteine\Module\Set_Input.awl
|
||||||
|
Grund: registerindirekter/zeigerbasierter Operand: = E[ #AR1Zeiger]
|
||||||
|
```
|
||||||
|
|
||||||
|
Bausteine, die nur wegen falscher Kategorie oder als reiner Datenbaustein
|
||||||
|
übersprungen wurden, zählen nicht als „nicht übersetzt" (die stehen bereits
|
||||||
|
in den eigenen Log-Abschnitten).
|
||||||
|
|||||||
+43
-1
@@ -62,7 +62,11 @@ class ParsedBlock:
|
|||||||
|
|
||||||
|
|
||||||
class NotABlockError(Exception):
|
class NotABlockError(Exception):
|
||||||
"""Datei ist keine Baustein-AWL (z.B. leere/fremde Datei)."""
|
"""Datei ist keine uebersetzbare Baustein-AWL (z.B. leere/fremde Datei)."""
|
||||||
|
|
||||||
|
|
||||||
|
class DataBlockError(NotABlockError):
|
||||||
|
"""Reiner Datenbaustein (DB) ohne Programmlogik -- nichts zu uebersetzen."""
|
||||||
|
|
||||||
|
|
||||||
# ---------------------------------------------------------------------------
|
# ---------------------------------------------------------------------------
|
||||||
@@ -138,6 +142,10 @@ def detect_format(text):
|
|||||||
# ---------------------------------------------------------------------------
|
# ---------------------------------------------------------------------------
|
||||||
|
|
||||||
HEADER_RE = re.compile(r"^===\s*(\w+)\s+(\S*):\s*(.+?)\s*\[STL\]\s*===\s*$")
|
HEADER_RE = re.compile(r"^===\s*(\w+)\s+(\S*):\s*(.+?)\s*\[STL\]\s*===\s*$")
|
||||||
|
# Kopfzeile mit beliebigem Sprach-/Typ-Tag (z.B. "[DB]") -- fuer die Erkennung
|
||||||
|
# reiner Datenbausteine, die kein STL enthalten.
|
||||||
|
ANY_HEADER_RE = re.compile(r"^===\s*(\w+)\s+(\S*):\s*(.+?)\s*\[(\w+)\]\s*===\s*$")
|
||||||
|
DATA_BLOCK_TYPES = {"GlobalDB", "InstanceDB", "DB", "ArrayDB"}
|
||||||
NW_RE = re.compile(r"^---\s*NW\s*\d+:\s*(.*?)\s*---\s*$")
|
NW_RE = re.compile(r"^---\s*NW\s*\d+:\s*(.*?)\s*---\s*$")
|
||||||
STMT_RE = re.compile(r"^(?:(\S+:)\s+)?(\S+)(?:\s+(.*))?$")
|
STMT_RE = re.compile(r"^(?:(\S+:)\s+)?(\S+)(?:\s+(.*))?$")
|
||||||
MEMBER_RE = re.compile(r'^(\s*)(\S+|"[^"]+")\s*:\s*(\S+)(?:\s*:=\s*(\S+))?\s*(?:$|(?<=\S)\s{2,}//\s*(.*)$)')
|
MEMBER_RE = re.compile(r'^(\s*)(\S+|"[^"]+")\s*:\s*(\S+)(?:\s*:=\s*(\S+))?\s*(?:$|(?<=\S)\s{2,}//\s*(.*)$)')
|
||||||
@@ -148,6 +156,10 @@ def parse_rendered(text):
|
|||||||
i = 0
|
i = 0
|
||||||
m = HEADER_RE.match(lines[0].strip())
|
m = HEADER_RE.match(lines[0].strip())
|
||||||
if not m:
|
if not m:
|
||||||
|
any_m = ANY_HEADER_RE.match(lines[0].strip())
|
||||||
|
if any_m and (any_m.group(4) == "DB" or any_m.group(1) in DATA_BLOCK_TYPES):
|
||||||
|
raise DataBlockError(
|
||||||
|
f"Datenbaustein ({any_m.group(1)} {any_m.group(2)}: {any_m.group(3)}) - keine Logik")
|
||||||
raise NotABlockError("Kopfzeile nicht erkannt (gerendertes Format)")
|
raise NotABlockError("Kopfzeile nicht erkannt (gerendertes Format)")
|
||||||
btype, num, name = m.group(1), m.group(2), m.group(3)
|
btype, num, name = m.group(1), m.group(2), m.group(3)
|
||||||
i = 1
|
i = 1
|
||||||
@@ -274,6 +286,9 @@ def parse_native(text):
|
|||||||
i = 0
|
i = 0
|
||||||
mh = NATIVE_HEADER_RE.match(lines[0].strip())
|
mh = NATIVE_HEADER_RE.match(lines[0].strip())
|
||||||
if not mh:
|
if not mh:
|
||||||
|
mdb = re.match(r'^DATA_BLOCK\s+"([^"]+)"', lines[0].strip())
|
||||||
|
if mdb:
|
||||||
|
raise DataBlockError(f"Datenbaustein (DATA_BLOCK {mdb.group(1)}) - keine Logik")
|
||||||
raise NotABlockError("Kopfzeile nicht erkannt (natives Format)")
|
raise NotABlockError("Kopfzeile nicht erkannt (natives Format)")
|
||||||
btype = {"FUNCTION_BLOCK": "FB", "FUNCTION": "FC", "ORGANIZATION_BLOCK": "OB"}[mh.group(1)]
|
btype = {"FUNCTION_BLOCK": "FB", "FUNCTION": "FC", "ORGANIZATION_BLOCK": "OB"}[mh.group(1)]
|
||||||
name = mh.group(2)
|
name = mh.group(2)
|
||||||
@@ -1007,6 +1022,9 @@ def _is_generated(scl_path):
|
|||||||
def process_file(awl_path, requested_categories, target_dir, console, opts):
|
def process_file(awl_path, requested_categories, target_dir, console, opts):
|
||||||
try:
|
try:
|
||||||
parsed = parse_awl_file(awl_path)
|
parsed = parse_awl_file(awl_path)
|
||||||
|
except DataBlockError as exc:
|
||||||
|
console(f"UEBERSPRUNGEN [Datenbaustein, keine Logik] {awl_path}: {exc}")
|
||||||
|
return Result(awl_path, Outcome.SKIPPED_CATEGORY, reason=f"Datenbaustein (no logic): {exc}")
|
||||||
except NotABlockError as exc:
|
except NotABlockError as exc:
|
||||||
console(f"UEBERSPRUNGEN [kein Baustein] {awl_path}: {exc}")
|
console(f"UEBERSPRUNGEN [kein Baustein] {awl_path}: {exc}")
|
||||||
return Result(awl_path, Outcome.SKIPPED_CATEGORY, reason=str(exc))
|
return Result(awl_path, Outcome.SKIPPED_CATEGORY, reason=str(exc))
|
||||||
@@ -1203,6 +1221,9 @@ def main(argv=None):
|
|||||||
parser.add_argument("--tochange", type=Path, default=None,
|
parser.add_argument("--tochange", type=Path, default=None,
|
||||||
help="Pfad der toChange-Liste (Default: <Projekt>/data/globals2params_tochange.json)")
|
help="Pfad der toChange-Liste (Default: <Projekt>/data/globals2params_tochange.json)")
|
||||||
parser.add_argument("--log", type=Path, help="Pfad der Log-Datei")
|
parser.add_argument("--log", type=Path, help="Pfad der Log-Datei")
|
||||||
|
parser.add_argument("--show-missing", action="store_true",
|
||||||
|
help="Am Ende alle nicht uebersetzten Bausteine (manuelle Pruefung + Fehler) "
|
||||||
|
"mit Grund auf der Konsole auflisten")
|
||||||
args = parser.parse_args(argv)
|
args = parser.parse_args(argv)
|
||||||
|
|
||||||
targets = list(args.files)
|
targets = list(args.files)
|
||||||
@@ -1252,8 +1273,29 @@ def main(argv=None):
|
|||||||
if args.globals2params and store is not None:
|
if args.globals2params and store is not None:
|
||||||
print(f"toChange-Liste: {store.path}")
|
print(f"toChange-Liste: {store.path}")
|
||||||
print(f"Log: {log_path}")
|
print(f"Log: {log_path}")
|
||||||
|
|
||||||
|
if args.show_missing:
|
||||||
|
print_missing(results)
|
||||||
|
|
||||||
return 1 if n_err else 0
|
return 1 if n_err else 0
|
||||||
|
|
||||||
|
|
||||||
|
def print_missing(results):
|
||||||
|
"""Listet alle nicht uebersetzten Bausteine (manuelle Pruefung + Fehler) mit Grund auf."""
|
||||||
|
missing = [r for r in results if r.outcome in (Outcome.MANUAL_REVIEW, Outcome.ERROR)]
|
||||||
|
print()
|
||||||
|
print("=" * 70)
|
||||||
|
print(f"Nicht uebersetzt ({len(missing)})")
|
||||||
|
print("=" * 70)
|
||||||
|
if not missing:
|
||||||
|
print("(keine)")
|
||||||
|
return
|
||||||
|
for r in sorted(missing, key=lambda r: str(r.path)):
|
||||||
|
tag = "MANUELL" if r.outcome == Outcome.MANUAL_REVIEW else "FEHLER "
|
||||||
|
cat = f"[{r.category}] " if r.category else ""
|
||||||
|
print(f"{tag} {cat}{r.path}")
|
||||||
|
print(f" Grund: {r.reason}")
|
||||||
|
|
||||||
|
|
||||||
if __name__ == "__main__":
|
if __name__ == "__main__":
|
||||||
sys.exit(main())
|
sys.exit(main())
|
||||||
|
|||||||
Reference in New Issue
Block a user