; UGI Grammar v0: RFC 5234 ABNF ; Generated from ugi_registry_v0.json ; ; Compatible with abnf.dev/abnf2svg ; === Top-level === ugi-string = "ugi:" version "@" handle ":" field-list version = 1*DIGIT ["/" 1*DIGIT] ; handle: alphanumeric, hyphens, underscores, dots handle = 1*(ALPHA / DIGIT / %x2D / %x5F / %x2E) field-list = field *("," field) ; === Field dispatch === field = field-a / field-b / field-c / field-d / field-e / field-f / field-g / field-h / field-i / field-j / field-k / field-l / field-m / field-o / field-p / field-q / field-r / field-s / field-t / field-v / field-w / field-x / field-y / field-z ; === Common rules === ODIGIT = %x30-37 paid = "$" aspire = "+" ODIGIT paid-aspire = paid [aspire] modifier = paid-aspire / aspire alternative = "/" ODIGIT ; custom sub-ID: ~ followed by 2+ alpha chars custom-sub = "~" 2*ALPHA ; sub-ID: 1-4 alpha chars sub-id = 1*4ALPHA ; === Per-field rules === ; a: Age (direct) field-a = %x61 ODIGIT ; b: Build (special) field-b = %x62 ODIGIT [aspire] "/" ODIGIT [aspire] ; c: Clothing (direct) field-c = %x63 ODIGIT [alternative / aspire] ; d: Editor / IDE (multi) field-d-entry = (sub-id / custom-sub) ODIGIT [aspire] field-d = %x64 1*field-d-entry ; e: Education (direct) field-e = %x65 ODIGIT [aspire] ; f: Food / Cooking (direct) field-f = %x66 ODIGIT [modifier] ; g: Geek Specialization (special) g-domain = 2*4ALPHA ["$"] g-custom = "~" 2*ALPHA field-g = %x67 (g-domain / g-custom) *("/" (g-domain / g-custom)) ; h: Hair (multi) field-h-entry = (sub-id / custom-sub) ODIGIT [aspire] field-h = %x68 1*field-h-entry ; i: AI Stance (direct) field-i = %x69 ODIGIT ; j: Gaming (multi) field-j-entry = (sub-id / custom-sub) ODIGIT [modifier] field-j = %x6A 1*field-j-entry ; k: Books (direct) field-k = %x6B ODIGIT [aspire] ; l: Spoken Languages (multi) field-l-entry = 2ALPHA ODIGIT [modifier] field-l = %x6C 1*field-l-entry ; m: Music (multi) field-m-entry = (sub-id / custom-sub) ODIGIT field-m = %x6D 1*field-m-entry ; o: Operating System (multi) field-o-entry = (sub-id / custom-sub) ODIGIT [modifier] field-o = %x6F 1*field-o-entry ; p: Programming Languages (multi) field-p-entry = (sub-id / custom-sub) ODIGIT [modifier] field-p = %x70 1*field-p-entry ; q: Security / Hacking (direct) field-q = %x71 ODIGIT [alternative / modifier] ; r: Religion (single) field-r = %x72 (sub-id / custom-sub) ODIGIT ; s: Sex / Relationships (direct) field-s = %x73 ODIGIT [alternative / aspire] ; t: TV / Film (multi) field-t-entry = (sub-id / custom-sub) ODIGIT field-t = %x74 1*field-t-entry ; v: Politics (special) field-v = %x76 ODIGIT "/" ODIGIT ; w: Hardware (direct) field-w = %x77 ODIGIT [modifier] ; x: Comics / Manga (multi) field-x-entry = (sub-id / custom-sub) ODIGIT field-x = %x78 1*field-x-entry ; y: Fitness (direct) field-y = %x79 ODIGIT [modifier] ; z: Maker / DIY (direct) field-z = %x7A ODIGIT [modifier] ; === Block format === ugi-block = block-header CRLF block-first-line CRLF 1*(block-field-line CRLF) block-footer block-header = "------- BEGIN UGI BLOCK -------" block-footer = "-------- END UGI BLOCK --------" block-first-line = "v:" version SP "@" handle [SP block-geek-field] ; In block format, G field uses uppercase and appears on first line block-geek-field = "G" (g-domain / g-custom) *("/" (g-domain / g-custom)) block-field-line = block-field *(SP block-field) ; Block fields use uppercase code prefix repeated per sub-ID block-field = ALPHA 1*(ALPHA / DIGIT / %x24 / %x2B / %x2F / %x7E) ; === Core rules (RFC 5234) === ALPHA = %x41-5A / %x61-7A DIGIT = %x30-39 SP = %x20 CRLF = %x0D.0A / %x0A