/* description: Parses expressions. */ /* lexical grammar */ %lex %options case-insensitive %% \s+ /* skip whitespace */ (\-(webkit|moz)\-)?calc\b return 'CALC'; [a-z][a-z0-9-]*\s*\((?:(?:\"(?:\\.|[^\"\\])*\"|\'(?:\\.|[^\'\\])*\')|\([^)]*\)|[^\(\)]*)*\) return 'FUNCTION'; "*" return 'MUL'; "/" return 'DIV'; "+" return 'ADD'; "-" return 'SUB'; (([0-9]+("."[0-9]+)?|"."[0-9]+)(e(\+|-)[0-9]+)?)em\b return 'EMS'; (([0-9]+("."[0-9]+)?|"."[0-9]+)(e(\+|-)[0-9]+)?)ex\b return 'EXS'; (([0-9]+("."[0-9]+)?|"."[0-9]+)(e(\+|-)[0-9]+)?)ch\b return 'CHS'; (([0-9]+("."[0-9]+)?|"."[0-9]+)(e(\+|-)[0-9]+)?)rem\b return 'REMS'; (([0-9]+("."[0-9]+)?|"."[0-9]+)(e(\+|-)[0-9]+)?)vw\b return 'VWS'; (([0-9]+("."[0-9]+)?|"."[0-9]+)(e(\+|-)[0-9]+)?)vh\b return 'VHS'; (([0-9]+("."[0-9]+)?|"."[0-9]+)(e(\+|-)[0-9]+)?)vmin\b return 'VMINS'; (([0-9]+("."[0-9]+)?|"."[0-9]+)(e(\+|-)[0-9]+)?)vmax\b return 'VMAXS'; (([0-9]+("."[0-9]+)?|"."[0-9]+)(e(\+|-)[0-9]+)?)cm\b return 'LENGTH'; (([0-9]+("."[0-9]+)?|"."[0-9]+)(e(\+|-)[0-9]+)?)mm\b return 'LENGTH'; (([0-9]+("."[0-9]+)?|"."[0-9]+)(e(\+|-)[0-9]+)?)Q\b return 'LENGTH'; (([0-9]+("."[0-9]+)?|"."[0-9]+)(e(\+|-)[0-9]+)?)in\b return 'LENGTH'; (([0-9]+("."[0-9]+)?|"."[0-9]+)(e(\+|-)[0-9]+)?)pt\b return 'LENGTH'; (([0-9]+("."[0-9]+)?|"."[0-9]+)(e(\+|-)[0-9]+)?)pc\b return 'LENGTH'; (([0-9]+("."[0-9]+)?|"."[0-9]+)(e(\+|-)[0-9]+)?)px\b return 'LENGTH'; (([0-9]+("."[0-9]+)?|"."[0-9]+)(e(\+|-)[0-9]+)?)deg\b return 'ANGLE'; (([0-9]+("."[0-9]+)?|"."[0-9]+)(e(\+|-)[0-9]+)?)grad\b return 'ANGLE'; (([0-9]+("."[0-9]+)?|"."[0-9]+)(e(\+|-)[0-9]+)?)rad\b return 'ANGLE'; (([0-9]+("."[0-9]+)?|"."[0-9]+)(e(\+|-)[0-9]+)?)turn\b return 'ANGLE'; (([0-9]+("."[0-9]+)?|"."[0-9]+)(e(\+|-)[0-9]+)?)s\b return 'TIME'; (([0-9]+("."[0-9]+)?|"."[0-9]+)(e(\+|-)[0-9]+)?)ms\b return 'TIME'; (([0-9]+("."[0-9]+)?|"."[0-9]+)(e(\+|-)[0-9]+)?)Hz\b return 'FREQ'; (([0-9]+("."[0-9]+)?|"."[0-9]+)(e(\+|-)[0-9]+)?)kHz\b return 'FREQ'; (([0-9]+("."[0-9]+)?|"."[0-9]+)(e(\+|-)[0-9]+)?)dpi\b return 'RES'; (([0-9]+("."[0-9]+)?|"."[0-9]+)(e(\+|-)[0-9]+)?)dpcm\b return 'RES'; (([0-9]+("."[0-9]+)?|"."[0-9]+)(e(\+|-)[0-9]+)?)dppx\b return 'RES'; (([0-9]+("."[0-9]+)?|"."[0-9]+)(e(\+|-)[0-9]+)?)\% return 'PERCENTAGE'; (([0-9]+("."[0-9]+)?|"."[0-9]+)(e(\+|-)[0-9]+)?)\b return 'NUMBER'; (([0-9]+("."[0-9]+)?|"."[0-9]+)(e(\+|-)[0-9]+)?)-?([a-zA-Z_]|[\240-\377]|(\\[0-9a-fA-F]{1,6}(\r\n|[ \t\r\n\f])?|\\[^\r\n\f0-9a-fA-F]))([a-zA-Z0-9_-]|[\240-\377]|(\\[0-9a-fA-F]{1,6}(\r\n|[ \t\r\n\f])?|\\[^\r\n\f0-9a-fA-F]))*\b return 'UNKNOWN_DIMENSION'; "(" return 'LPAREN'; ")" return 'RPAREN'; <> return 'EOF'; /lex %left ADD SUB %left MUL DIV %left UPREC %start expression %% expression : math_expression EOF { return $1; } ; math_expression : CALC LPAREN math_expression RPAREN { $$ = $3; } | math_expression ADD math_expression { $$ = { type: 'MathExpression', operator: $2, left: $1, right: $3 }; } | math_expression SUB math_expression { $$ = { type: 'MathExpression', operator: $2, left: $1, right: $3 }; } | math_expression MUL math_expression { $$ = { type: 'MathExpression', operator: $2, left: $1, right: $3 }; } | math_expression DIV math_expression { $$ = { type: 'MathExpression', operator: $2, left: $1, right: $3 }; } | LPAREN math_expression RPAREN { $$ = { type: 'ParenthesizedExpression', content: $2 }; } | function { $$ = $1; } | dimension { $$ = $1; } | number { $$ = $1; } ; function : FUNCTION { $$ = { type: 'Function', value: $1 }; } ; dimension : LENGTH { $$ = { type: 'LengthValue', value: parseFloat($1), unit: /[a-z]+$/i.exec($1)[0] }; } | ANGLE { $$ = { type: 'AngleValue', value: parseFloat($1), unit: /[a-z]+$/i.exec($1)[0] }; } | TIME { $$ = { type: 'TimeValue', value: parseFloat($1), unit: /[a-z]+$/i.exec($1)[0] }; } | FREQ { $$ = { type: 'FrequencyValue', value: parseFloat($1), unit: /[a-z]+$/i.exec($1)[0] }; } | RES { $$ = { type: 'ResolutionValue', value: parseFloat($1), unit: /[a-z]+$/i.exec($1)[0] }; } | UNKNOWN_DIMENSION { $$ = { type: 'UnknownDimension', value: parseFloat($1), unit: /[a-z]+$/i.exec($1)[0] }; } | EMS { $$ = { type: 'EmValue', value: parseFloat($1), unit: 'em' }; } | EXS { $$ = { type: 'ExValue', value: parseFloat($1), unit: 'ex' }; } | CHS { $$ = { type: 'ChValue', value: parseFloat($1), unit: 'ch' }; } | REMS { $$ = { type: 'RemValue', value: parseFloat($1), unit: 'rem' }; } | VHS { $$ = { type: 'VhValue', value: parseFloat($1), unit: 'vh' }; } | VWS { $$ = { type: 'VwValue', value: parseFloat($1), unit: 'vw' }; } | VMINS { $$ = { type: 'VminValue', value: parseFloat($1), unit: 'vmin' }; } | VMAXS { $$ = { type: 'VmaxValue', value: parseFloat($1), unit: 'vmax' }; } | PERCENTAGE { $$ = { type: 'PercentageValue', value: parseFloat($1), unit: '%' }; } | ADD dimension { var prev = $2; $$ = prev; } | SUB dimension { var prev = $2; prev.value *= -1; $$ = prev; } ; number : NUMBER { $$ = { type: 'Number', value: parseFloat($1) }; } | ADD NUMBER { $$ = { type: 'Number', value: parseFloat($2) }; } | SUB NUMBER { $$ = { type: 'Number', value: parseFloat($2) * -1 }; } ;