diff --git a/README.md b/README.md index ccca2e5..5e9dc3f 100644 --- a/README.md +++ b/README.md @@ -12,17 +12,23 @@ Integer ::= [0-9]+ Number ::= Integer Ignored String ::= '"' '"' Ignored | '"' StringCharacter '"' Ignored Variable ::= "$" Name Ignored // 变量 -Assignment ::= Variable Ignored '=' Ignored ( String | Number | Variable | BinaryExpression) Ignored +Assignment ::= Variable Ignored '=' Ignored ( String | Number | Variable | Expressions) Ignored Print ::= "print" "(" Ignored Variable Ignored ")" Ignored Statement ::= Print | Assignment SourceCode ::= Statement+ Comment ::= Ignored "#" SourceCharacter // 注释 -BinaryExpression::= (Variable | Number) Ignored Operator Ignored (Variable | Number) -Operator ::= "+" | "-" | "*" | "/" | ">" | "<" | "==" | ">=" | "<=" -BinaryExpressions ::= (BinaryExpression Operator)+ Ignored (Variable | Number) // eg: 1: (2 + 1 +) 3 2: ((2 + 1 +) (5 + 6 -)) 3 +// BinaryExpression::= (Variable | Number) Ignored Operator1 Ignored (Variable | Number) +Compare ::= ">" | "<" | "==" | ">=" | "<=" +Operator1 ::= "+" | "-" +Operator2 ::= "*" | "/" +Expressions ::= Term Expressions_tail +Expressions_tail ::= (Operator1 Term)? // 0个或一个 +Term ::= Factor Term_tail +Term_tail ::= (Operator2 Factor)? // 0个或一个 +Factor ::= Number | "(" Expressions ")" FunctionDeclaration ::= "func" Ignored Name Ignored "(" Variable ("," Variable)* ")" BlockStatement // eg: 1: func foo ($a) {} 2: func foo ($a[,$b][,$c]) {} ("," Variable)*这部分是一个或多个 BlockStatement ::= "{" Ignored (IfStatement | CallFunction | Print | Assignment | ReturnStatement ) Ignored "}" -ReturnStatement ::= "return" (BinaryExpression | Variable) +ReturnStatement ::= "return" (Expressions | Variable) CallFunction ::= Name "(" (Variable | Number) ("," (Variable | Number))* ")" Ignored IfStatement ::= "if" Ignored "(" Variable Ignored Operator Ignored Variable ")" Ignored BlockStatement Ignored "else" Ignored BlockStatement Ignored diff --git a/demo/hello-world-11.pineapple b/demo/hello-world-11.pineapple new file mode 100644 index 0000000..c6b9a4b --- /dev/null +++ b/demo/hello-world-11.pineapple @@ -0,0 +1,2 @@ +$a = 1 + 2 + 3 +print($a) diff --git a/dist/src/parser/Assignment.js b/dist/src/parser/Assignment.js index b60ee4c..8382eff 100644 --- a/dist/src/parser/Assignment.js +++ b/dist/src/parser/Assignment.js @@ -1,6 +1,6 @@ "use strict"; Object.defineProperty(exports, "__esModule", { value: true }); -exports.parseBinaryExpression = exports.parseAssignment = exports.Assignment = exports.Identifier = exports.Literal = void 0; +exports.parseBinaryExpression = exports.Factor = exports.Trem_tail = exports.Trem = exports.Expression_tail = exports.Expressions = exports.parseAssignment = exports.Assignment = exports.Identifier = exports.Literal = void 0; const lexer1_1 = require("../lexer1"); const parser_1 = require("../parser"); const Expression_1 = require("./Expression"); @@ -51,6 +51,7 @@ function parseAssignment(lexer) { const tokenType = lexer.LookAhead().tokenType; // 如果后面仍是$ if (tokenType === lexer1_1.TOKEN_VAR_PREFIX) { + // 需要Expressions处理 const Variable = parser_1.parseVariable(lexer); // 标识符,这里面会把邻近的空格回车删掉 const identifier = new Identifier(Variable.Name); VariableDeclarator.init = identifier; @@ -75,8 +76,20 @@ function parseAssignment(lexer) { assignment.type = "VariableDeclaration"; } else if (tokenType === lexer1_1.NUMBER) { - const literial = new Literal(parser_1.parseNumber(lexer)); // 这里面会把邻近的空格回车删掉 - VariableDeclarator.init = literial; + // 需要Expressions处理 + let ex = new BinaryExpression(''); + const lineNumber = lexer.GetLineNum(); + while (lexer.GetLineNum() === lineNumber) { + const expr = Expressions(lexer, ex); + ex = expr; + // ex.left = expr; + // let ahead = lexer.LookAhead() + // ex.operator = ahead.token + console.log(expr); + } + console.log(ex); + // const literial = new Literal(parseNumber(lexer)) // 这里面会把邻近的空格回车删掉 + VariableDeclarator.init = ex; assignment.type = "VariableDeclaration"; } else { @@ -99,6 +112,107 @@ function parseAssignment(lexer) { } } exports.parseAssignment = parseAssignment; +// $a = $b + $c + $d +// $a = 1 + 2 + 5 +// $a = 1 + $b + $c +function Expressions(lexer, expr) { + let value = Trem(lexer, expr); + return Expression_tail(lexer, value ? value : expr); +} +exports.Expressions = Expressions; +function Expression_tail(lexer, value) { + let ahead = lexer.LookAhead(); + if (ahead.token === "+") { + if (value instanceof BinaryExpression) { + value.operator = "+"; + } + lexer.NextTokenIs(lexer1_1.Operator); + const expression = new BinaryExpression("+"); + expression.left = value; + expression.right = Trem(lexer); + return expression; + } + else if (ahead.token === "-") { + if (value instanceof BinaryExpression) { + value.operator = "-"; + } + lexer.NextTokenIs(lexer1_1.Operator); + const expression = new BinaryExpression("-"); + expression.left = value; + expression.right = Trem(lexer); + return expression; + } + else { + lexer.isIgnored(); + return value; + } +} +exports.Expression_tail = Expression_tail; +function Trem(lexer, expr) { + let value = Factor(lexer, expr); + return Trem_tail(lexer, value); +} +exports.Trem = Trem; +function Trem_tail(lexer, value) { + let ahead = lexer.LookAhead(); + if (ahead.token === "*") { + lexer.NextTokenIs(lexer1_1.Operator); + const expression = new BinaryExpression("*"); + expression.left = value; + expression.right = Factor(lexer); + return expression; + } + else if (ahead.token === "/") { + lexer.NextTokenIs(lexer1_1.Operator); + const expression = new BinaryExpression("/"); + expression.left = value; + expression.right = Factor(lexer); + return expression; + } + else { + // 如果不进行NextTokenIs,取消缓存,使用lexer.LookAheadAndSkip(TOKEN_IGNORED)不生效 + // 只能使用这个lexer.isIgnored() api了 + lexer.isIgnored(); + return value; + } +} +exports.Trem_tail = Trem_tail; +function Factor(lexer, expr) { + let ahead = lexer.LookAhead(); + if (lexer.isNumber(ahead.token)) { + lexer.NextTokenIs(lexer1_1.NUMBER); + lexer.LookAheadAndSkip(lexer1_1.TOKEN_IGNORED); + return new Literal(+ahead.token); + } + else if (ahead.token === "(") { + // (1 + 2) + lexer.NextTokenIs(lexer1_1.TOKEN_LEFT_PAREN); + lexer.LookAheadAndSkip(lexer1_1.TOKEN_IGNORED); + // type: "BinaryExpression", + // left: { + // // type: "Identifier", + // // name: "c" + // }, + // operator: lexer.nextToken, + // right: { + // // type: "Identifier", + // // name: "b" + // } + const exp = Expressions(lexer, expr); + lexer.LookAheadAndSkip(lexer1_1.TOKEN_IGNORED); + lexer.NextTokenIs(lexer1_1.TOKEN_RIGHT_PAREN); + return exp; + } +} +exports.Factor = Factor; +class BinaryExpression { + constructor(operator, type = "BinaryExpression", left = {}, right = {}) { + this.type = type; + this.left = left; + this.operator = operator; + this.right = right; + } +} function parseBinaryExpression(lexer, idAndinit, assignment, leftType) { const BinaryExpression = { type: "BinaryExpression", diff --git a/dist/test/test.js b/dist/test/test.js index 0eaff3d..b1b2a2b 100644 --- a/dist/test/test.js +++ b/dist/test/test.js @@ -2,7 +2,7 @@ const fs = require('fs'); const path = require('path'); const Execute = require('../dist/src/backend.js').Execute; -code = fs.readFileSync(path.resolve(__dirname, '../demo/hello-world-10.pineapple'), { encoding: 'utf-8' }); +code = fs.readFileSync(path.resolve(__dirname, '../demo/hello-world-11.pineapple'), { encoding: 'utf-8' }); console.log(code, 'code'); if (code.length > 0) { Execute(code); diff --git a/src/lexer1.ts b/src/lexer1.ts index 27deafc..94cf668 100644 --- a/src/lexer1.ts +++ b/src/lexer1.ts @@ -8,17 +8,23 @@ Integer ::= [0-9]+ Number ::= Integer Ignored String ::= '"' '"' Ignored | '"' StringCharacter '"' Ignored Variable ::= "$" Name Ignored // 变量 -Assignment ::= Variable Ignored '=' Ignored ( String | Number | Variable | BinaryExpression) Ignored +Assignment ::= Variable Ignored '=' Ignored ( String | Number | Variable | Expressions) Ignored Print ::= "print" "(" Ignored Variable Ignored ")" Ignored Statement ::= Print | Assignment SourceCode ::= Statement+ Comment ::= Ignored "#" SourceCharacter // 注释 -BinaryExpression::= (Variable | Number) Ignored Operator Ignored (Variable | Number) -Operator ::= "+" | "-" | "*" | "/" | ">" | "<" | "==" | ">=" | "<=" -BinaryExpressions ::= (BinaryExpression Operator)+ Ignored (Variable | Number) // eg: 1: (2 + 1 +) 3 2: ((2 + 1 +) (5 + 6 -)) 3 +// BinaryExpression::= (Variable | Number) Ignored Operator1 Ignored (Variable | Number) +Compare ::= ">" | "<" | "==" | ">=" | "<=" +Operator1 ::= "+" | "-" +Operator2 ::= "*" | "/" +Expressions ::= Term Expressions_tail +Expressions_tail ::= (Operator1 Term)? // 0个或一个 +Term ::= Factor Term_tail +Term_tail ::= (Operator2 Factor)? // 0个或一个 +Factor ::= Number | "(" Expressions ")" FunctionDeclaration ::= "func" Ignored Name Ignored "(" Variable ("," Variable)* ")" BlockStatement // eg: 1: func foo ($a) {} 2: func foo ($a[,$b][,$c]) {} ("," Variable)*这部分是一个或多个 BlockStatement ::= "{" Ignored (IfStatement | CallFunction | Print | Assignment | ReturnStatement ) Ignored "}" -ReturnStatement ::= "return" (BinaryExpression | Variable) +ReturnStatement ::= "return" (Expressions | Variable) CallFunction ::= Name "(" (Variable | Number) ("," (Variable | Number))* ")" Ignored IfStatement ::= "if" Ignored "(" Variable Ignored Operator Ignored Variable ")" Ignored BlockStatement Ignored "else" Ignored BlockStatement Ignored diff --git a/src/parser/Assignment.ts b/src/parser/Assignment.ts index 4af348a..36f797a 100644 --- a/src/parser/Assignment.ts +++ b/src/parser/Assignment.ts @@ -1,5 +1,5 @@ import { Variable } from "../definition"; -import { Lexer, NUMBER, Operator, tokenNameMap, Tokens, TOKEN_EQUAL, TOKEN_IGNORED, TOKEN_NAME, TOKEN_VAR_PREFIX } from "../lexer1"; +import { INTERGER, Lexer, NUMBER, Operator, tokenNameMap, Tokens, TOKEN_EQUAL, TOKEN_IGNORED, TOKEN_LEFT_PAREN, TOKEN_NAME, TOKEN_RIGHT_PAREN, TOKEN_VAR_PREFIX } from "../lexer1"; import { parseNumber, parseString, parseVariable } from "../parser"; import { parseExpression } from "./Expression"; @@ -75,6 +75,7 @@ export function parseAssignment(lexer: Lexer) { // 如果后面仍是$ if (tokenType === TOKEN_VAR_PREFIX) { + // 需要Expressions处理 const Variable = parseVariable(lexer) // 标识符,这里面会把邻近的空格回车删掉 const identifier = new Identifier(Variable.Name); VariableDeclarator.init = identifier @@ -98,8 +99,20 @@ export function parseAssignment(lexer: Lexer) { VariableDeclarator.init = expression.expression assignment.type = "VariableDeclaration" } else if (tokenType === NUMBER) { - const literial = new Literal(parseNumber(lexer)) // 这里面会把邻近的空格回车删掉 - VariableDeclarator.init = literial + // 需要Expressions处理 + let ex = new BinaryExpression('') + const lineNumber = lexer.GetLineNum() + while (lexer.GetLineNum() === lineNumber) { + const expr = Expressions(lexer, ex) + ex = expr + // ex.left = expr; + // let ahead = lexer.LookAhead() + // ex.operator = ahead.token + console.log(expr) + } + console.log(ex) + // const literial = new Literal(parseNumber(lexer)) // 这里面会把邻近的空格回车删掉 + VariableDeclarator.init = ex assignment.type = "VariableDeclaration" } else { const literial = new Literal(parseString(lexer)) // 这里面会把邻近的空格回车删掉 @@ -123,6 +136,112 @@ export function parseAssignment(lexer: Lexer) { } } +// $a = $b + $c + $d +// $a = 1 + 2 + 5 +// $a = 1 + $b + $c + +export function Expressions(lexer: Lexer, expr: any) { + let value = Trem(lexer, expr) + return Expression_tail(lexer, value ? value : expr) +} + +export function Expression_tail(lexer: Lexer, value: any) { + let ahead = lexer.LookAhead() + if (ahead.token === "+") { + if (value instanceof BinaryExpression) { + value.operator = "+" + } + lexer.NextTokenIs(Operator) + const expression = new BinaryExpression("+") + expression.left = value; + expression.right = Trem(lexer) + return expression + } else if (ahead.token === "-") { + if (value instanceof BinaryExpression) { + value.operator = "-" + } + lexer.NextTokenIs(Operator) + const expression = new BinaryExpression("-") + expression.left = value; + expression.right = Trem(lexer) + return expression + } else { + lexer.isIgnored() + return value + } +} + +export function Trem(lexer: Lexer, expr?: any) { + let value = Factor(lexer, expr) + return Trem_tail(lexer, value) +} + +export function Trem_tail(lexer: Lexer, value: any) { + let ahead = lexer.LookAhead() + if (ahead.token === "*") { + lexer.NextTokenIs(Operator) + const expression = new BinaryExpression("*") + expression.left = value; + expression.right = Factor(lexer) + return expression + } else if (ahead.token === "/") { + lexer.NextTokenIs(Operator) + const expression = new BinaryExpression("/") + expression.left = value; + expression.right = Factor(lexer) + return expression + } else { + // 如果不进行NextTokenIs,取消缓存,使用lexer.LookAheadAndSkip(TOKEN_IGNORED)不生效 + // 只能使用这个lexer.isIgnored() api了 + lexer.isIgnored() + return value + } +} + +export function Factor(lexer: Lexer, expr?: any) { + let ahead = lexer.LookAhead() + if (lexer.isNumber(ahead.token)) { + lexer.NextTokenIs(NUMBER) + lexer.LookAheadAndSkip(TOKEN_IGNORED) + return new Literal(+ahead.token) + } else if (ahead.token === "(") { + // (1 + 2) + lexer.NextTokenIs(TOKEN_LEFT_PAREN) + lexer.LookAheadAndSkip(TOKEN_IGNORED) + // type: "BinaryExpression", + // left: { + // // type: "Identifier", + // // name: "c" + // }, + // operator: lexer.nextToken, + // right: { + // // type: "Identifier", + // // name: "b" + // } + const exp: any = Expressions(lexer, expr) + lexer.LookAheadAndSkip(TOKEN_IGNORED) + lexer.NextTokenIs(TOKEN_RIGHT_PAREN) + + return exp + } +} + +interface BinaryExpression { + type?: string, + left: any, + operator?: any, + right?: any +} + +class BinaryExpression { + constructor(operator: string, type = "BinaryExpression", left = {}, right = {}) { + this.type = type; + this.left = left; + this.operator = operator; + this.right = right; + } +} + export function parseBinaryExpression(lexer: Lexer, idAndinit: { init: Literal | Identifier, id: Identifier }, assignment: Assignment, leftType: string) { const BinaryExpression: { type: string, diff --git a/test/test.js b/test/test.js index 6fae3be..e87c647 100644 --- a/test/test.js +++ b/test/test.js @@ -2,7 +2,7 @@ const fs = require('fs') const path = require('path') const Execute = require('../dist/src/backend.js').Execute -code = fs.readFileSync(path.resolve(__dirname, '../demo/hello-world-10.pineapple'), {encoding: 'utf-8'}) +code = fs.readFileSync(path.resolve(__dirname, '../demo/hello-world-11.pineapple'), {encoding: 'utf-8'}) console.log(code, 'code') if (code.length > 0) { Execute(code)