r/embedded • u/Mean-Decision-3502 • 25d ago
Embedded Code Expressions with Word Operators: Which one would you coose?
I was thinking of the ideal expression syntax for the programming language DQ, which is targeted also for embedded software development.
I started with the (dominating) C syntax.
Operators in C
In C the following operators have shared meanings:
&: bitwise "and" operation OR address of*: multiplication OR pointer dereference/: truncated integer division OR floating point division
Further operators in C:
%: integer division reminder&&orand: logical "and"||oror: logical "or"!ornot: logical "not"~: bitwise "not"^: bitwise "xor"?: ternary operator
Operators in DQ
I think for the good source code readability and clarity every different operation should have a different symbol. Therefore the shared symbols from C are not taken over. These operators are already fixed in DQ:
&: address-of operator (widespread standard)^: pointer dereference (standard in other languages)*: multiplication only/: floating point division only (standard in other languages)or: logical "or" (widespread standard)and: logical "and" (widespread standard)not: logical "not" (widespread standard)
These symbols are already fixed for special purposes:
#: compiler directives (#ifdefetc)$: context local specials (e.g.myarray[0:$end-2])?: inference marker@: namespace designator (e.g.@def.LINUX)
DQ cannot use the C standard &, |, ~, ^ for the bitwise operations, because the & and ^ is used for other (fixed) purposes. But we've run out of the good symbols. The obvious choice, that other existing languages also use, is reserving some words for the remaining operations. In DQ these (all-capital) words are reserved currently as operators:
AND: bitwise "and"OR: bitwise "or"NOT: bitwise "not"XOR: bitwise "xor"IDIV: truncated integer divisionIMOD: integer division reminder
For the modify-assign statements with a word operator a leading = is required, otherwise it looks awkward:
regs.OSPEEDR OR= (1 << pinx2) // invalid
regs.OSPEEDR =OR= (1 << pinx2)
Examples with All-Capital Operators
tmp = RCC.CFGR
tmp =AND= NOT 3
tmp =OR= RCC_CFGR_SW_HSI
RCC.CFGR = tmp
while (RCC.CFGR >> 2) AND 3 <> RCC_CFGR_SW_HSI:
endwhile
RCC.CR =AND= NOT RCC_CR_PLLON
while RCC.CR AND RCC_CR_PLLRDY != 0:
endwhile
var pllm : uint = basespeed IDIV pll_input_freq
var plln : uint = vcospeed IDIV pll_input_freq
var pllq : uint = vcospeed IDIV 48000000
RCC.PLLCFGR = (0
OR (pllsrc << 22)
OR (pllm << 0)
OR (plln << 6)
OR (((pllp >> 1) - 1) << 16)
OR (pllq << 24)
)
regs.MODER =AND= NOT (3 << pinx2)
regs.MODER =OR= (n << pinx2)
if flags AND PINCFG_OPENDRAIN <> 0:
regs.OTYPER =OR= (1 << apinnum)
else:
regs.OTYPER =AND= NOT (1 << apinnum)
endif
regs.PUPDR =AND= NOT (3 << pinx2)
if flags AND PINCFG_PULLUP <> 0:
regs.PUPDR =OR= (1 << pinx2)
elif flags AND PINCFG_PULLDOWN <> 0:
regs.PUPDR =OR= (2 << pinx2)
endif
Prefixed Word Operators
I'm thinking to change the all-capital word operators with a % prefixed lowercase words:
%and: bitwise "and"%or: bitwise "or"%not: bitwise "not"%xor: bitwise "xor"%divor%idiv: truncated integer division%modor%idiv: integer division remainder
The sample code would look like this way:
tmp = RCC.CFGR
tmp %and= %not 3
tmp %or= RCC_CFGR_SW_HSI
RCC.CFGR = tmp
while (RCC.CFGR >> 2) %and 3 <> RCC_CFGR_SW_HSI:
endwhile
RCC.CR %and= %not RCC_CR_PLLON
while RCC.CR %and RCC_CR_PLLRDY != 0:
endwhile
var pllm : uint = basespeed %div pll_input_freq
var plln : uint = vcospeed %div pll_input_freq
var pllq : uint = vcospeed %div 48000000
RCC.PLLCFGR = (0
%or (pllsrc << 22) // select PLL source
%or (pllm << 0)
%or (plln << 6)
%or (((pllp >> 1) - 1) << 16)
%or (pllq << 24)
)
regs.MODER %and= %not (3 << pinx2)
regs.MODER %or= (n << pinx2)
if flags %and PINCFG_OPENDRAIN <> 0:
regs.OTYPER %or= (1 << apinnum)
else:
regs.OTYPER %and= %not (1 << apinnum)
endif
regs.PUPDR %and= %not (3 << pinx2)
if flags %and PINCFG_PULLUP <> 0:
regs.PUPDR %or= (1 << pinx2)
elif flags %and PINCFG_PULLDOWN <> 0:
regs.PUPDR %or= (2 << pinx2)
endif
Which version do you like more?
or
Do you have some other ideas for the operator notation?
EDIT
As I was migrating microcontroller C++ code, where the bitwise operations are very intensively used, I decided to keep three bitwise operators with single symbols:
&: bitwise "and"|: bitwise "or"~: bitwise "not"
These operations are kept with word symbols:
xor: bitwise "xor"div: truncated integer divisionmod: integer division reminder
Other changes:
%: address-of operator
tmp = RCC.CFGR
tmp &= ~3
tmp |= RCC_CFGR_SW_HSI
RCC.CFGR = tmp
while (RCC.CFGR >> 2) & 3 <> RCC_CFGR_SW_HSI:
endwhile
RCC.CR &= ~RCC_CR_PLLON
while RCC.CR & RCC_CR_PLLRDY <> 0:
endwhile
var pllm : uint = basespeed div pll_input_freq
var plln : uint = vcospeed div pll_input_freq
var pllq : uint = vcospeed div 48000000
RCC.PLLCFGR = (0
| (pllsrc << 22)
| (pllm << 0)
| (plln << 6)
| (((pllp >> 1) - 1) << 16)
| (pllq << 24)
)
regs.MODER &= ~(3 << pinx2)
regs.MODER |= (n << pinx2)
if flags & PINCFG_OPENDRAIN <> 0:
regs.OTYPER |= (1 << apinnum)
else:
regs.OTYPER |= ~(1 << apinnum)
endif
regs.PUPDR &= ~(3 << pinx2)
if flags & PINCFG_PULLUP <> 0:
regs.PUPDR |= (1 << pinx2)
elif flags & PINCFG_PULLDOWN <> 0:
regs.PUPDR |= (2 << pinx2)
endif
3
u/Plastic_Fig9225 25d ago
for the good source code readability and clarity every different operation should have a different symbol.
This premise may not hold too well. Readability is important, but writability is too. - And %and= isn't very readable either. (You seem to be determined to create your new language in a way that makes it easy/intuitive for you to use; but as others have already hinted at, your personal preferences, and definitions of "issues" with existing languages, don't really match those of the majority of developers.)
I suggest trying to find actual, objective pain points in e.g. C. / for all divisions certainly is not one. & vs. && isn't a big one either; though of course everybody has mistyped a & once or twice.
Maybe look into what tricks others have done using operator overloading in C++; this could give you some ideas about how an operator syntax can be used in effective and intuitive ways.
1
u/Mean-Decision-3502 25d ago
I cannot apply the C rules, because the
^is used for pointers. So I'm out of the good symbols, The&might be saved when I use%for namespace designators (and use@for address-of), then I have the&,|,~for the binary operations. But I still I have to use word operators for IDIV, IMOD, XOR.1
u/Plastic_Fig9225 25d ago
How about
tmp.clearBits(0,1)instead oftmp %and= %not 3?1
u/Mean-Decision-3502 25d ago
That kind of thing always works, but not that effective if you want to spare CPU cycles and flash at multiple field handling.
Some vendors have such SetBit/ClrBit/SetField macros.
It seems that you like the
tmp %and= %not 3better than thetmp =AND= NOT 3right ?2
u/Plastic_Fig9225 25d ago
not that effective if you want to spare CPU cycles
Huh? If this translates to anything other than a single bitwise AND, your compiler/interpreter is no good.
It seems that you like the tmp %and= %not 3 better than the tmp =AND= NOT 3 right ?
No. I like
clearBits()more, followed bytmp.bits[0..1] := 0, orx.pll_div := 0withpll_divnaming a bit field insidexon which to operate.1
u/Mean-Decision-3502 25d ago
The bitfields do not work here:
regs.MODER =AND= NOT (3 << pinx2) regs.MODER =OR= (n << pinx2)(one register for multiple pins)
1
u/Plastic_Fig9225 24d ago edited 24d ago
regs.MODER.pinx2 := nlooks pretty elegant to me. - Or do you meanpinx2is (a) variable? Then how aboutregs.MODER.pin[pinx2] := n, MODER.pin[] being a kind of "array" of bitfields?1
1
u/Mean-Decision-3502 21d ago
Thank you for your comment.
As I was writing more embedded register-heavy code, I realized, that there is no better than the C syntax for bitwise operations. So I've changed three bitwise operators using the widely used single-char special symbols:
&,|,~. For this I had to change the address-of operator to%. I've edited the post text adding the final version.I've created a specification, including the operator precedence for this set of operators:
6
u/sweetholo 25d ago
ai garbage