From 40896802af9f20658a362ac0a0af962a582ad40f Mon Sep 17 00:00:00 2001
From: Stefan Rueger <stefan.rueger@urclocks.com>
Date: Wed, 31 Aug 2022 11:29:06 +0100
Subject: [PATCH] Allow integer expressions in config file where numbers are
 expected

Notable exceptions are for pin numbers and where numbers are separated by
space only, eg, in signature and readback assignments.
---
 src/avrdude.conf.in  | 148 +++++++++++++++++++++----------------------
 src/config_gram.y    | 132 +++++++++++++++++++-------------------
 src/doc/avrdude.texi | 125 ++++++++++++++++++++----------------
 src/lexer.l          |   2 +-
 4 files changed, 213 insertions(+), 194 deletions(-)

diff --git a/src/avrdude.conf.in b/src/avrdude.conf.in
index df64dfea..1152af77 100644
--- a/src/avrdude.conf.in
+++ b/src/avrdude.conf.in
@@ -17,51 +17,49 @@
 # Possible entry formats are:
 #
 #   programmer
-#       parent <id>                                 # optional parent
-#       id       = <id1> [, <id2> [, <id3>] ...] ;  # <idN> are quoted strings
-#       desc     = <description> ;                  # quoted string
-#       type     = <type>;                          # programmer type, quoted string
-#                                                   # supported types can be listed by "-c ?type"
-#       prog_modes = PM_<i/f> {| PM_<i/f>}          # interfaces, eg, PM_SPM|PM_PDI (1)
+#       parent <id>                               # optional parent
+#       id       = <id1> [, <id2> ... ] ;         # <idN> are quoted strings
+#       desc     = <description> ;                # quoted string
+#       type     = <type>;                        # programmer type, quoted string
+#                                                 # supported types can be listed by "-c ?type"
+#       prog_modes = PM_<i/f> {| PM_<i/f>}        # interfaces, eg, PM_SPM|PM_PDI (1)
 #       connection_type = parallel | serial | usb | spi
-#       baudrate = <num> ;                          # baudrate for avr910-programmer
-#       vcc      = <pin1> [, <pin2> ... ] ;         # pin number(s)
-#       buff     = <pin1> [, <pin2> ... ] ;         # pin number(s)
-#       reset    = <pin> ;                          # pin number
-#       sck      = <pin> ;                          # pin number
-#       mosi     = <pin> ;                          # pin number
-#       miso     = <pin> ;                          # pin number
-#       errled   = <pin> ;                          # pin number
-#       rdyled   = <pin> ;                          # pin number
-#       pgmled   = <pin> ;                          # pin number
-#       vfyled   = <pin> ;                          # pin number
-#       usbvid   = <hexnum> ;                       # USB VID (Vendor ID)
-#       usbpid   = <hexnum> [, <hexnum> ...] ;      # USB PID (Product ID) (2)
-#       usbdev   = <interface> ;                    # USB interface or other device info
-#       usbvendor = <vendorname> ;                  # USB Vendor Name
-#       usbproduct = <productname> ;                # USB Product Name
-#       usbsn    = <serialno> ;                     # USB Serial Number
-#       hvupdi_support = <num> [, <num>, ... ] ;    # UPDI HV Variants Support
+#       baudrate = <num> ;                        # baudrate for avr910-programmer
+#       vcc      = <pin1> [, <pin2> ... ] ;       # pin number(s)
+#       buff     = <pin1> [, <pin2> ... ] ;       # pin number(s)
+#       reset    = <pin> ;                        # pin number
+#       sck      = <pin> ;                        # pin number
+#       mosi     = <pin> ;                        # pin number
+#       miso     = <pin> ;                        # pin number
+#       errled   = <pin> ;                        # pin number
+#       rdyled   = <pin> ;                        # pin number
+#       pgmled   = <pin> ;                        # pin number
+#       vfyled   = <pin> ;                        # pin number
+#       usbvid   = <hexnum> ;                     # USB VID (Vendor ID)
+#       usbpid   = <hexnum> [, <hexnum> ...] ;    # USB PID (Product ID) (2)
+#       usbdev   = <interface> ;                  # USB interface or other device info
+#       usbvendor = <vendorname> ;                # USB Vendor Name
+#       usbproduct = <productname> ;              # USB Product Name
+#       usbsn    = <serialno> ;                   # USB Serial Number
+#       hvupdi_support = <num> [, <num>, ... ] ;  # UPDI HV Variants Support
 #   ;
 #
-#       # To invert a bit, use = ~ <num>, the spaces are important.
-#       # For a pin list all pins must be inverted.
-#       # A single pin can be specified as usual = ~ <num>, for lists
-#       # specify it as follows = ~ ( <num> [, <num2> ... ] ).
-#       #
-#       # (1) The following program modes are known:
-#       #  - PM_SPM: Bootloaders, self-programming with SPM opcodes or NVM Controllers
-#       #  - PM_TPI: Tiny Programming Interface (t4, t5, t9, t10, t20, t40, t102, t104)
-#       #  - PM_ISP: SPI programming for In-System Programming (almost all classic parts)
-#       #  - PM_PDI: Program and Debug Interface (xmega parts)
-#       #  - PM_UPDI: Unified Program and Debug Interface
-#       #  - PM_HVSP: High Voltage Serial Programming (some classic parts)
-#       #  - PM_HVPP: High Voltage Parallel Programming (most non-HVSP classic parts)
-#       #  - PM_debugWIRE: Simpler alternative to JTAG (a subset of HVPP/HVSP parts)
-#       #  - PM_JTAG: Joint Test Action Group standard (some classic parts, some xmega)
-#       #  - PM_aWire: AVR32 parts
-#       #
-#       # (2) Not all programmer types can process a list of PIDs
+#   # To invert a pin use = ~ <num>
+#   # To invert a pin list (all pins get inverted) use ~ ( <num1> [, <num2> ... ] )
+#   #
+#   # (1) The following program modes are known:
+#   #  - PM_SPM: Bootloaders, self-programming with SPM opcodes or NVM Controllers
+#   #  - PM_TPI: Tiny Programming Interface (t4, t5, t9, t10, t20, t40, t102, t104)
+#   #  - PM_ISP: SPI programming for In-System Programming (almost all classic parts)
+#   #  - PM_PDI: Program and Debug Interface (xmega parts)
+#   #  - PM_UPDI: Unified Program and Debug Interface
+#   #  - PM_HVSP: High Voltage Serial Programming (some classic parts)
+#   #  - PM_HVPP: High Voltage Parallel Programming (most non-HVSP classic parts)
+#   #  - PM_debugWIRE: Simpler alternative to JTAG (a subset of HVPP/HVSP parts)
+#   #  - PM_JTAG: Joint Test Action Group standard (some classic parts, some xmega)
+#   #  - PM_aWire: AVR32 parts
+#   #
+#   # (2) Not all programmer types can process a list of PIDs
 #
 #   part
 #       desc             = <description> ;        # quoted string
@@ -75,13 +73,12 @@
 #       devicecode       = <num> ;                # deprecated, use stk500_devcode
 #       stk500_devcode   = <num> ;                # numeric
 #       avr910_devcode   = <num> ;                # numeric
-#       has_jtag         = <yes/no> ;             # part has JTAG i/f
-#       has_debugwire    = <yes/no> ;             # part has debugWire i/f
-#       has_pdi          = <yes/no> ;             # part has PDI i/f
-#       has_updi         = <yes/no> ;             # part has UPDI i/f
-#       has_tpi          = <yes/no> ;             # part has TPI i/f
-#       is_avr32         = <yes/no> ;             # AVR32 part
-#
+#       has_jtag         = <yes/no> ;             # part has JTAG i/f (deprecated, use prog_modes)
+#       has_debugwire    = <yes/no> ;             # part has debugWire i/f (deprecated, use prog_modes)
+#       has_pdi          = <yes/no> ;             # part has PDI i/f (deprecated, use prog_modes)
+#       has_updi         = <yes/no> ;             # part has UPDI i/f (deprecated, use prog_modes)
+#       has_tpi          = <yes/no> ;             # part has TPI i/f (deprecated, use prog_modes)
+#       is_avr32         = <yes/no> ;             # AVR32 part (deprecated, use prog_modes)
 #       is_at90s1200     = <yes/no> ;             # AT90S1200 part
 #       signature        = <num> <num> <num> ;    # signature bytes
 #       usbpid           = <num> ;                # DFU USB PID
@@ -94,7 +91,7 @@
 #       bs2              = <num> ;                # pin name in hex, i.e., 0xA0
 #       serial           = <yes/no> ;             # can use serial downloading
 #       parallel         = <yes/no/pseudo> ;      # can use par. programming
-#       # STK500v2 parameters, to be taken from Atmel's XML files
+#       # STK500v2 parameters, to be taken from Atmel's ATDF files
 #       timeout          = <num> ;
 #       stabdelay        = <num> ;
 #       cmdexedelay      = <num> ;
@@ -106,13 +103,13 @@
 #       postdelay        = <num> ;
 #       pollmethod       = <num> ;
 #       hvspcmdexedelay  = <num> ;
-#       # STK500v2 HV programming parameters, from XML
-#       pp_controlstack  = <num>, <num>, ... ;  # PP only
-#       hvsp_controlstack = <num>, <num>, ... ; # HVSP only
+#       # STK500v2 HV programming parameters, from ATDFs
+#       pp_controlstack  = <num>, <num>, ... ;    # PP only
+#       hvsp_controlstack = <num>, <num>, ... ;   # HVSP only
 #       flash_instr      = <num>, <num>, <num> ;
 #       eeprom_instr     = <num>, <num>, ... ;
 #       hventerstabdelay = <num> ;
-#       progmodedelay    = <num> ;              # PP only
+#       progmodedelay    = <num> ;                # PP only
 #       latchcycles      = <num> ;
 #       togglevtg        = <num> ;
 #       poweroffdelay    = <num> ;
@@ -120,21 +117,21 @@
 #       resetdelayus     = <num> ;
 #       hvleavestabdelay = <num> ;
 #       resetdelay       = <num> ;
-#       synchcycles      = <num> ;               # HVSP only
-#       chiperasepulsewidth = <num> ;            # PP only
+#       synchcycles      = <num> ;                # HVSP only
+#       chiperasepulsewidth = <num> ;             # PP only
 #       chiperasepolltimeout = <num> ;
-#       chiperasetime    = <num> ;               # HVSP only
-#       programfusepulsewidth = <num> ;          # PP only
+#       chiperasetime    = <num> ;                # HVSP only
+#       programfusepulsewidth = <num> ;           # PP only
 #       programfusepolltimeout = <num> ;
-#       programlockpulsewidth = <num> ;          # PP only
+#       programlockpulsewidth = <num> ;           # PP only
 #       programlockpolltimeout = <num> ;
-#       # JTAG ICE mkII parameters, also from XML files
+#       # JTAG ICE mkII parameters, also from ATDF files
 #       allowfullpagebitstream = <yes/no> ;
 #       enablepageprogramming = <yes/no> ;
-#       idr              = <num> ;               # IO addr of IDR (OCD) reg
-#       rampz            = <num> ;               # IO addr of RAMPZ reg
-#       spmcr            = <num> ;               # mem addr of SPMC[S]R reg
-#       eecr             = <num> ;               # mem addr of EECR reg only when != 0x3f
+#       idr              = <num> ;                # IO addr of IDR (OCD) reg
+#       rampz            = <num> ;                # IO addr of RAMPZ reg
+#       spmcr            = <num> ;                # mem addr of SPMC[S]R reg
+#       eecr             = <num> ;                # mem addr of EECR reg only when != 0x3f
 #       mcu_base         = <num> ;
 #       nvm_base         = <num> ;
 #       ocd_base         = <num> ;
@@ -154,7 +151,7 @@
 #           readback_p1     = <num> ;             # byte value (first component)
 #           readback_p2     = <num> ;             # byte value (second component)
 #           pwroff_after_write = <yes/no> ;       # yes/no
-#           mode            = <num> ;             # STK500 v2 file parameter, to be taken from Atmel's XML files
+#           mode            = <num> ;             # STK500 v2 file parameter from ATDF files
 #           delay           = <num> ;             #   "
 #           blocksize       = <num> ;             #   "
 #           readsize        = <num> ;             #   "
@@ -171,10 +168,13 @@
 #   ;
 #
 # If any of the above parameters are not specified, the default value
-# of 0 is used for numerics (except for hvupdi_variant and ocdrev,
-# where the default value is -1) or the empty string ("") for string
-# values.  If a required parameter is left empty, AVRDUDE will
-# complain.
+# of 0 is used for numerics (except for mcuid, hvupdi_variant and
+# ocdrev, where the default value is -1) or the empty string "" for
+# string values. If a required parameter is left empty, AVRDUDE will
+# complain. Almost all occurrences of numbers (with the exception of
+# pin numbers and where they are separated by space, eg, in signature
+# and readback) can also be given as simple expressions involving
+# arithemtic and bitwise operators.
 #
 # Parts can also inherit parameters from previously defined parts
 # using the following syntax. In this case specified integer and
@@ -185,7 +185,7 @@
 # memory definition is extended, and components overwritten with new
 # values. Assigning NULL removes an inherited SPI instruction format,
 # memory definition, control stack, eeprom or flash instruction, eg,
-# as in  memory "efuse" = NULL;
+# as in memory "efuse" = NULL;
 #
 #   part parent <id>                              # quoted string
 #       id               = <id> ;                 # quoted string
@@ -195,16 +195,16 @@
 # NOTES:
 #   * 'devicecode' is the device code used by the STK500 (see codes
 #       listed below)
-#   * Not all memory types will implement all instructions.
-#   * AVR Fuse bits and Lock bits are implemented as a type of memory.
+#   * Not all memory types will implement all instructions
+#   * AVR Fuse bits and Lock bits are implemented as a type of memory
 #   * Example memory types are:
 #       "flash", "eeprom", "fuse", "lfuse" (low fuse), "hfuse" (high
 #       fuse), "signature", "calibration", "lock"
 #   * The memory type specified on the avrdude command line must match
-#     one of the memory types defined for the specified chip.
+#     one of the memory types defined for the specified chip
 #   * The pwroff_after_write flag causes avrdude to attempt to
 #     power the device off and back on after an unsuccessful write to
-#     the affected memory area if VCC programmer pins are defined.  If
+#     the affected memory area if VCC programmer pins are defined. If
 #     VCC pins are not defined for the programmer, a message
 #     indicating that the device needs a power-cycle is printed out.
 #     This flag was added to work around a problem with the
diff --git a/src/config_gram.y b/src/config_gram.y
index 5c5a687d..ca47dab5 100644
--- a/src/config_gram.y
+++ b/src/config_gram.y
@@ -227,7 +227,7 @@ static int pin_name;
 %%
 
 number_real : 
- TKN_NUMBER {
+ numexpr {
     $$ = $1;
     /* convert value to real */
     $$->value.number_real = $$->value.number;
@@ -461,8 +461,8 @@ string_list :
 
 
 num_list :
-  TKN_NUMBER { ladd(number_list, $1); } |
-  num_list TKN_COMMA TKN_NUMBER { ladd(number_list, $3); }
+  numexpr { ladd(number_list, $1); } |
+  num_list TKN_COMMA numexpr { ladd(number_list, $3); }
 ;
 
 prog_parms :
@@ -496,7 +496,7 @@ prog_parm :
     current_prog->desc = cache_string($3->value.string);
     free_token($3);
   } |
-  K_BAUDRATE TKN_EQUAL TKN_NUMBER {
+  K_BAUDRATE TKN_EQUAL numexpr {
     {
       current_prog->baudrate = $3->value.number;
       free_token($3);
@@ -545,7 +545,7 @@ prog_parm_usb:
       free_token($3);
     }
   } |
-  K_USBVID TKN_EQUAL TKN_NUMBER {
+  K_USBVID TKN_EQUAL numexpr {
     {
       current_prog->usbvid = $3->value.number;
       free_token($3);
@@ -573,7 +573,7 @@ prog_parm_usb:
 ;
 
 usb_pid_list:
-  TKN_NUMBER {
+  numexpr {
     {
       /* overwrite pids, so clear the existing entries */
       if(current_prog->usbpid)
@@ -587,7 +587,7 @@ usb_pid_list:
       free_token($1);
     }
   } |
-  usb_pid_list TKN_COMMA TKN_NUMBER {
+  usb_pid_list TKN_COMMA numexpr {
     {
       int *ip = cfg_malloc("usb_pid_list", sizeof(int));
       *ip = $3->value.number;
@@ -602,7 +602,7 @@ prog_parm_updi:
 ;
 
 hvupdi_support_list:
-  TKN_NUMBER {
+  numexpr {
     {
       /* overwrite list entries, so clear the existing entries */
       if(current_prog->hvupdi_support)
@@ -616,7 +616,7 @@ hvupdi_support_list:
       free_token($1);
     }
   } |
-  hvupdi_support_list TKN_COMMA TKN_NUMBER {
+  hvupdi_support_list TKN_COMMA numexpr {
     {
       int *ip = cfg_malloc("hvupdi_support_list", sizeof(int));
       *ip = $3->value.number;
@@ -727,13 +727,13 @@ part_parm :
       free_token($3);
     } |
 
-  K_HVUPDI_VARIANT TKN_EQUAL TKN_NUMBER
+  K_HVUPDI_VARIANT TKN_EQUAL numexpr
     {
       current_part->hvupdi_variant = $3->value.number;
       free_token($3);
     } |
 
-  K_DEVICECODE TKN_EQUAL TKN_NUMBER {
+  K_DEVICECODE TKN_EQUAL numexpr {
     {
       yyerror("devicecode is deprecated, use "
               "stk500_devcode instead");
@@ -741,14 +741,14 @@ part_parm :
     }
   } |
 
-  K_STK500_DEVCODE TKN_EQUAL TKN_NUMBER {
+  K_STK500_DEVCODE TKN_EQUAL numexpr {
     {
       current_part->stk500_devcode = $3->value.number;
       free_token($3);
     }
   } |
 
-  K_AVR910_DEVCODE TKN_EQUAL TKN_NUMBER {
+  K_AVR910_DEVCODE TKN_EQUAL numexpr {
     {
       current_part->avr910_devcode = $3->value.number;
       free_token($3);
@@ -766,7 +766,7 @@ part_parm :
     }
   } |
 
- K_USBPID TKN_EQUAL TKN_NUMBER {
+ K_USBPID TKN_EQUAL numexpr {
     {
       current_part->usbpid = $3->value.number;
       free_token($3);
@@ -921,19 +921,19 @@ part_parm :
     }
   } |
 
-  K_CHIP_ERASE_DELAY TKN_EQUAL TKN_NUMBER
+  K_CHIP_ERASE_DELAY TKN_EQUAL numexpr
     {
       current_part->chip_erase_delay = $3->value.number;
       free_token($3);
     } |
 
-  K_PAGEL TKN_EQUAL TKN_NUMBER
+  K_PAGEL TKN_EQUAL numexpr
     {
       current_part->pagel = $3->value.number;
       free_token($3);
     } |
 
-  K_BS2 TKN_EQUAL TKN_NUMBER
+  K_BS2 TKN_EQUAL numexpr
     {
       current_part->bs2 = $3->value.number;
       free_token($3);
@@ -949,169 +949,169 @@ part_parm :
       free_tokens(2, $1, $3);
     } |
 
-  K_TIMEOUT TKN_EQUAL TKN_NUMBER
+  K_TIMEOUT TKN_EQUAL numexpr
     {
       current_part->timeout = $3->value.number;
       free_token($3);
     } |
 
-  K_STABDELAY TKN_EQUAL TKN_NUMBER
+  K_STABDELAY TKN_EQUAL numexpr
     {
       current_part->stabdelay = $3->value.number;
       free_token($3);
     } |
 
-  K_CMDEXEDELAY TKN_EQUAL TKN_NUMBER
+  K_CMDEXEDELAY TKN_EQUAL numexpr
     {
       current_part->cmdexedelay = $3->value.number;
       free_token($3);
     } |
 
-  K_HVSPCMDEXEDELAY TKN_EQUAL TKN_NUMBER
+  K_HVSPCMDEXEDELAY TKN_EQUAL numexpr
     {
       current_part->hvspcmdexedelay = $3->value.number;
       free_token($3);
     } |
 
-  K_SYNCHLOOPS TKN_EQUAL TKN_NUMBER
+  K_SYNCHLOOPS TKN_EQUAL numexpr
     {
       current_part->synchloops = $3->value.number;
       free_token($3);
     } |
 
-  K_BYTEDELAY TKN_EQUAL TKN_NUMBER
+  K_BYTEDELAY TKN_EQUAL numexpr
     {
       current_part->bytedelay = $3->value.number;
       free_token($3);
     } |
 
-  K_POLLVALUE TKN_EQUAL TKN_NUMBER
+  K_POLLVALUE TKN_EQUAL numexpr
     {
       current_part->pollvalue = $3->value.number;
       free_token($3);
     } |
 
-  K_POLLINDEX TKN_EQUAL TKN_NUMBER
+  K_POLLINDEX TKN_EQUAL numexpr
     {
       current_part->pollindex = $3->value.number;
       free_token($3);
     } |
 
-  K_PREDELAY TKN_EQUAL TKN_NUMBER
+  K_PREDELAY TKN_EQUAL numexpr
     {
       current_part->predelay = $3->value.number;
       free_token($3);
     } |
 
-  K_POSTDELAY TKN_EQUAL TKN_NUMBER
+  K_POSTDELAY TKN_EQUAL numexpr
     {
       current_part->postdelay = $3->value.number;
       free_token($3);
     } |
 
-  K_POLLMETHOD TKN_EQUAL TKN_NUMBER
+  K_POLLMETHOD TKN_EQUAL numexpr
     {
       current_part->pollmethod = $3->value.number;
       free_token($3);
     } |
 
-  K_HVENTERSTABDELAY TKN_EQUAL TKN_NUMBER
+  K_HVENTERSTABDELAY TKN_EQUAL numexpr
     {
       current_part->hventerstabdelay = $3->value.number;
       free_token($3);
     } |
 
-  K_PROGMODEDELAY TKN_EQUAL TKN_NUMBER
+  K_PROGMODEDELAY TKN_EQUAL numexpr
     {
       current_part->progmodedelay = $3->value.number;
       free_token($3);
     } |
 
-  K_LATCHCYCLES TKN_EQUAL TKN_NUMBER
+  K_LATCHCYCLES TKN_EQUAL numexpr
     {
       current_part->latchcycles = $3->value.number;
       free_token($3);
     } |
 
-  K_TOGGLEVTG TKN_EQUAL TKN_NUMBER
+  K_TOGGLEVTG TKN_EQUAL numexpr
     {
       current_part->togglevtg = $3->value.number;
       free_token($3);
     } |
 
-  K_POWEROFFDELAY TKN_EQUAL TKN_NUMBER
+  K_POWEROFFDELAY TKN_EQUAL numexpr
     {
       current_part->poweroffdelay = $3->value.number;
       free_token($3);
     } |
 
-  K_RESETDELAYMS TKN_EQUAL TKN_NUMBER
+  K_RESETDELAYMS TKN_EQUAL numexpr
     {
       current_part->resetdelayms = $3->value.number;
       free_token($3);
     } |
 
-  K_RESETDELAYUS TKN_EQUAL TKN_NUMBER
+  K_RESETDELAYUS TKN_EQUAL numexpr
     {
       current_part->resetdelayus = $3->value.number;
       free_token($3);
     } |
 
-  K_HVLEAVESTABDELAY TKN_EQUAL TKN_NUMBER
+  K_HVLEAVESTABDELAY TKN_EQUAL numexpr
     {
       current_part->hvleavestabdelay = $3->value.number;
       free_token($3);
     } |
 
-  K_RESETDELAY TKN_EQUAL TKN_NUMBER
+  K_RESETDELAY TKN_EQUAL numexpr
     {
       current_part->resetdelay = $3->value.number;
       free_token($3);
     } |
 
-  K_CHIPERASEPULSEWIDTH TKN_EQUAL TKN_NUMBER
+  K_CHIPERASEPULSEWIDTH TKN_EQUAL numexpr
     {
       current_part->chiperasepulsewidth = $3->value.number;
       free_token($3);
     } |
 
-  K_CHIPERASEPOLLTIMEOUT TKN_EQUAL TKN_NUMBER
+  K_CHIPERASEPOLLTIMEOUT TKN_EQUAL numexpr
     {
       current_part->chiperasepolltimeout = $3->value.number;
       free_token($3);
     } |
 
-  K_CHIPERASETIME TKN_EQUAL TKN_NUMBER
+  K_CHIPERASETIME TKN_EQUAL numexpr
     {
       current_part->chiperasetime = $3->value.number;
       free_token($3);
     } |
 
-  K_PROGRAMFUSEPULSEWIDTH TKN_EQUAL TKN_NUMBER
+  K_PROGRAMFUSEPULSEWIDTH TKN_EQUAL numexpr
     {
       current_part->programfusepulsewidth = $3->value.number;
       free_token($3);
     } |
 
-  K_PROGRAMFUSEPOLLTIMEOUT TKN_EQUAL TKN_NUMBER
+  K_PROGRAMFUSEPOLLTIMEOUT TKN_EQUAL numexpr
     {
       current_part->programfusepolltimeout = $3->value.number;
       free_token($3);
     } |
 
-  K_PROGRAMLOCKPULSEWIDTH TKN_EQUAL TKN_NUMBER
+  K_PROGRAMLOCKPULSEWIDTH TKN_EQUAL numexpr
     {
       current_part->programlockpulsewidth = $3->value.number;
       free_token($3);
     } |
 
-  K_PROGRAMLOCKPOLLTIMEOUT TKN_EQUAL TKN_NUMBER
+  K_PROGRAMLOCKPOLLTIMEOUT TKN_EQUAL numexpr
     {
       current_part->programlockpolltimeout = $3->value.number;
       free_token($3);
     } |
 
-  K_SYNCHCYCLES TKN_EQUAL TKN_NUMBER
+  K_SYNCHCYCLES TKN_EQUAL numexpr
     {
       current_part->synchcycles = $3->value.number;
       free_token($3);
@@ -1201,49 +1201,49 @@ part_parm :
       free_token($3);
     } |
 
-  K_IDR TKN_EQUAL TKN_NUMBER
+  K_IDR TKN_EQUAL numexpr
     {
       current_part->idr = $3->value.number;
       free_token($3);
     } |
 
-  K_RAMPZ TKN_EQUAL TKN_NUMBER
+  K_RAMPZ TKN_EQUAL numexpr
     {
       current_part->rampz = $3->value.number;
       free_token($3);
     } |
 
-  K_SPMCR TKN_EQUAL TKN_NUMBER
+  K_SPMCR TKN_EQUAL numexpr
     {
       current_part->spmcr = $3->value.number;
       free_token($3);
     } |
 
-  K_EECR TKN_EQUAL TKN_NUMBER
+  K_EECR TKN_EQUAL numexpr
     {
       current_part->eecr = $3->value.number;
       free_token($3);
     } |
 
-  K_MCU_BASE TKN_EQUAL TKN_NUMBER
+  K_MCU_BASE TKN_EQUAL numexpr
     {
       current_part->mcu_base = $3->value.number;
       free_token($3);
     } |
 
-  K_NVM_BASE TKN_EQUAL TKN_NUMBER
+  K_NVM_BASE TKN_EQUAL numexpr
     {
       current_part->nvm_base = $3->value.number;
       free_token($3);
     } |
 
- K_OCD_BASE TKN_EQUAL TKN_NUMBER
+ K_OCD_BASE TKN_EQUAL numexpr
     {
       current_part->ocd_base = $3->value.number;
       free_token($3);
     } |
 
-  K_OCDREV          TKN_EQUAL TKN_NUMBER
+  K_OCDREV          TKN_EQUAL numexpr
     {
       current_part->ocdrev = $3->value.number;
       free_token($3);
@@ -1399,14 +1399,14 @@ mem_spec :
       free_token($3);
     } |
 
-  K_SIZE            TKN_EQUAL TKN_NUMBER
+  K_SIZE            TKN_EQUAL numexpr
     {
       current_mem->size = $3->value.number;
       free_token($3);
     } |
 
 
-  K_PAGE_SIZE       TKN_EQUAL TKN_NUMBER
+  K_PAGE_SIZE       TKN_EQUAL numexpr
     {
       int ps = $3->value.number;
       if (ps <= 0)
@@ -1418,25 +1418,25 @@ mem_spec :
       free_token($3);
     } |
 
-  K_NUM_PAGES       TKN_EQUAL TKN_NUMBER
+  K_NUM_PAGES       TKN_EQUAL numexpr
     {
       current_mem->num_pages = $3->value.number;
       free_token($3);
     } |
 
-  K_OFFSET          TKN_EQUAL TKN_NUMBER
+  K_OFFSET          TKN_EQUAL numexpr
     {
       current_mem->offset = $3->value.number;
       free_token($3);
     } |
 
-  K_MIN_WRITE_DELAY TKN_EQUAL TKN_NUMBER
+  K_MIN_WRITE_DELAY TKN_EQUAL numexpr
     {
       current_mem->min_write_delay = $3->value.number;
       free_token($3);
     } |
 
-  K_MAX_WRITE_DELAY TKN_EQUAL TKN_NUMBER
+  K_MAX_WRITE_DELAY TKN_EQUAL numexpr
     {
       current_mem->max_write_delay = $3->value.number;
       free_token($3);
@@ -1456,44 +1456,44 @@ mem_spec :
       free_token($4);
     } |
 
-  K_READBACK_P1     TKN_EQUAL TKN_NUMBER
+  K_READBACK_P1     TKN_EQUAL numexpr
     {
       current_mem->readback[0] = $3->value.number;
       free_token($3);
     } |
 
-  K_READBACK_P2     TKN_EQUAL TKN_NUMBER
+  K_READBACK_P2     TKN_EQUAL numexpr
     {
       current_mem->readback[1] = $3->value.number;
       free_token($3);
     } |
 
 
-  K_MODE TKN_EQUAL TKN_NUMBER
+  K_MODE TKN_EQUAL numexpr
     {
       current_mem->mode = $3->value.number;
       free_token($3);
     } |
 
-  K_DELAY TKN_EQUAL TKN_NUMBER
+  K_DELAY TKN_EQUAL numexpr
     {
       current_mem->delay = $3->value.number;
       free_token($3);
     } |
 
-  K_BLOCKSIZE TKN_EQUAL TKN_NUMBER
+  K_BLOCKSIZE TKN_EQUAL numexpr
     {
       current_mem->blocksize = $3->value.number;
       free_token($3);
     } |
 
-  K_READSIZE TKN_EQUAL TKN_NUMBER
+  K_READSIZE TKN_EQUAL numexpr
     {
       current_mem->readsize = $3->value.number;
       free_token($3);
     } |
 
-  K_POLLINDEX TKN_EQUAL TKN_NUMBER
+  K_POLLINDEX TKN_EQUAL numexpr
     {
       current_mem->pollindex = $3->value.number;
       free_token($3);
diff --git a/src/doc/avrdude.texi b/src/doc/avrdude.texi
index 8b955d44..3bcade32 100644
--- a/src/doc/avrdude.texi
+++ b/src/doc/avrdude.texi
@@ -1694,31 +1694,31 @@ The format of the programmer definition is as follows:
 
 @smallexample
 programmer
-    parent <id>                                 # optional parent
-    id       = <id1> [, <id2> [, <id3>] ...] ;  # <idN> are quoted strings
-    desc     = <description> ;                  # quoted string
-    type     = <type>;                          # programmer type, quoted string
-                                                # supported types can be listed by "-c ?type"
-    prog_modes = PM_<i/f> @{ | PM_<i/f> @}        # interfaces, eg, PM_SPM|PM_PDI
+    parent <id>                               # optional parent
+    id       = <id1> [, <id2> ... ] ;         # <idN> are quoted strings
+    desc     = <description> ;                # quoted string
+    type     = <type>;                        # programmer type, quoted string
+                                              # supported types can be listed by "-c ?type"
+    prog_modes = PM_<i/f> @{ | PM_<i/f> @}      # interfaces, eg, PM_SPM|PM_PDI
     connection_type = parallel | serial | usb | spi
-    baudrate = <num> ;                          # baudrate for avr910-programmer
-    vcc      = <pin1> [, <pin2> ... ] ;         # pin number(s)
-    buff     = <pin1> [, <pin2> ... ] ;         # pin number(s)
-    reset    = <pin> ;                          # pin number
-    sck      = <pin> ;                          # pin number
-    mosi     = <pin> ;                          # pin number
-    miso     = <pin> ;                          # pin number
-    errled   = <pin> ;                          # pin number
-    rdyled   = <pin> ;                          # pin number
-    pgmled   = <pin> ;                          # pin number
-    vfyled   = <pin> ;                          # pin number
-    usbvid   = <hexnum> ;                       # USB VID (Vendor ID)
-    usbpid   = <hexnum> [, <hexnum> ...] ;      # USB PID (Product ID)
-    usbdev   = <interface> ;                    # USB interface or other device info
-    usbvendor = <vendorname> ;                  # USB Vendor Name
-    usbproduct = <productname> ;                # USB Product Name
-    usbsn    = <serialno> ;                     # USB Serial Number
-    hvupdi_support = <num> [, <num>, ... ] ;    # UPDI HV Variants Support
+    baudrate = <num> ;                        # baudrate for avr910-programmer
+    vcc      = <pin1> [, <pin2> ... ] ;       # pin number(s)
+    buff     = <pin1> [, <pin2> ... ] ;       # pin number(s)
+    reset    = <pin> ;                        # pin number
+    sck      = <pin> ;                        # pin number
+    mosi     = <pin> ;                        # pin number
+    miso     = <pin> ;                        # pin number
+    errled   = <pin> ;                        # pin number
+    rdyled   = <pin> ;                        # pin number
+    pgmled   = <pin> ;                        # pin number
+    vfyled   = <pin> ;                        # pin number
+    usbvid   = <hexnum> ;                     # USB VID (Vendor ID)
+    usbpid   = <hexnum> [, <hexnum> ...] ;    # USB PID (Product ID)
+    usbdev   = <interface> ;                  # USB interface or other device info
+    usbvendor = <vendorname> ;                # USB Vendor Name
+    usbproduct = <productname> ;              # USB Product Name
+    usbsn    = <serialno> ;                   # USB Serial Number
+    hvupdi_support = <num> [, <num>, ... ] ;  # UPDI HV Variants Support
 ;
 @end smallexample
 
@@ -1742,7 +1742,8 @@ Known programming modes are
 @end itemize
 
 @noindent
-To invert a bit in the pin definitions, use @code{= ~ <num>}.
+To invert a bit in the pin definitions, use @code{= ~ <num>}. To invert a pin list
+(all pins get inverted) use @code{~ ( <num1> [, <num2> ... ] )}.
 
 @noindent
 Not all programmer types can handle a list of USB PIDs.
@@ -1765,7 +1766,7 @@ part
     desc             = <description> ;        # quoted string
     id               = <id> ;                 # quoted string
     family_id        = <id> ;                 # quoted string, eg, "megaAVR" or "tinyAVR"
-    prog_modes       = PM_<i/f> @{ | PM_<i/f> @} # interfaces, eg, PM_SPM|PM_ISP|PM_HVPP|PM_debugWIRE
+    prog_modes       = PM_<i/f> @{| PM_<i/f>@}  # interfaces, eg, PM_SPM|PM_ISP|PM_HVPP|PM_debugWIRE
     mcuid            = <num>;                 # unique id in 0..2039 for 8-bit AVRs
     n_interrupts     = <num>;                 # number of interrupts, used for vector bootloaders
     n_page_erase     = <num>;                 # if set, number of pages erased during NVM erase
@@ -1773,12 +1774,12 @@ part
     devicecode       = <num> ;                # deprecated, use stk500_devcode
     stk500_devcode   = <num> ;                # numeric
     avr910_devcode   = <num> ;                # numeric
-    has_jtag         = <yes/no> ;             # part has JTAG i/f
-    has_debugwire    = <yes/no> ;             # part has debugWire i/f
-    has_pdi          = <yes/no> ;             # part has PDI i/f
-    has_updi         = <yes/no> ;             # part has UPDI i/f
-    has_tpi          = <yes/no> ;             # part has TPI i/f
-    is_avr32         = <yes/no> ;             # AVR32 part
+    has_jtag         = <yes/no> ;             # part has JTAG i/f (deprecated, use prog_modes)
+    has_debugwire    = <yes/no> ;             # part has debugWire i/f (deprecated, use prog_modes)
+    has_pdi          = <yes/no> ;             # part has PDI i/f (deprecated, use prog_modes)
+    has_updi         = <yes/no> ;             # part has UPDI i/f (deprecated, use prog_modes)
+    has_tpi          = <yes/no> ;             # part has TPI i/f (deprecated, use prog_modes)
+    is_avr32         = <yes/no> ;             # AVR32 part (deprecated, use prog_modes)
     is_at90s1200     = <yes/no> ;             # AT90S1200 part
     signature        = <num> <num> <num> ;    # signature bytes
     usbpid           = <num> ;                # DFU USB PID
@@ -1791,7 +1792,7 @@ part
     bs2              = <num> ;                # pin name in hex, i.e., 0xA0
     serial           = <yes/no> ;             # can use serial downloading
     parallel         = <yes/no/pseudo> ;      # can use par. programming
-    # STK500v2 parameters, to be taken from Atmel's XML files
+    # STK500v2 parameters, to be taken from Atmel's ATDF files
     timeout          = <num> ;
     stabdelay        = <num> ;
     cmdexedelay      = <num> ;
@@ -1803,13 +1804,13 @@ part
     postdelay        = <num> ;
     pollmethod       = <num> ;
     hvspcmdexedelay  = <num> ;
-    # STK500v2 HV programming parameters, from XML
-    pp_controlstack  = <num>, <num>, ... ;  # PP only
-    hvsp_controlstack = <num>, <num>, ... ; # HVSP only
+    # STK500v2 HV programming parameters, from ATDFs
+    pp_controlstack  = <num>, <num>, ... ;    # PP only
+    hvsp_controlstack = <num>, <num>, ... ;   # HVSP only
     flash_instr      = <num>, <num>, <num> ;
     eeprom_instr     = <num>, <num>, ... ;
     hventerstabdelay = <num> ;
-    progmodedelay    = <num> ;              # PP only
+    progmodedelay    = <num> ;                # PP only
     latchcycles      = <num> ;
     togglevtg        = <num> ;
     poweroffdelay    = <num> ;
@@ -1817,21 +1818,21 @@ part
     resetdelayus     = <num> ;
     hvleavestabdelay = <num> ;
     resetdelay       = <num> ;
-    synchcycles      = <num> ;               # HVSP only
-    chiperasepulsewidth = <num> ;            # PP only
+    synchcycles      = <num> ;                # HVSP only
+    chiperasepulsewidth = <num> ;             # PP only
     chiperasepolltimeout = <num> ;
-    chiperasetime    = <num> ;               # HVSP only
-    programfusepulsewidth = <num> ;          # PP only
+    chiperasetime    = <num> ;                # HVSP only
+    programfusepulsewidth = <num> ;           # PP only
     programfusepolltimeout = <num> ;
-    programlockpulsewidth = <num> ;          # PP only
+    programlockpulsewidth = <num> ;           # PP only
     programlockpolltimeout = <num> ;
-    # JTAG ICE mkII parameters, also from XML files
+    # JTAG ICE mkII parameters, also from ATDF files
     allowfullpagebitstream = <yes/no> ;
     enablepageprogramming = <yes/no> ;
-    idr              = <num> ;               # IO addr of IDR (OCD) reg
-    rampz            = <num> ;               # IO addr of RAMPZ reg
-    spmcr            = <num> ;               # mem addr of SPMC[S]R reg
-    eecr             = <num> ;               # mem addr of EECR reg only when != 0x3f
+    idr              = <num> ;                # IO addr of IDR (OCD) reg
+    rampz            = <num> ;                # IO addr of RAMPZ reg
+    spmcr            = <num> ;                # mem addr of SPMC[S]R reg
+    eecr             = <num> ;                # mem addr of EECR reg only when != 0x3f
     mcu_base         = <num> ;
     nvm_base         = <num> ;
     ocd_base         = <num> ;
@@ -1851,7 +1852,7 @@ part
         readback_p1     = <num> ;             # byte value (first component)
         readback_p2     = <num> ;             # byte value (second component)
         pwroff_after_write = <yes/no> ;       # yes/no
-        mode            = <num> ;             # STK500 v2 file parameter from Atmel's XML files
+        mode            = <num> ;             # STK500 v2 file parameter from ATDF files
         delay           = <num> ;             #   "
         blocksize       = <num> ;             #   "
         readsize        = <num> ;             #   "
@@ -1868,6 +1869,16 @@ part
 ;
 @end smallexample
 
+@noindent
+If any of the above parameters are not specified, the default value
+of 0 is used for numerics (except for @code{mcuid}, @code{hvupdi_variant} and @code{ocdrev},
+where the default value is -1) or the empty string @code{""} for string
+values. If a required parameter is left empty, AVRDUDE will complain.
+Almost all occurrences of numbers (with the exception of pin numbers
+and where they are separated by space, eg, in signature and readback)
+can also be given as simple expressions involving arithemtic and
+bitwise operators.
+
 @menu
 * Parent Part::
 * Instruction Format::
@@ -1880,11 +1891,19 @@ part
 @subsection Parent Part
 
 @noindent
-Parts can also inherit parameters from previously defined parts
-using the following syntax. In this case specified integer and 
-string values override parameter values from the parent part. New 
-memory definitions are added to the definitions inherited from the 
-parent.
+Parts can also inherit parameters from previously defined parts using
+the following syntax. In this case specified integer and  string values
+override parameter values from the parent part. New  memory definitions
+are added to the definitions inherited from the  parent. If, however, a
+new memory definition refers to an existing one of the same name for
+that part then, from v7.1, the existing memory definition is extended,
+and components overwritten with new values. Assigning @code{NULL}
+removes an inherited SPI instruction format, memory definition, control
+stack, eeprom or flash instruction, eg, as in @code{memory "efuse" =
+NULL;}
+
+@noindent
+Example format for part inheritance:
 
 @smallexample
    part parent <id>                              # quoted string
diff --git a/src/lexer.l b/src/lexer.l
index 65b7a451..02fa6008 100644
--- a/src/lexer.l
+++ b/src/lexer.l
@@ -63,7 +63,7 @@ SIGN     [+-]
 
 %%
 
-{SIGN}?{DIGIT}+            { yylval = new_number(yytext); return TKN_NUMBER; }
+{DIGIT}+                   { yylval = new_number(yytext); return TKN_NUMBER; /* sign is treated in grammar */ }
 {SIGN}?{DIGIT}+"."{DIGIT}* { yylval = new_number_real(yytext); return TKN_NUMBER_REAL; }
 {SIGN}?"."{DIGIT}+         { yylval = new_number_real(yytext); return TKN_NUMBER_REAL; }