Last active
November 21, 2024 16:15
-
-
Save ddribin/6be9227772295000cf45217302a0554d to your computer and use it in GitHub Desktop.
Lark grammar and Python script for Potentiometers
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
pot : "PDB18" GANGS "-" PIN_TYPE DETENT SHAFT_LENGTH SHAFT_STYLE "-" RESISTANCE TAPER | |
GANGS : "1" | "2" | |
PIN_TYPE \ | |
: "K" // PC pins, vertical 12.5mm | |
| "A" // PC pins, vertical 18.0mm | |
DETENT \ | |
: "2" // Center detents | |
| "4" // No Detents | |
// Length is in millimeters | |
SHAFT_LENGTH : "15" | "18" | "20" | "25" | "30" | |
SHAFT_STYLE \ | |
: "F" // Metal flatted | |
| "K" // Metal knurled | |
| "P" // Metal plain | |
// Standard code, e.g. "103" = "1,000" | |
RESISTANCE : DIGIT DIGIT DIGIT | |
TAPER \ | |
: "B" // Linear | |
| "A2" // Logarithmic (Audio) | |
DIGIT : "0" | "1" | "2" | "3" | "4" | "5" | "6" | "7" | "8" | "9" |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#!/usr/bin/env python3 | |
import sys | |
from typing import Any | |
from dataclasses import dataclass | |
from enum import IntEnum, StrEnum | |
from lark import Lark, Transformer, Token | |
from pathlib import Path | |
class Gang(IntEnum): | |
SINGLE = 1 | |
DUAL = 2 | |
def __str__(self) -> str: | |
match self: | |
case self.SINGLE: | |
return "Single gang" | |
case self.DUAL: | |
return "Dual gang" | |
class PinType(StrEnum): | |
PC_PINS_12_5 = "K" | |
PC_PINS_18 = "A" | |
def __str__(self) -> str: | |
match self: | |
case self.PC_PINS_12_5: | |
return "PC Pins vertical/Down Facing (12.5 mm)" | |
case self.PC_PINS_18: | |
return "PC Pins vertical/Down Facing (18.0 mm)" | |
class Detent(IntEnum): | |
CENTER_DETENT = 2 | |
NO_DETENT = 4 | |
def __str__(self) -> str: | |
match self: | |
case self.CENTER_DETENT: | |
return "Center Detent" | |
case self.NO_DETENT: | |
return "No Detent" | |
class ShaftLength(IntEnum): | |
L15 = 15 | |
L18 = 18 | |
L20 = 20 | |
L25 = 25 | |
L30 = 30 | |
def __str__(self) -> str: | |
match self: | |
case self.L15: | |
return "15 mm" | |
case self.L18: | |
return "18 mm" | |
case self.L20: | |
return "20 mm" | |
case self.L25: | |
return "25 mm" | |
case self.L30: | |
return "30 mm" | |
class ShaftStyle(StrEnum): | |
FLATTED = "F" | |
KNURLED = "K" | |
PLAIN = "P" | |
def __str__(self) -> str: | |
match self: | |
case self.FLATTED: | |
return "Metal Flatted" | |
case self.KNURLED: | |
return "Metal Knurled" | |
case self.PLAIN: | |
return "Metal Plain" | |
@dataclass(frozen=True) | |
class Resistance: | |
code: str | |
def __str__(self) -> str: | |
int_code = int(self.code) | |
(base, exponent) = divmod(int_code, 10) | |
value = base * (10**exponent) | |
return f"{value:,} ohm" | |
class Taper(StrEnum): | |
LINEAR = "B" | |
AUDIO = "A2" | |
def __str__(self) -> str: | |
match self: | |
case self.LINEAR: | |
return "Linear Taper" | |
case self.AUDIO: | |
return "Logarithmic (Audio) Taper" | |
@dataclass(frozen=True) | |
class Potentiometer: | |
gang: Gang | |
pin_type: PinType | |
detent: Detent | |
shaft_length: ShaftLength | |
shaft_style: ShaftStyle | |
resistance: Resistance | |
taper: Taper | |
def __str__(self) -> str: | |
l: list[Any] = [ | |
self.gang, | |
self.pin_type, | |
self.detent, | |
self.shaft_length, | |
self.shaft_style, | |
self.resistance, | |
self.taper, | |
] | |
s = ", ".join(str(x) for x in l) | |
return s | |
@property | |
def long_description(self) -> str: | |
lines = [ | |
f"Gang = {self.gang}", | |
f"Pin type = {self.pin_type}", | |
f"Detent = {self.detent}", | |
f"Shaft length = {self.shaft_length}", | |
f"Shaft style = {self.shaft_style}", | |
f"Resistance = {self.resistance}", | |
f"Taper = {self.taper}", | |
] | |
return "\n".join(lines) | |
class PotentiometerParser: | |
def __init__(self) -> None: | |
self._parser = Lark(Path("pot.lark").read_text(), start="pot") | |
def parse(self, string: str) -> None: | |
tree = self._parser.parse(string) | |
# print(tree.pretty()) | |
# print(tree) | |
transformer = PotentiometerTransformer() | |
poteniometer = transformer.transform(tree) | |
print(poteniometer.long_description) | |
class PotentiometerTransformer(Transformer): | |
def pot(self, arg: list[Any]) -> Potentiometer: | |
pot = Potentiometer( | |
gang=arg[0], | |
pin_type=arg[1], | |
detent=arg[2], | |
shaft_length=arg[3], | |
shaft_style=arg[4], | |
resistance=arg[5], | |
taper=arg[6], | |
) | |
return pot | |
def GANGS(self, token: Token) -> Gang: | |
return Gang(int(token)) | |
def PIN_TYPE(self, token: Token) -> PinType: | |
return PinType(str(token)) | |
def DETENT(self, token: Token) -> Detent: | |
return Detent(int(token)) | |
def SHAFT_LENGTH(self, token: Token) -> ShaftLength: | |
return ShaftLength(int(token)) | |
def SHAFT_STYLE(self, token: Token) -> ShaftStyle: | |
return ShaftStyle(str(token)) | |
def RESISTANCE(self, token: Token) -> Resistance: | |
return Resistance(str(token)) | |
def TAPER(self, token: Token) -> Taper: | |
return Taper(str(token)) | |
if __name__ == "__main__": | |
parser = PotentiometerParser() | |
parser.parse(sys.argv[1]) |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Lark: https://lark-parser.readthedocs.io/en/stable/
Source: Page 5 of https://www.bourns.com/docs/Product-Datasheets/PDB18.pdf
Example output: